WMS->stopFreezingScreen()冻屏总结

对于冻屏理解不深可能会认为冻屏会出现黑屏,不是这样的,恰恰相反,冻屏的目的就是防止执行默写操作的过程出现黑屏。冻屏的过程只是不接收输入和不执行动画,并且会截取屏幕进行显示。下面我们就来分下冻屏的过程。

WMS暴露了一个可以通过binder调用执行的冻屏操作,是startFreezingScreen函数

     @Override
    public void startFreezingScreen(int exitAnim, int enterAnim) {
    // 1 权限检查
        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
                "startFreezingScreen()")) {
            throw new SecurityException("Requires FREEZE_SCREEN permission");
        }

        synchronized(mWindowMap) { //2 执行冻结屏幕
            if (!mClientFreezingScreen) {
                mClientFreezingScreen = true;
                final long origId = Binder.clearCallingIdentity();
                try { 
                    startFreezingDisplayLocked(false, exitAnim, enterAnim);
                    mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
                    mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
    }

这个函数很简单 mClientFreezingScreen变量代表通过客户端进行冻结屏幕,另外作为系统服务,客户端是不可靠的,所以添加了一个CLIENT_FREEZE_TIMEOUT超时的消息,用于结束冻结屏幕。这是系统设置中最重要的一个保障,对于不可控的客户端操作全都采用超时处理机制。

startFreezingDisplayLocked函数是内部实现,系统除了由于客户端请求的冻结,还有其他情况会冻结,都是通过这个函数实现,我们在分析结束冻结的时候会看到那些情况出发冻结

private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
        if (mDisplayFrozen) {
            return;
        }

        if (!mDisplayReady || !mPolicy.isScreenOn()) { //1 display没准备好或者熄屏 不需要冻结屏幕
            // No need to freeze the screen before the system is ready or if
            // the screen is off.
            return;
        }

        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
                "startFreezingDisplayLocked: inTransaction=" + inTransaction
                + " exitAnim=" + exitAnim + " enterAnim=" + enterAnim
                + " called by " + Debug.getCallers(8));
        // 2 获取一个WEAK LOCK防止睡眠
        mScreenFrozenLock.acquire();

        // 3 核心变量设置为真
        mDisplayFrozen = true;
        mDisplayFreezeTime = SystemClock.elapsedRealtime();
        mLastFinishedFreezeSource = null;

     // 4 冻结input输入
        mInputMonitor.freezeInputDispatchingLw();

        // Clear the last input window -- that is just used for
        // clean transitions between IMEs, and if we are freezing
        // the screen then the whole world is changing behind the scenes.
        mPolicy.setLastInputMethodWindowLw(null, null);

        //5 强制结束app动画
        if (mAppTransition.isTransitionSet()) {
            mAppTransition.freeze();
        }

        if (PROFILE_ORIENTATION) {
            File file = new File("/data/system/frozen");
            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
        }
   
     //5 设置用户传进来的动画,CUSTOM_SCREEN_ROTATION一般系统都为真,为假的情况我们后面分析
        if (CUSTOM_SCREEN_ROTATION) {
            mExitAnimId = exitAnim;
            mEnterAnimId = enterAnim;
            final DisplayContent displayContent = getDefaultDisplayContentLocked();
            final int displayId = displayContent.getDisplayId();
            //6 结束之前的转屏动画
            ScreenRotationAnimation screenRotationAnimation =
                    mAnimator.getScreenRotationAnimationLocked(displayId);
            if (screenRotationAnimation != null) {
                screenRotationAnimation.kill();
            }

            // Check whether the current screen contains any secure content.
            boolean isSecure = false;
            final WindowList windows = getDefaultWindowListLocked();
            final int N = windows.size();
            for (int i = 0; i < N; i++) {
                WindowState ws = windows.get(i);
                if (ws.isOnScreen() && (ws.mAttrs.flags & FLAG_SECURE) != 0) {
                    isSecure = true;
                    break;
                }
            }

            // TODO(multidisplay): rotation on main screen only.
            displayContent.updateDisplayInfo();
            // 7 创建并且设置转屏动画
            screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure);
            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
        }
    }

对于第七步骤中设置转屏动画的解释是,系统把转屏和冻屏放在一个动画处理,首先转屏会触发冻品,其次这里冻屏其实就是0对的转屏动画, mAnimator对象则是WMS中执行动画的大管家我们后面会分析的到。

对于ScreenRotationAnimation的构造如下

public ScreenRotationAnimation(Context context, DisplayContent displayContent,
            SurfaceSession session, boolean inTransaction, boolean forceDefaultOrientation,
            boolean isSecure) {
        mContext = context;
        mDisplayContent = displayContent;
        // 1获取屏幕逻辑大小(有时候模拟小屏幕的时候逻辑大小小于物理大小)
        displayContent.getLogicalDisplayRect(mOriginalDisplayRect);

        // Screenshot does NOT include rotation!
        final Display display = displayContent.getDisplay();
        int originalRotation = display.getRotation();
        final int originalWidth;
        final int originalHeight;
        DisplayInfo displayInfo = displayContent.getDisplayInfo();
        if (forceDefaultOrientation) {
            // Emulated orientation.
            mForceDefaultOrientation = true;
            originalWidth = displayContent.mBaseDisplayWidth;
            originalHeight = displayContent.mBaseDisplayHeight;
        } else {
            // Normal situation
            originalWidth = displayInfo.logicalWidth;
            originalHeight = displayInfo.logicalHeight;
        }
        if (originalRotation == Surface.ROTATION_90
                || originalRotation == Surface.ROTATION_270) {
            mWidth = originalHeight;
            mHeight = originalWidth;
        } else {
            mWidth = originalWidth;
            mHeight = originalHeight;
        }
    // 2 设置三个变量,分别表示转屏之前的角度,宽高
        mOriginalRotation = originalRotation;
        mOriginalWidth = originalWidth;
        mOriginalHeight = originalHeight;

     // 4 如果没有在surfaceflinger事务中执行冻结操作要开启事务
        if (!inTransaction) {
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                    ">>> OPEN TRANSACTION ScreenRotationAnimation");
            SurfaceControl.openTransaction();
        }

        try {
            try {
                int flags = SurfaceControl.HIDDEN;
                if (isSecure) {//因为后面会截取屏幕,这里有些surface是安全的则动画这个surface也应该是安全的
                //否则会泄露信息 
                    flags |= SurfaceControl.SECURE;
                }

                if (DEBUG_SURFACE_TRACE) {
                    mSurfaceControl = new SurfaceTrace(session, "ScreenshotSurface",
                            mWidth, mHeight,
                            PixelFormat.OPAQUE, flags);
                    Slog.w(TAG, "ScreenRotationAnimation ctor: displayOffset="
                            + mOriginalDisplayRect.toShortString());
                } else {
                    mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface",
                            mWidth, mHeight,
                            PixelFormat.OPAQUE, flags);
                }
                //4 截取屏幕并显示这个surface,注意这里设置的z轴SCREEN_FREEZE_LAYER_SCREENSHOT很大,在上面
                // capture a screenshot into the surface we just created
                Surface sur = new Surface();
                sur.copyFrom(mSurfaceControl);
                // FIXME: we should use the proper display
                SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
                        SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
                mSurfaceControl.setLayerStack(display.getLayerStack());
                mSurfaceControl.setLayer(SCREEN_FREEZE_LAYER_SCREENSHOT);
                mSurfaceControl.setAlpha(0);
                mSurfaceControl.show();
                sur.destroy();
            } catch (OutOfResourcesException e) {
                Slog.w(TAG, "Unable to allocate freeze surface", e);
            }

            if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
                    "  FREEZE " + mSurfaceControl + ": CREATE");

            setRotationInTransaction(originalRotation);
        } finally {
            if (!inTransaction) { //5 最后提交事务
                SurfaceControl.closeTransaction();
                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
                        "<<< CLOSE TRANSACTION ScreenRotationAnimation");
            }
        }
    }
// Must be called while in a transaction.
    private void setRotationInTransaction(int rotation) {
        mCurRotation = 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); //这里设置alpha为1使surface可见
    }

从ScreenRotationAnimation的构造中可以看出来创建一个Surface,并且截取屏幕,放在所有layer的上面,然后显示这个layer,导致了冻结屏幕后其实显示的界面已经变成了截图的这个surface. 这里不是研究动画矩阵的变化,就不分析矩阵相关的操作了(其实也很简单,我前面有写过相关的博客)。

同样WMS有暴露了一个结束冻结的方法stopFreezingScreen

@Override
    public void stopFreezingScreen() {
        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
                "stopFreezingScreen()")) {
            throw new SecurityException("Requires FREEZE_SCREEN permission");
        }

        synchronized(mWindowMap) { //设置mClientFreezingScreen为false标志客户端请求的冻结屏幕已经结束,调用stopFreezingDisplayLocked执行解冻操作
            if (mClientFreezingScreen) {
                mClientFreezingScreen = false;
                mLastFinishedFreezeSource = "client";
                final long origId = Binder.clearCallingIdentity();
                try {
                    stopFreezingDisplayLocked();
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }
        }
    }

同样stopFreezingDisplayLocak为解冻操作的实作者

void stopFreezingDisplayLocked() {
        if (!mDisplayFrozen) { //1 没有冻屏直接返回
            return;
        }
        //2 判断是否所有引起冻结的情况都已经解除,其中mWaitingForConfig表示配置属性变化
        //mAppsFreezingScreen表示切换Activity时候引起的冻结,mWindowsFreezingScreen Window切换引起的,mClientFreezingScreen客户明确请求
        if (mWaitingForConfig || mAppsFreezingScreen > 0
                || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
                || mClientFreezingScreen || !mOpeningApps.isEmpty()) {
            if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
                + ", mClientFreezingScreen=" + mClientFreezingScreen
                + ", mOpeningApps.size()=" + mOpeningApps.size());
            return;
        }

        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
                "stopFreezingDisplayLocked: Unfreezing now");
        mDisplayFrozen = false; //3 核心变量解除冻结
        mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
        StringBuilder sb = new StringBuilder(128);
        sb.append("Screen frozen for ");
        TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
        if (mLastFinishedFreezeSource != null) {
            sb.append(" due to ");
            sb.append(mLastFinishedFreezeSource);
        }
        Slog.i(TAG_WM, sb.toString());
        mH.removeMessages(H.APP_FREEZE_TIMEOUT); //4移除超时消息
        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
        if (PROFILE_ORIENTATION) {
            Debug.stopMethodTracing();
        }

        boolean updateRotation = false;

        final DisplayContent displayContent = getDefaultDisplayContentLocked();
        final int displayId = displayContent.getDisplayId();
        ScreenRotationAnimation screenRotationAnimation =
                mAnimator.getScreenRotationAnimationLocked(displayId);
        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
                && screenRotationAnimation.hasScreenshot()) {//5 启动冻结时候设置的动画
            if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation");
            // TODO(multidisplay): rotation on main screen only.
            DisplayInfo displayInfo = displayContent.getDisplayInfo();
            // Get rotation animation again, with new top window
            boolean isDimming = displayContent.isDimming();
            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
                mExitAnimId = mEnterAnimId = 0;
            }
            //6.1 dismiss成功后执行动画
            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                    getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
                scheduleAnimationLocked();
            } else {
            //6.2 dismiss不成功结束动画
                screenRotationAnimation.kill();
                mAnimator.setScreenRotationAnimationLocked(displayId, null);
                updateRotation = true;
            }
        } else {// 6.3 不支持自定义动画什么都不做
            if (screenRotationAnimation != null) {
                screenRotationAnimation.kill();
                mAnimator.setScreenRotationAnimationLocked(displayId, null);
            }
            updateRotation = true;
        }

        //7 恢复接收input事件
        mInputMonitor.thawInputDispatchingLw();

        boolean configChanged;

        // While the display is frozen we don't re-compute the orientation
        // to avoid inconsistent states.  However, something interesting
        // could have actually changed during that time so re-evaluate it
        // now to catch that.
        // 8 根据app更新方向
        configChanged = updateOrientationFromAppTokensLocked(false);

        // A little kludge: a lot could have happened while the
        // display was frozen, so now that we are coming back we
        // do a gc so that any remote references the system
        // processes holds on others can be released if they are
        // no longer needed.
        // 9 进行gc
        mH.removeMessages(H.FORCE_GC);
        mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
       //10 释放weak lock
        mScreenFrozenLock.release();

        //11 更新方向
        if (updateRotation) {
            if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
            configChanged |= updateRotationUncheckedLocked(false);
        }
        //12通知
        if (configChanged) {
            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
        }
    }

这里我们关心的是ScreenRotationAnimation 关闭和动画执行的过程

 public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
            float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
        if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
        if (mSurfaceControl == null) { //1 没有创建surface返回
            // Can't do animation.
            return false;
        }
        if (!mStarted) { //开启动画
            startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
                    true, exitAnim, enterAnim);
        }
        if (!mStarted) {
            return false;
        }
        if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
        mFinishAnimReady = true; //结束动画开始
        return true;
    }

动画的初始化都在startAnimation函数中

/**
     * Returns true if animating.
     */
    private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
            float animationScale, int finalWidth, int finalHeight, boolean dismissing,
            int exitAnim, int enterAnim) {
        if (mSurfaceControl == null) {
            // Can't do animation.
            return false;
        }
        if (mStarted) {
            return true;
        }

        mStarted = true;

        boolean firstStart = false;

        // Figure out how the screen has moved from the original rotation.
        int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);

        if (TWO_PHASE_ANIMATION && mFinishExitAnimation == null
                && (!dismissing || delta != Surface.ROTATION_0)) {
            if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations");
            firstStart = true;
            mStartExitAnimation = AnimationUtils.loadAnimation(mContext,
                    com.android.internal.R.anim.screen_rotate_start_exit);
            mStartEnterAnimation = AnimationUtils.loadAnimation(mContext,
                    com.android.internal.R.anim.screen_rotate_start_enter);
            if (USE_CUSTOM_BLACK_FRAME) {
                mStartFrameAnimation = AnimationUtils.loadAnimation(mContext,
                        com.android.internal.R.anim.screen_rotate_start_frame);
            }
            mFinishExitAnimation = AnimationUtils.loadAnimation(mContext,
                    com.android.internal.R.anim.screen_rotate_finish_exit);
            mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext,
                    com.android.internal.R.anim.screen_rotate_finish_enter);
            if (USE_CUSTOM_BLACK_FRAME) {
                mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext,
                        com.android.internal.R.anim.screen_rotate_finish_frame);
            }
        }

        if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth="
                + finalWidth + " finalHeight=" + finalHeight
                + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);

        //2 加载动画
        final boolean customAnim;
        if (exitAnim != 0 && enterAnim != 0) {
            customAnim = true;
            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
        } else {
            customAnim = false;
            switch (delta) {
                case Surface.ROTATION_0:
                    mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_0_exit);
                    mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_0_enter);
                    if (USE_CUSTOM_BLACK_FRAME) {
                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
                                com.android.internal.R.anim.screen_rotate_0_frame);
                    }
                    break;
                case Surface.ROTATION_90:
                    mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_plus_90_exit);
                    mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_plus_90_enter);
                    if (USE_CUSTOM_BLACK_FRAME) {
                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
                                com.android.internal.R.anim.screen_rotate_plus_90_frame);
                    }
                    break;
                case Surface.ROTATION_180:
                    mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_180_exit);
                    mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_180_enter);
                    if (USE_CUSTOM_BLACK_FRAME) {
                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
                                com.android.internal.R.anim.screen_rotate_180_frame);
                    }
                    break;
                case Surface.ROTATION_270:
                    mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_minus_90_exit);
                    mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                            com.android.internal.R.anim.screen_rotate_minus_90_enter);
                    if (USE_CUSTOM_BLACK_FRAME) {
                        mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
                                com.android.internal.R.anim.screen_rotate_minus_90_frame);
                    }
                    break;
            }
        }

        // Initialize the animations.  This is a hack, redefining what "parent"
        // means to allow supplying the last and next size.  In this definition
        // "%p" is the original (let's call it "previous") size, and "%" is the
        // screen's current/new size.
        if (TWO_PHASE_ANIMATION && firstStart) {
            // Compute partial steps between original and final sizes.  These
            // are used for the dimensions of the exiting and entering elements,
            // so they are never stretched too significantly.
            final int halfWidth = (finalWidth + mOriginalWidth) / 2;
            final int halfHeight = (finalHeight + mOriginalHeight) / 2;

            if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations");
            mStartEnterAnimation.initialize(finalWidth, finalHeight,
                    halfWidth, halfHeight);
            mStartExitAnimation.initialize(halfWidth, halfHeight,
                    mOriginalWidth, mOriginalHeight);
            mFinishEnterAnimation.initialize(finalWidth, finalHeight,
                    halfWidth, halfHeight);
            mFinishExitAnimation.initialize(halfWidth, halfHeight,
                    mOriginalWidth, mOriginalHeight);
            if (USE_CUSTOM_BLACK_FRAME) {
                mStartFrameAnimation.initialize(finalWidth, finalHeight,
                        mOriginalWidth, mOriginalHeight);
                mFinishFrameAnimation.initialize(finalWidth, finalHeight,
                        mOriginalWidth, mOriginalHeight);
            }
        }
        mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
        mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
        if (USE_CUSTOM_BLACK_FRAME) {
            mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth,
                    mOriginalHeight);
        }
        mAnimRunning = false;
        mFinishAnimReady = false;
        mFinishAnimStartTime = -1;

        if (TWO_PHASE_ANIMATION && firstStart) {
            mStartExitAnimation.restrictDuration(maxAnimationDuration);
            mStartExitAnimation.scaleCurrentDuration(animationScale);
            mStartEnterAnimation.restrictDuration(maxAnimationDuration);
            mStartEnterAnimation.scaleCurrentDuration(animationScale);
            mFinishExitAnimation.restrictDuration(maxAnimationDuration);
            mFinishExitAnimation.scaleCurrentDuration(animationScale);
            mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
            mFinishEnterAnimation.scaleCurrentDuration(animationScale);
            if (USE_CUSTOM_BLACK_FRAME) {
                mStartFrameAnimation.restrictDuration(maxAnimationDuration);
                mStartFrameAnimation.scaleCurrentDuration(animationScale);
                mFinishFrameAnimation.restrictDuration(maxAnimationDuration);
                mFinishFrameAnimation.scaleCurrentDuration(animationScale);
            }
        }
        //3 设置动画属性
        mRotateExitAnimation.restrictDuration(maxAnimationDuration);
        mRotateExitAnimation.scaleCurrentDuration(animationScale);
        mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
        mRotateEnterAnimation.scaleCurrentDuration(animationScale);
        if (USE_CUSTOM_BLACK_FRAME) {
            mRotateFrameAnimation.restrictDuration(maxAnimationDuration);
            mRotateFrameAnimation.scaleCurrentDuration(animationScale);
        }

        final int layerStack = mDisplayContent.getDisplay().getLayerStack();
        if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
            if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                    TAG_WM,
                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
            SurfaceControl.openTransaction();

            // Compute the transformation matrix that must be applied
            // the the black frame to make it stay in the initial position
            // before the new screen rotation.  This is different than the
            // snapshot transformation because the snapshot is always based
            // of the native orientation of the screen, not the orientation
            // we were last in.
            createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);

            try {
                Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
                        mOriginalWidth*2, mOriginalHeight*2);
                Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
                mCustomBlackFrame = new BlackFrame(session, outer, inner,
                        SCREEN_FREEZE_LAYER_CUSTOM, layerStack, false);
                mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
            } catch (OutOfResourcesException e) {
                Slog.w(TAG, "Unable to allocate black surface", e);
            } finally {
                SurfaceControl.closeTransaction();
                if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                        TAG_WM,
                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
            }
        }

        if (!customAnim && mExitingBlackFrame == null) {
            if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                    TAG_WM,
                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
            SurfaceControl.openTransaction();
            try {
                // Compute the transformation matrix that must be applied
                // the the black frame to make it stay in the initial position
                // before the new screen rotation.  This is different than the
                // snapshot transformation because the snapshot is always based
                // of the native orientation of the screen, not the orientation
                // we were last in.
                createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);

                final Rect outer;
                final Rect inner;
                if (mForceDefaultOrientation) {
                    // Going from a smaller Display to a larger Display, add curtains to sides
                    // or top and bottom. Going from a larger to smaller display will result in
                    // no BlackSurfaces being constructed.
                    outer = mCurrentDisplayRect;
                    inner = mOriginalDisplayRect;
                } else {
                    outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
                            mOriginalWidth*2, mOriginalHeight*2);
                    inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
                }
                mExitingBlackFrame = new BlackFrame(session, outer, inner,
                        SCREEN_FREEZE_LAYER_EXIT, layerStack, mForceDefaultOrientation);
                mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
            } catch (OutOfResourcesException e) {
                Slog.w(TAG, "Unable to allocate black surface", e);
            } finally {
                SurfaceControl.closeTransaction();
                if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                        TAG_WM,
                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
            }
        }

        if (customAnim && mEnteringBlackFrame == null) {
            if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                    TAG_WM,
                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
            SurfaceControl.openTransaction();
            //4 插入一个黑色的layer
            try {
                Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
                        finalWidth*2, finalHeight*2);
                Rect inner = new Rect(0, 0, finalWidth, finalHeight);
                mEnteringBlackFrame = new BlackFrame(session, outer, inner,
                        SCREEN_FREEZE_LAYER_ENTER, layerStack, false);
            } catch (OutOfResourcesException e) {
                Slog.w(TAG, "Unable to allocate black surface", e);
            } finally {
                SurfaceControl.closeTransaction();
                if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
                        TAG_WM,
                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
            }
        }

        return true;
    }

scheduleAnimationLocked函数会触发动画执行

  /** Note that Locked in this case is on mLayoutToAnim */
    void scheduleAnimationLocked() {
        if (!mAnimationScheduled) {
            mAnimationScheduled = true;
            mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
        }
    }

动画执行的过程在WindowAnimator类中,是动画执行的引擎. animateLocked函数的第一段就是动画执行的过程

SurfaceControl.openTransaction();
        SurfaceControl.setAnimationTransaction();
        try {
            final int numDisplays = mDisplayContentsAnimators.size();
            for (int i = 0; i < numDisplays; i++) {
                final int displayId = mDisplayContentsAnimators.keyAt(i);
                updateAppWindowsLocked(displayId);  // 1 执行app transaction动画
                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i); 

                final ScreenRotationAnimation screenRotationAnimation =
                        displayAnimator.mScreenRotationAnimation; //2 转屏动画
                if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { // 如果有需要执行的动画
                    removeMultiWindowAnimationLocked(displayAnimator);//3干掉分屏动画
                    if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) { //4执行冻结屏幕动画
                        //5 执行成功
                        setAnimating(true);
                    } else {
                         //6 执行完成更新状态
                        mBulkUpdateParams |= SET_UPDATE_ROTATION;
                        screenRotationAnimation.kill(); //7 结束动画
                        displayAnimator.mScreenRotationAnimation = null;

                        //TODO (multidisplay): Accessibility supported only for the default display.
                        if (mService.mAccessibilityController != null
                                && displayId == Display.DEFAULT_DISPLAY) {
                            // We just finished rotation animation which means we did not
                            // anounce the rotation and waited for it to end, announce now.
                            mService.mAccessibilityController.onRotationChangedLocked(
                                    mService.getDefaultDisplayContentLocked(), mService.mRotation);
                        }
                    }

                }

                // Update animations of all applications, including those
                // associated with exiting/removed apps
                updateWindowsLocked(displayId);
                WindowAnimatorInjector.updateLockDeviceWindowLocked(displayId, mService);
                updateWallpaperLocked(displayId);

                final WindowList windows = mService.getWindowListLocked(displayId);
                final int N = windows.size();
                for (int j = 0; j < N; j++) {
                    windows.get(j).mWinAnimator.prepareSurfaceLocked(true);
                }
            }

上面冻结动画执行过程很简单,我们来看下具体动画的执行过程

public boolean stepAnimationLocked(long now) {
        if (!hasAnimations()) { //1 不包含动画直接返回
            if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
            mFinishAnimReady = false;
            return false;
        }

        if (!mAnimRunning) { //2 首次执行
            if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
            //3 设置一些动画开始时间
            if (TWO_PHASE_ANIMATION) {
                if (mStartEnterAnimation != null) {
                    mStartEnterAnimation.setStartTime(now);
                }
                if (mStartExitAnimation != null) {
                    mStartExitAnimation.setStartTime(now);
                }
                if (mFinishEnterAnimation != null) {
                    mFinishEnterAnimation.setStartTime(0);
                }
                if (mFinishExitAnimation != null) {
                    mFinishExitAnimation.setStartTime(0);
                }
            }
            if (USE_CUSTOM_BLACK_FRAME) {
                if (mStartFrameAnimation != null) {
                    mStartFrameAnimation.setStartTime(now);
                }
                if (mFinishFrameAnimation != null) {
                    mFinishFrameAnimation.setStartTime(0);
                }
                if (mRotateFrameAnimation != null) {
                    mRotateFrameAnimation.setStartTime(now);
                }
            }
            if (mRotateEnterAnimation != null) {
                mRotateEnterAnimation.setStartTime(now);
            }
            if (mRotateExitAnimation != null) {
                mRotateExitAnimation.setStartTime(now);
            }
            //3 表示动画开启,mHalfwayPoint表示开始一半的时间
            mAnimRunning = true;
            mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2;
        }

        return stepAnimation(now);
    }

下面来分析setpAnimation

    private boolean stepAnimation(long now) {
        if (now > mHalfwayPoint) { //1 大于一半时间设置为Long.MAX_VALUE,可以看下一半时间的时候做啥
            mHalfwayPoint = Long.MAX_VALUE;
        }
        if (mFinishAnimReady && mFinishAnimStartTime < 0) { //2设置开始执行时间
            if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
            mFinishAnimStartTime = now;
        }

        if (TWO_PHASE_ANIMATION) { //3 二相位的动画执行
            mMoreStartExit = false;
            if (mStartExitAnimation != null) {
                mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
            }

            mMoreStartEnter = false;
            if (mStartEnterAnimation != null) {
                mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
            }
        }
        if (USE_CUSTOM_BLACK_FRAME) { 
            mMoreStartFrame = false;
            if (mStartFrameAnimation != null) { // 4根据时间从开始动画中获取矩阵
                mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
            }
        }

        long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; 
        if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);

        if (TWO_PHASE_ANIMATION) { //5 二相位计数动画动画处理
            mMoreFinishExit = false;
            if (mFinishExitAnimation != null) {
                mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
            }

            mMoreFinishEnter = false;
            if (mFinishEnterAnimation != null) { //5.1 结束动画中获取矩阵
                mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
            }
        }
        if (USE_CUSTOM_BLACK_FRAME) {  //6 结束动画中获取矩阵
            mMoreFinishFrame = false;
            if (mFinishFrameAnimation != null) {
                mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
            }
        }

        mMoreRotateExit = false;
        if (mRotateExitAnimation != null) { //7 从旋转离开的动画中获取矩阵
            mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
        }

        mMoreRotateEnter = false;
        if (mRotateEnterAnimation != null) {
            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
        }

        if (USE_CUSTOM_BLACK_FRAME) { //8 黑屏动画中获取矩阵
            mMoreRotateFrame = false;
            if (mRotateFrameAnimation != null) {
                mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
            }
        }
        //9 结束的处理
        if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) {
            if (TWO_PHASE_ANIMATION) {
                if (mStartExitAnimation != null) {
                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
                    mStartExitAnimation.cancel();
                    mStartExitAnimation = null;
                    mStartExitTransformation.clear();
                }
                if (mFinishExitAnimation != null) {
                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
                    mFinishExitAnimation.cancel();
                    mFinishExitAnimation = null;
                    mFinishExitTransformation.clear();
                }
            }
            if (mRotateExitAnimation != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!");
                mRotateExitAnimation.cancel();
                mRotateExitAnimation = null;
                mRotateExitTransformation.clear();
            }
        }

        if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) {
            if (TWO_PHASE_ANIMATION) {
                if (mStartEnterAnimation != null) {
                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
                    mStartEnterAnimation.cancel();
                    mStartEnterAnimation = null;
                    mStartEnterTransformation.clear();
                }
                if (mFinishEnterAnimation != null) {
                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
                    mFinishEnterAnimation.cancel();
                    mFinishEnterAnimation = null;
                    mFinishEnterTransformation.clear();
                }
            }
            if (mRotateEnterAnimation != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!");
                mRotateEnterAnimation.cancel();
                mRotateEnterAnimation = null;
                mRotateEnterTransformation.clear();
            }
        }

        if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) {
            if (mStartFrameAnimation != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!");
                mStartFrameAnimation.cancel();
                mStartFrameAnimation = null;
                mStartFrameTransformation.clear();
            }
            if (mFinishFrameAnimation != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!");
                mFinishFrameAnimation.cancel();
                mFinishFrameAnimation = null;
                mFinishFrameTransformation.clear();
            }
            if (mRotateFrameAnimation != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!");
                mRotateFrameAnimation.cancel();
                mRotateFrameAnimation = null;
                mRotateFrameTransformation.clear();
            }
        }

        mExitTransformation.set(mRotateExitTransformation);
        mEnterTransformation.set(mRotateEnterTransformation);
        if (TWO_PHASE_ANIMATION) {
            mExitTransformation.compose(mStartExitTransformation);
            mExitTransformation.compose(mFinishExitTransformation);

            mEnterTransformation.compose(mStartEnterTransformation);
            mEnterTransformation.compose(mFinishEnterTransformation);
        }

        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);

        if (USE_CUSTOM_BLACK_FRAME) {
            //mFrameTransformation.set(mRotateExitTransformation);
            //mFrameTransformation.compose(mStartExitTransformation);
            //mFrameTransformation.compose(mFinishExitTransformation);
            mFrameTransformation.set(mRotateFrameTransformation);
            mFrameTransformation.compose(mStartFrameTransformation);
            mFrameTransformation.compose(mFinishFrameTransformation);
            mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
        }
        // 10 返回是否还有更多动画:条件是其中一个动画结束
        final boolean more = (TWO_PHASE_ANIMATION
                    && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
                || (USE_CUSTOM_BLACK_FRAME
                        && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
                || mMoreRotateEnter || mMoreRotateExit
                || !mFinishAnimReady;
        // 11设置最终矩阵
        mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);

        if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);

        return more;
    }

到这里来看冻屏其实还是很简单的,只不过是截取图片显示出来,到冻结屏幕结束时候执行一个渐变动画

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页