rk3288 android7.1 横竖屏切换(动画过度)

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);
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值