1.android 横竖屏切换上层从HdmiSettings.java 开始。我们从这里开始分析。
路径:packages\apps\Settings\src\com\android\settings\HdmiSettings.java
mHdmiResolution.setOnPreferenceClickListener(this);
public boolean onPreferenceChange(Preference preference, Object obj) {
Log.i(TAG, "onPreferenceChange:" + obj);
String key = preference.getKey();
Log.d(TAG, key);
if(preference == mHdmiResolution) {
if (KEY_HDMI_RESOLUTION.equals(key)) {
if (obj.equals(mOldResolution))
return true;
int index = mHdmiResolution.findIndexOfValue((String) obj);
Log.i(TAG, "onPreferenceChange: index= " + index);
mDisplayInfo = getDisplayInfo();
if (mDisplayInfo != null) {
DrmDisplaySetting.setDisplayModeTemp(mDisplayInfo, index);
showConfirmSetModeDialog();
}
}
} else if (preference == mHdmiRotation) {
if (KEY_HDMI_ROTATION.equals(key)) {
try {
int value = Integer.parseInt((String) obj);
android.os.SystemProperties.set("persist.sys.orientation", (String) obj);
Log.d(TAG,"freezeRotation~~~value:"+(String) obj);
if(value == 0)
wm.freezeRotation(Surface.ROTATION_0);
else if(value == 90)
wm.freezeRotation(Surface.ROTATION_90);
else if(value == 180)
wm.freezeRotation(Surface.ROTATION_180);
else if(value == 270)
wm.freezeRotation(Surface.ROTATION_270);
else
return true;
//android.os.SystemProperties.set("sys.boot_completed", "1");
} catch (Exception e) {
Log.e(TAG, "freezeRotation error");
}
}
} else if (preference == mHdmiDualScreen) {
android.provider.Settings.System.putInt(getActivity().getContentResolver(),DOUBLE_SCREEN_CONFIG,(Boolean)obj?1:0);
SystemProperties.set("persist.orientation.vhinit", "0");
SystemProperties.set("persist.orientation.vhshow", "false");
mHdmiDualScreenVH.setEnabled((Boolean)obj);
mHdmiDualScreenVH.setChecked(false);
mHdmiDualScreenList.setEnabled(false);
this.finish();
} else if (preference == mHdmiDualScreenVH) {
if((Boolean)obj) {
SystemProperties.set("persist.orientation.vhshow", "true");
mHdmiDualScreenList.setEnabled(true);
} else {
SystemProperties.set("persist.orientation.vhshow", "false");
mHdmiDualScreenList.setEnabled(false);
SystemProperties.set("persist.orientation.vhinit", "0");
}
SystemProperties.set("persist.orientation.vhinit", "0");
} else if (preference == mHdmiDualScreenList) {
if("0".equals(obj.toString())) {
SystemProperties.set("persist.orientation.vhinit", "0");
} else if ("1".equals(obj.toString())) {
SystemProperties.set("persist.orientation.vhinit", "1");
}
}
return true;
}
2. 主要调用了wm.freezeRotation(Surface.ROTATION_0); 这个函数,通过WMS实现。
wm = IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
3.跨进程访问服务AIDL
路径:frameworks\base\core\java\android\view\IWindowManager.aidl
interface IWindowManager
{
/**
* Lock the device orientation to the specified rotation, or to the
* current rotation if -1. Sensor input will be ignored until
* thawRotation() is called.
* @hide
*/
void freezeRotation(int rotation);
}
4.AIDL(Android Interface Definition Language)具体实现的方法类
路径:frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
enable “Auto-rotate screen” 则调用public void freezeRotation(int rotation),disable “Auto-rotate screen” 则调用public void thawRotation() 。
public void freezeRotation(int rotation) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"freezeRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
if (rotation < -1 || rotation > Surface.ROTATION_270) {
throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
+ "rotation constant.");
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "freezeRotation: mRotation=" + mRotation);
long origId = Binder.clearCallingIdentity();
try {
mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
rotation == -1 ? mRotation : rotation);
} finally {
Binder.restoreCallingIdentity(origId);
}
updateRotationUnchecked(false, false);
}
/**
* Thaw rotation changes. (Disable "rotation lock".)
* Persists across reboots.
*/
@Override
public void thawRotation() {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"thawRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "thawRotation: mRotation=" + mRotation);
long origId = Binder.clearCallingIdentity();
try {
mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
777); // rot not used
} finally {
Binder.restoreCallingIdentity(origId);
}
//关键函数
updateRotationUnchecked(false, false);
}
public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked("
+ "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
long origId = Binder.clearCallingIdentity();
boolean changed;
synchronized(mWindowMap) {
//更新方向
changed = updateRotationUncheckedLocked(false);
if (!changed || forceRelayout) {
getDefaultDisplayContentLocked().layoutNeeded = true;
//屏幕绘制
mWindowPlacerLocked.performSurfacePlacement();
}
}
if (changed || alwaysSendConfiguration) {
//发送新配置
sendNewConfiguration();
}
Binder.restoreCallingIdentity(origId);
}
//更新rotation 横转直最核心的code
public boolean updateRotationUncheckedLocked(boolean inTransaction) {
/*
* 调用函数pauseRotationLocked() mDeferredRotationPauseCount + 1
* 调用函数resumeRotationLocked() mDeferredRotationPauseCount - 1
* 调用 updateRotationUncheckedLocked() 将 change rotation
*/
if (mDeferredRotationPauseCount > 0) {
// Rotation updates have been paused temporarily. Defer the update until
// updates have been resumed.
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
return false;
}
//如果上一次动画未完成,则不进行旋转操作
ScreenRotationAnimation screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
// Rotation updates cannot be performed while the previous rotation change
// animation is still in progress. Skip this update. We will try updating
// again after the animation is finished and the display is unfrozen.
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
return false;
}
//即使屏幕旋转动画已经完成,仍然有一段时间我们还没有解冻显示。需要中止旋转。
if (mDisplayFrozen) {
// Even if the screen rotation animation has finished (e.g. isAnimating
// returns false), there is still some time where we haven't yet unfrozen
// the display. We also need to abort rotation here.
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, still finishing previous rotation");
return false;
}
//如果不启用显示,也无需进行旋转操作
if (!mDisplayEnabled) {
// No point choosing a rotation if the display is not enabled.
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
return false;
}
final DisplayContent displayContent = getDefaultDisplayContentLocked();
final WindowList windows = displayContent.getWindowList();
final int oldRotation = mRotation;
//根据传感器综合计算出屏幕方向
int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
//处理判断是否可以无缝旋转
if (rotateSeamlessly) {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
// We can't rotate (seamlessly or not) while waiting for the last seamless rotation
// to complete (that is, waiting for windows to redraw). It's tempting to check
// w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
if (w.mSeamlesslyRotated) {
return false;
}
// In what can only be called an unfortunate workaround we require
// seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
// flag. Due to limitations in the client API, there is no way for
// the client to set this flag in a race free fashion. If we seamlessly rotate
// a window which does not have this flag, but then gains it, we will get
// an incorrect visual result (rotated viewfinder). This means if we want to
// support seamlessly rotating windows which could gain this flag, we can't
// rotate windows without it. This limits seamless rotation in N to camera framework
// users, windows without children, and native code. This is unfortunate but
// having the camera work is our primary goal.
if (w.isChildWindow() & w.isVisibleNow() &&
!w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
rotateSeamlessly = false;
}
}
}
// TODO: Implement forced rotation changes.
// Set mAltOrientation to indicate that the application is receiving
// an orientation that has different metrics than it expected.
// eg. Portrait instead of Landscape.
boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
mLastOrientation, rotation);
if (DEBUG_ORIENTATION) {
Slog.v(TAG_WM, "Selected orientation "
+ mLastOrientation + ", got rotation " + rotation
+ " which has " + (altOrientation ? "incompatible" : "compatible")
+ " metrics");
}
if (mRotateOnBoot) {
mRotation = Surface.ROTATION_0;
rotation = Surface.ROTATION_90;
}
if (mRotation == rotation && mAltOrientation == altOrientation) {
// No change.
return false;
}
if (DEBUG_ORIENTATION) {
Slog.v(TAG_WM,
"Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
+ " from " + mRotation + (mAltOrientation ? " (alt)" : "")
+ ", lastOrientation=" + mLastOrientation);
}
//获取新的rotation ,传给PhoneWindowManager
mRotation = rotation;
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation);
//发送WINDOW_FREEZE_TIMEOUT消息
mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
if (mFirstRotate) {
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, 5000);
mFirstRotate = false;
} else {
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
}
mWaitingForConfig = true;
displayContent.layoutNeeded = true;
final int[] anim = new int[2];
if (displayContent.isDimming()) {
anim[0] = anim[1] = 0;
} else {
//在PhoneWindowManager中判断进入还是退出转屏动画操作
mPolicy.selectRotationAnimationLw(anim);
}
//如果是Seamlessly则无旋转动画,因Seamlessly目前不支持旋转动画
if (!rotateSeamlessly) {
startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
// startFreezingDisplayLocked can reset the ScreenRotationAnimation.
screenRotationAnimation =
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
} else {
// The screen rotation animation uses a screenshot to freeze the screen
// while windows resize underneath.
// When we are rotating seamlessly, we allow the elements to transition
// to their rotated state independently and without a freeze required.
screenRotationAnimation = null;
// We have to reset this in case a window was removed before it
// finished seamless rotation.
mSeamlessRotationCount = 0;
}
boolean isDelay = true;//(("true".equals(SystemProperties.get("ro.config.low_ram", "false")))||("true".equals(SystemProperties.get("ro.mem_optimise.enable", "false")))) && (!"true".equals(SystemProperties.get("sys.cts_gts.status", "false")));
if (mRotateOnBoot) {
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED !!!!!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
}
}
// We need to update our screen size information to match the new rotation. If the rotation
// has actually changed then this method will return true and, according to the comment at
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
// By updating the Display info here it will be available to
// computeScreenConfigurationLocked later.
//根据rotation 去更新DisplayInfo
updateDisplayAndOrientationLocked(mCurConfiguration.uiMode);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (!inTransaction) {
if (SHOW_TRANSACTIONS) {
Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
}
SurfaceControl.openTransaction();
}
try {
// NOTE: We disable the rotation in the emulator because
// it doesn't support hardware OpenGL emulation yet.
//进行屏幕过度旋转动画操作
if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
&& screenRotationAnimation.hasScreenshot()) {
if (screenRotationAnimation.setRotationInTransaction(
rotation, mFxSession,
MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(),
displayInfo.logicalWidth, displayInfo.logicalHeight)) {
scheduleAnimationLocked();
}
}
if (rotateSeamlessly) {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation);
}
}
mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
} finally {
if (!inTransaction) {
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
}
}
}
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
// Discard surface after orientation change, these can't be reused.
if (w.mAppToken != null) {
w.mAppToken.destroySavedSurfaces();
}
if (w.mHasSurface && !rotateSeamlessly) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
w.mOrientationChanging = true;
mWindowPlacerLocked.mOrientationChangeComplete = false;
w.mLastFreezeDuration = 0;
}
}
if (rotateSeamlessly) {
mH.removeMessages(H.SEAMLESS_ROTATION_TIMEOUT);
mH.sendEmptyMessageDelayed(H.SEAMLESS_ROTATION_TIMEOUT, SEAMLESS_ROTATION_TIMEOUT_DURATION);
}
for (int i=mRotationWatchers.size()-1; i>=0; i--) {
try {
mRotationWatchers.get(i).watcher.onRotationChanged(rotation);
} catch (RemoteException e) {
}
}
// TODO (multidisplay): Magnification is supported only for the default display.
// Announce rotation only if we will not animate as we already have the
// windows in final state. Otherwise, we make this call at the rotation end.
if (screenRotationAnimation == null && mAccessibilityController != null
&& displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(),
rotation);
}
return true;
}
1)无论 public void freezeRotation(int rotation)还是public void thawRotation() 最终都会调用WindowManagerPolicy.cpp 中提供的接口。
路径:frameworks\base\core\java\android\view\WindowManagerPolicy.java
public interface WindowManagerPolicy {
public void selectRotationAnimationLw(int anim[]);
public int getUserRotationMode();
public void setUserRotationMode(@UserRotationMode int mode, @Surface.Rotation int rotation);
...
}
WindowManagerPolicy 接口类的具体实现方法在PhoneWindowManager.java中。
路径:frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
public int getUserRotationMode() {
return Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ?
WindowManagerPolicy.USER_ROTATION_FREE :
WindowManagerPolicy.USER_ROTATION_LOCKED;
}
2)动画旋转过程
通过截图,制作旋转动画效果,重新绘制横屏转竖屏或者竖屏转横屏的界面,在ScreenRotationAnimation.java 中完成。
路径:frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
screenRotationAnimation.setRotationInTransaction(
rotation, mFxSession,
MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(),
displayInfo.logicalWidth, displayInfo.logicalHeight)
在ScreenRotationAnimation.java调用
路径:frameworks\base\services\core\java\com\android\server\wm\ScreenRotationAnimation.java
//动画旋转的整个过程
// Must be called while in a transaction.
private void setRotationInTransaction(int rotation) {
mCurRotation = rotation;
if (DEBUG_STATE) Slog.v(TAG, "navy **** ROTATION: " + rotation);
// Compute the transformation matrix that must be applied
// to the snapshot to make it stay in the same original position
// with the current screen rotation.
int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
setSnapshotTransformInTransaction(mSnapshotInitialMatrix, 1.0f);
}
// Must be called while in a transaction.
public boolean setRotationInTransaction(int rotation, SurfaceSession session,
long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
setRotationInTransaction(rotation);
if (TWO_PHASE_ANIMATION) {
return startAnimation(session, maxAnimationDuration, animationScale,
finalWidth, finalHeight, false, 0, 0);
}
// Don't start animation yet.
return false;
}
//主要用来计算动画旋转的变换矩阵
public static void createRotationMatrix(int rotation, int width, int height,
Matrix outMatrix) {
switch (rotation) {
case Surface.ROTATION_0:
outMatrix.reset();
break;
case Surface.ROTATION_90:
outMatrix.setRotate(90, 0, 0);
outMatrix.postTranslate(height, 0);
break;
case Surface.ROTATION_180:
outMatrix.setRotate(180, 0, 0);
outMatrix.postTranslate(width, height);
break;
case Surface.ROTATION_270:
outMatrix.setRotate(270, 0, 0);
outMatrix.postTranslate(0, width);
break;
}
}
在DisplayContent.java比较rotation
路径:frameworks\base\services\core\java\com\android\server\wm\DisplayContent.java
static int deltaRotation(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
return delta;
}
3)剖析Matrix 类的实现
路径:frameworks\base\graphics\java\android\graphics\Matrix.java
private static native void native_setRotate(long native_object,
float degrees, float px, float py);
private static native void native_setRotate(long native_object,
float degrees);
/**
* Set the matrix to rotate by the specified number of degrees, with a pivot
* point at (px, py). The pivot point is the coordinate that should remain
* unchanged by the specified transformation.
*/
public void setRotate(float degrees, float px, float py) {
native_setRotate(native_instance, degrees, px, py);
}
/**
* Set the matrix to rotate about (0,0) by the specified number of degrees.
*/
public void setRotate(float degrees) {
native_setRotate(native_instance, degrees);
}
具体jni 实现方法:
路径:frameworks\base\core\jni\android\graphics\Matrix.cpp
static void setRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
obj->setRotate(degrees, px, py);
}
static void setRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
obj->setRotate(degrees);
}
static const JNINativeMethod methods[] = {
{"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
{"native_create","(J)J", (void*) SkMatrixGlue::create},
{"native_isIdentity","!(J)Z", (void*) SkMatrixGlue::isIdentity},
{"native_isAffine","!(J)Z", (void*) SkMatrixGlue::isAffine},
{"native_rectStaysRect","!(J)Z", (void*) SkMatrixGlue::rectStaysRect},
{"native_reset","!(J)V", (void*) SkMatrixGlue::reset},
{"native_set","!(JJ)V", (void*) SkMatrixGlue::set},
{"native_setTranslate","!(JFF)V", (void*) SkMatrixGlue::setTranslate},
{"native_setScale","!(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
{"native_setScale","!(JFF)V", (void*) SkMatrixGlue::setScale__FF},
{"native_setRotate","!(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
{"native_setRotate","!(JF)V", (void*) SkMatrixGlue::setRotate__F},
{"native_setSinCos","!(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
{"native_setSinCos","!(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
{"native_setSkew","!(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
{"native_setSkew","!(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
{"native_setConcat","!(JJJ)V", (void*) SkMatrixGlue::setConcat},
{"native_preTranslate","!(JFF)V", (void*) SkMatrixGlue::preTranslate},
{"native_preScale","!(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
{"native_preScale","!(JFF)V", (void*) SkMatrixGlue::preScale__FF},
{"native_preRotate","!(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
{"native_preRotate","!(JF)V", (void*) SkMatrixGlue::preRotate__F},
{"native_preSkew","!(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
{"native_preSkew","!(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
{"native_preConcat","!(JJ)V", (void*) SkMatrixGlue::preConcat},
{"native_postTranslate","!(JFF)V", (void*) SkMatrixGlue::postTranslate},
{"native_postScale","!(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
{"native_postScale","!(JFF)V", (void*) SkMatrixGlue::postScale__FF},
{"native_postRotate","!(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
{"native_postRotate","!(JF)V", (void*) SkMatrixGlue::postRotate__F},
{"native_postSkew","!(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
{"native_postSkew","!(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
{"native_postConcat","!(JJ)V", (void*) SkMatrixGlue::postConcat},
{"native_setRectToRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect},
{"native_setPolyToPoly","!(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
{"native_invert","!(JJ)Z", (void*) SkMatrixGlue::invert},
{"native_mapPoints","!(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
{"native_mapRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF},
{"native_mapRadius","!(JF)F", (void*) SkMatrixGlue::mapRadius},
{"native_getValues","!(J[F)V", (void*) SkMatrixGlue::getValues},
{"native_setValues","!(J[F)V", (void*) SkMatrixGlue::setValues},
{"native_equals", "!(JJ)Z", (void*) SkMatrixGlue::equals}
};
static jfieldID sNativeInstanceField;
int register_android_graphics_Matrix(JNIEnv* env) {
int result = RegisterMethodsOrDie(env, "android/graphics/Matrix", methods, NELEM(methods));
jclass clazz = FindClassOrDie(env, "android/graphics/Matrix");
sNativeInstanceField = GetFieldIDOrDie(env, clazz, "native_instance", "J");
return result;
}
SkMatrix* android_graphics_Matrix_getSkMatrix(JNIEnv* env, jobject matrixObj) {
return reinterpret_cast<SkMatrix*>(env->GetLongField(matrixObj, sNativeInstanceField));
}
}
函数 static void setRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py);和 函数static void setRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees);中调用SkMatrix.cpp 中的函数。
路径:external\skia\include\core\SkMatrix.h
/** Set the matrix to rotate by the specified number of degrees, with a
pivot point at (px, py). The pivot point is the coordinate that should
remain unchanged by the specified transformation.
*/
void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
/** Set the matrix to rotate about (0,0) by the specified number of degrees.
*/
void setRotate(SkScalar degrees);
最终的3x3 matrix 来源:
路径:external\skia\src\core\SkMatrix.cpp
void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
fMat[kMScaleX] = cosV;
fMat[kMSkewX] = -sinV;
fMat[kMTransX] = 0;
fMat[kMSkewY] = sinV;
fMat[kMScaleY] = cosV;
fMat[kMTransY] = 0;
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = 1;
this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
SkScalar sinV, cosV;
sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
this->setSinCos(sinV, cosV, px, py);
}