了解AsyncRotationController

概述

基于android 15.0, 以从强制横屏App上滑退回桌面流程来分析

frameworks/base/services/core/java/com/android/server/wm/AsyncRotationController.java

AsyncRotationController 是一种控制器,用于处理设备显示屏旋转时非活动窗口的异步更新。这种控制器通过异步处理来优化屏幕旋转或应用过渡动画的启动延迟,确保窗口在旋转过程中能够平滑过渡,避免闪烁或延迟问题。具体功能包括:

  • 在旋转变化时处理窗口的淡出和淡入效果。
  • 隐藏和显示目标窗口以匹配新的旋转角度。
  • 使用同步事务管理无缝旋转,确保窗口能够平滑过渡到新的旋转状态。
Async Rotation执行时机

在这里插入图片描述

// DisplayContent.java
void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) {
    if (mFixedRotationLaunchingApp == null && r != null) {
        mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation);
        // 延迟隐藏动画,以避免在短时间内点击导航栏可能触发固定旋转时出现闪烁
        final boolean shouldDebounce = r == mFixedRotationTransitionListener.mAnimatingRecents
                || mTransitionController.isTransientLaunch(r);
        startAsyncRotation(shouldDebounce);
    } else if (mFixedRotationLaunchingApp != null && r == null) {
        mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this);
        // 如果请求display的下一次transition,保持异步旋转控制器。
        if (!mTransitionController.hasCollectingRotationChange(this, getRotation())) {
            finishAsyncRotationIfPossible();
        }
    }
    mFixedRotationLaunchingApp = r;
}

用于启动异步旋转过程。这个过程允许应用程序或系统在不阻塞主线程的情况下处理显示屏的旋转,从而提供更平滑的用户体验.

// DisplayContent.java
private boolean startAsyncRotation(boolean shouldDebounce) {
    if (shouldDebounce) {
        mWmService.mH.postDelayed(() -> {
            synchronized (mWmService.mGlobalLock) {
                if (mFixedRotationLaunchingApp != null
                        && startAsyncRotation(false /* shouldDebounce */)) {
                    // 应用该事务,使动画控制能够立即生效
                    getPendingTransaction().apply();
                }
            }
        }, FIXED_ROTATION_HIDE_ANIMATION_DEBOUNCE_DELAY_MS); //250ms
        return false;
    }
    if (mAsyncRotationController == null) {
        mAsyncRotationController = new AsyncRotationController(this);
        mAsyncRotationController.start();
        return true;
    }
    return false;
}

动画执行

  1. 收集目标窗口
// AsyncRotationController.java
AsyncRotationController(DisplayContent displayContent) {
    .....
    // 收集那些可以异步旋转而不阻塞display的窗口。
    displayContent.forAllWindows(this, true /* traverseTopToBottom */);
    ......
}

public void accept(WindowState w) {
    if (!w.mHasSurface || !canBeAsync(w.mToken)) {
        return;
    }
    if (mTransitionOp == OP_LEGACY && w.mForceSeamlesslyRotate) {
        // Legacy transition already handles seamlessly windows.
        return;
    }
    ......
    // 大部分都是执行fade窗口动画
    final int action = mTransitionOp == OP_CHANGE_MAY_SEAMLESS || w.mForceSeamlesslyRotate
            ? Operation.ACTION_SEAMLESS : Operation.ACTION_FADE;
    mTargetWindowTokens.put(w.mToken, new Operation(action));
}
  1. 目标窗口在TO_FRONT transition启动时淡出
    在这里插入图片描述
07-11 15:27:24.362  3750  3785 D AsyncRotation: Start fade-out Window{ae32994 u0 Floating XXX}
// AsyncRotationController.java
/**
 * 为可能稍后无缝旋转的窗口令牌准备相应的操作(例如隐藏动画)
 */
void start() {
   .....
    for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
        final WindowToken windowToken = mTargetWindowTokens.keyAt(i);
        final Operation op = mTargetWindowTokens.valueAt(i);
        if (op.mAction == Operation.ACTION_FADE || op.mAction == Operation.ACTION_TOGGLE_IME) {
            fadeWindowToken(false /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
            op.mLeash = windowToken.getAnimationLeash();
            if (DEBUG) Slog.d(TAG, "Start fade-out " + windowToken.getTopChild());
        } else if (op.mAction == Operation.ACTION_SEAMLESS) {
            op.mLeash = windowToken.mSurfaceControl;
            if (DEBUG) Slog.d(TAG, "Start seamless " + windowToken.getTopChild());
        }
    }
    .....
}
  1. 目标窗口在CHANGE transition启动时以new rotation重绘
    在这里插入图片描述
3750  3785 V WindowManager: Resize reasons for w=Window{eb45fff u0 Floating XXX}:  forceReportingResized=false insetsChanged=true configChanged=true didFrameInsetsChange=true
3750  3785 I WindowManager: Resizing Window{ae32994 u0 Floating XXX} WITH DRAW PENDING
3750  3785 V WindowManager: Requested redraw for orientation change: Window{ae32994 u0 Floating XXX}
3750  7896 I WindowManager: finishDrawing of orientation change: Window{ae32994 u0 Floating XXX} 100ms
// WindowState.java
void updateResizingWindowIfNeeded() {
    ......
    // display rotation改变, 所以这里的configChanged为true
    final boolean configChanged = !mInRelayout && !isLastConfigReportedToClient();
    ......
    final boolean contentChanged = didFrameInsetsChange || configChanged
            || dragResizingChanged || attachedFrameChanged;
    .....

    if (contentChanged || insetsChanged || shouldSendRedrawForSync()) {
        ProtoLog.v(WM_DEBUG_RESIZE,
                    "Resize reasons for w=%s:  %s configChanged=%b didFrameInsetsChange=%b",
                    this, mWindowFrames.getInsetsChangedInfo(),
                    configChanged, didFrameInsetsChange);

        .....

        // 重置当前窗口的mDrawState为DRAW_PENDING
        if ((configChanged || getOrientationChanging() || dragResizingChanged)
                && isVisibleRequested()) {
            winAnimator.mDrawState = DRAW_PENDING;
            .....
        }
        if (!mWmService.mResizingWindows.contains(this)) {
            ProtoLog.v(WM_DEBUG_RESIZE, "Resizing window %s", this);
            mWmService.mResizingWindows.add(this);
        }
    } .....
}

void reportResized() {
    ......
    ProtoLog.v(WM_DEBUG_RESIZE, "Reporting new frame to %s: %s", this,
            mWindowFrames.mCompatFrame);
    final boolean drawPending = mWinAnimator.mDrawState == DRAW_PENDING;
    if (drawPending) {
        ProtoLog.i(WM_DEBUG_ORIENTATION, "Resizing %s WITH DRAW PENDING", this);
    }

    .....
    final boolean reportDraw = syncRedraw || drawPending;
    .....

    if (Flags.bundleClientTransactionFlag()) {
        getProcess().scheduleClientTransactionItem(
                WindowStateResizeItem.obtain(mClient, mClientWindowFrames, reportDraw,
                        mLastReportedConfiguration, getCompatInsetsState(), forceRelayout,
                        alwaysConsumeSystemBars, displayId,
                        syncWithBuffers ? mSyncSeqId : -1, isDragResizing,
                        mLastReportedActivityWindowInfo));
        onResizePostDispatched(drawPending, prevRotation, displayId);
    }
    ......
}
  1. TO_FRONT动画结束时开始淡入目标窗口
07-11 15:27:25.532  3750  7896 D AsyncRotation: handleFinishDrawing Window{ae32994 u0 Floating XXX}
07-11 15:27:25.532  3750  7896 D AsyncRotation: Complete set pending Window{ae32994 u0 Floating XXX}
07-11 15:27:25.572  3750  8951 D AsyncRotation: Setup unrotate Window{ae32994 u0 Floating XXX}
07-11 15:27:25.636  3750  7166 D AsyncRotation: Complete directly Window{ae32994 u0 Floating XXX}
07-11 15:27:25.636  3750  7166 D AsyncRotation: finishOp fade-in Window{ae32994 u0 Floating XXX}

在这里插入图片描述

// AsyncRotationController.java
void completeAll() {
    for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
        finishOp(mTargetWindowTokens.keyAt(i));
    }
    mTargetWindowTokens.clear();
    onAllCompleted();
}

private void finishOp(WindowToken windowToken) {
    final Operation op = mTargetWindowTokens.remove(windowToken);
    ......
    else if (op.mAction == Operation.ACTION_FADE) {
        if (DEBUG) Slog.d(TAG, "finishOp fade-in " + windowToken.getTopChild());
        // The previous animation leash will be dropped when preparing fade-in animation, so
        // simply apply new animation without restoring the transformation.
        fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
    } ......
}

finishOp的执行路径

走finishAsyncRotation

在这里插入图片描述
在这里插入图片描述

走completeAll

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值