背景:

aosp自带的单手模式一般如下:
在这里插入图片描述单手模式本身在层级结构树中是有单独的一个Feature:
在这里插入图片描述结构树构建时候代码配置如下:
在这里插入图片描述
详细的原理及结合Winscope分析之前已经有分享过
重学WMS核心层级结构树之Feature作用-实战案例讲解

不过没有拿出具体源码分析,本文就来补充这块单手模式的源码分析,看看源码中这个Feature到底是如何影响单手模式的偏移的。

OneHanded位置偏移设置

位置Y方向偏移堆栈情况如下:

  setPosition (tx=3358664428444  sc=OneHanded:32:32) x=0.0 y=1183.4318
  java.lang.Throwable
  	at android.view.SurfaceControlRegistry.checkCallStackDebugging(SurfaceControlRegistry.java:330)
  	at android.view.SurfaceControl$Transaction.setPosition(SurfaceControl.java:3041)
  	at com.android.wm.shell.onehanded.OneHandedSurfaceTransactionHelper.translate(OneHandedSurfaceTransactionHelper.java:56)
  	at com.android.wm.shell.onehanded.OneHandedAnimationController$OneHandedTransitionAnimator$1.applySurfaceControlTransaction(OneHandedAnimationController.java:284)
  	at com.android.wm.shell.onehanded.OneHandedAnimationController$OneHandedTransitionAnimator.onAnimationUpdate(OneHandedAnimationController.java:188)
  	at android.animation.Animator$AnimatorCaller.lambda$static$4(Animator.java:855)
  	at android.animation.Animator$AnimatorCaller$$ExternalSyntheticLambda6.call(D8$$SyntheticClass:0)
  	at android.animation.Animator.callOnList(Animator.java:666)
  	at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1645)
  	at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1405)
  	at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1563)
  	at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:344)
  	at android.animation.AnimationHandler.-$$Nest$mdoAnimationFrame(Unknown Source:0)
  	at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:87)
  	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1404)
  	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1415)
  	at android.view.Choreographer.doCallbacks(Choreographer.java:1015)
  	at android.view.Choreographer.doFrame(Choreographer.java:941)
  	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1389)
  	at android.os.Handler.handleCallback(Handler.java:959)
  	at android.os.Handler.dispatchMessage(Handler.java:100)
  	at android.os.Looper.loopOnce(Looper.java:232)
  	at android.os.Looper.loop(Looper.java:317)
  	at android.os.HandlerThread.run(HandlerThread.java:85)

代码剖析

frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
在这里插入图片描述
那么看看这里的leash是哪里传递过来的
frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java

        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
            mOneHandedAnimationCallbacks.forEach(
                    (callback) -> callback.onAnimationUpdate(tx, 0f, mCurrentValue)
            );
            applySurfaceControlTransaction(mLeash, tx, animation.getAnimatedFraction());
        }

那么这里的mLeash又是哪来的呢?
在这里插入图片描述
这里OneHandedTransitionAnimator又是由ofYOffset方法导致的构造
在这里插入图片描述
而ofYOffset又是通过getAnimator方法获取的
在这里插入图片描述
frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java

private void animateWindows(WindowContainerToken token, SurfaceControl leash, float fromPos,
            float toPos, @OneHandedAnimationController.TransitionDirection int direction,
            int durationMs) {
        final OneHandedAnimationController.OneHandedTransitionAnimator animator =
                mAnimationController.getAnimator(token, leash, fromPos, toPos,
                        mLastVisualDisplayBounds);
//省略
    }

再看看animateWindows方法
frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java

    /**
     * Offset the windows by a given offset on Y-axis, triggered also from screen rotation.
     * Directly perform manipulation/offset on the leash.
     */
    public void scheduleOffset(int xOffset, int yOffset) {
        final float fromPos = mLastVisualOffset;
 //省略
 //这里会调用的mDisplayAreaTokenMap这个集合来遍历获取leash
        mDisplayAreaTokenMap.forEach(
                (token, leash) -> {
                    animateWindows(token, leash, fromPos, yOffset, direction,
                            mEnterExitAnimationDurationMs);
                });
        mLastVisualOffset = yOffset;
    }

那么这里的mDisplayAreaTokenMap又是哪里设置的呢?

frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java

  @Override
    public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
            @NonNull SurfaceControl leash) {
        leash.setUnreleasedWarningCallSite(
                "OneHandedSiaplyAreaOrganizer.onDisplayAreaAppeared");
        mDisplayAreaTokenMap.put(displayAreaInfo.token, leash);
    }

onDisplayAreaAppeared调用地方呢?可以看看如下registerOrganizer

    @Override
    public List<DisplayAreaAppearedInfo> registerOrganizer(int displayAreaFeature) {
        final List<DisplayAreaAppearedInfo> displayAreaInfos =
                super.registerOrganizer(displayAreaFeature);
        for (int i = 0; i < displayAreaInfos.size(); i++) {
            final DisplayAreaAppearedInfo info = displayAreaInfos.get(i);
            onDisplayAreaAppeared(info.getDisplayAreaInfo(), info.getLeash());
        }
        mIsReady = true;
        updateDisplayBounds();
        return displayAreaInfos;
    }

这里的调用是
frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java

    private void updateOneHandedEnabled() {
     //省略

        if (mDisplayAreaOrganizer.getDisplayAreaTokenMap().isEmpty()) {
            mDisplayAreaOrganizer.registerOrganizer(
                    OneHandedDisplayAreaOrganizer.FEATURE_ONE_HANDED);
        }
    }

注意在这里时候registerOrganizer时候有传递FEATURE_ONE_HANDED这个参数

获取OneHanded对应的WindowContainer

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

 @Override
    public ParceledListSlice<DisplayAreaAppearedInfo> registerOrganizer(
            IDisplayAreaOrganizer organizer, int feature) {
        enforceTaskPermission("registerOrganizer()");
        try {
            synchronized (mGlobalLock) {
                if (mOrganizersByFeatureIds.get(feature) != null) {
                    mOrganizersByFeatureIds.remove(feature).destroy();
                }

                final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
                        feature);
                final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
                mService.mRootWindowContainer.forAllDisplays(dc -> {
                    dc.forAllDisplayAreas((da) -> {
                    	//遍历出所有为FEATURE_ONE_HANDED的da
                        if (da.mFeatureId != feature) return;
                        displayAreaInfos.add(organizeDisplayArea(organizer, da,
                                "DisplayAreaOrganizerController.registerOrganizer"));
                    });
                });

                mOrganizersByFeatureIds.put(feature, state);
                return new ParceledListSlice<>(displayAreaInfos);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

到此就OneHanded相关Feature剖析讲解完成。

主要流程分为如下两个:

1、收集所有的Feature为FEATURE_ONE_HANDED的WindowContainer,进行保存到集合

2、单手设置本质就是对上面所有FEATURE_ONE_HANDED的WindowContainer进行位置Y方向的偏移

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐