背景:
前面有给大家布置一个关于系统Feature之放大镜部分剖析的作业,今天刚好整理好了相关文章给大家进行一下作业的核心部分剖析。
下面就带大家手把手分析一下系统放大镜功能具体是怎么和wms的Feature有链接关系的。
功能和使用场景上认识放大镜
放大镜分为两个部分,一个局部放大镜放大,一个全屏放大

局部放大:
使用场景:辅助模式的放大镜功能
该功能开启时候,明显看到放大镜内的画面内容都被放大了。
放大镜原理剖析:
如果只看window的层级结构树,其实是看不出有啥变化,也无法调研出放大镜原理。
ACTIVITY MANAGER CONTAINERS (dumpsys activity containers)
└─ ROOT type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ Display 0 name="Built-in Screen" type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][1440,2960] bounds=[0,0][1440,2960]
├─ Leaf:36:36 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ WindowToken{cc0358 type=2024 android.os.BinderProxy@e9ec03b} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ df26cb1 ScreenDecorOverlayBottom type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ WindowToken{873431a type=2024 android.os.BinderProxy@a53fdc5} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ e6136d4 ScreenDecorOverlay type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ HideDisplayCutout:32:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ OneHanded:34:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ FullscreenMagnification:34:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ Leaf:34:35 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ FullscreenMagnification:33:33 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ Leaf:33:33 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ OneHanded:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Leaf:32:32 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ WindowedMagnification:0:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ HideDisplayCutout:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ OneHanded:26:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ FullscreenMagnification:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ Leaf:29:31 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ Leaf:28:28 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ FullscreenMagnification:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Leaf:26:27 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ Leaf:24:25 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ WindowToken{5382011 type=2024 android.os.BinderProxy@b54e838} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ 7ed7777 com.android.systemui type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ WindowToken{1377eca type=2019 android.os.BinderProxy@356edbc} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ 63fa46c Taskbar type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ HideDisplayCutout:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ OneHanded:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ FullscreenMagnification:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Leaf:18:23 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ OneHanded:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ FullscreenMagnification:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Leaf:17:17 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ WindowToken{dbbf57d type=2040 android.os.BinderProxy@e1c17e6} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ 981cc72 NotificationShade type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ HideDisplayCutout:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ OneHanded:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ FullscreenMagnification:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Leaf:16:16 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ OneHanded:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ FullscreenMagnification:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Leaf:15:15 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ WindowToken{89531b1 type=2000 android.os.BinderProxy@b40bd3b} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ c904696 StatusBar type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ HideDisplayCutout:0:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ OneHanded:0:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ ImePlaceholder:13:14 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ ImeContainer type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ WindowToken{111a7e2 type=2011 android.os.Binder@bdd58ad} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ 977e336 InputMethod type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ FullscreenMagnification:0:12 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ Leaf:3:12 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ WindowToken{4c25074 type=2038 android.os.BinderProxy@bbd593e} type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ 844bb2d ShellDropTarget type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
├─ DefaultTaskDisplayArea type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ Task=658 type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ ActivityRecord{b052b4a u0 com.android.dialer/.main.impl.MainActivity t658} type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ a0ceca0 com.android.dialer/com.android.dialer.main.impl.MainActivity type=standard mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ Task=1 type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ Task=657 type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ ActivityRecord{4ba4130 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t657} type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ │ └─ 562602a com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher type=HOME mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ └─ Task=2 type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
│ ├─ Task=4 type=undefined mode=MULTI-WINDOW override-mode=MULTI-WINDOW requested-bounds=[0,2960][1440,4440] bounds=[0,2960][1440,4440]
│ └─ Task=3 type=undefined mode=MULTI-WINDOW override-mode=MULTI-WINDOW requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ Leaf:0:1 type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ WallpaperWindowToken{62c4b95 token=android.os.Binder@a003f4c} type=undefined mode=fullscreen override-mode=fullscreen requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
└─ 4bc28e5 com.android.systemui.wallpapers.ImageWallpaper type=undefined mode=fullscreen override-mode=undefined requested-bounds=[0,0][0,0] bounds=[0,0][1440,2960]
但是如果看sf的层级结构树既可以看的比较明显

可以看出放大镜显示区域相关的图层有多出好几个。
而且这些图层是有本质上是Mirror了现有的图层,比如桌面和壁纸都显示在放大镜的区域,而且只有放大镜的区域桌面和壁纸是放大的,其他非放大镜区域就是正常显示,那么是如何实现这样呢?

放大镜区域可以放大原理:
1、显示了当前桌面和壁纸图层Layer的Mirror
2、Mirror图层有被放大,而且针对放大镜区域进行了裁剪
对Mirror图层相关的剖析:

1、系统自动会创建一个层级高的Accessibility Overlays图层
2、放大镜功能开启后,会创建对应的Windowless窗口,而且这个窗口有对应的SurfaceView
3、对系统的display的图层会进行Mirror,创建出一个新的MirroRoot图层,下面挂载了系统层级结构的Mirror图层,名字一般会在后面加上“(Mirror)”字样,内容和源图层一样。
4、所有Mirror图层要被裁剪在放大镜的显示区域,而且图层会被scale

Mirror图层这部分的堆栈情况:
frameworks/base/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
/**
* This is called once the surfaceView is created so the mirrored content can be placed as a
* child of the surfaceView.
*/
private void createMirror() {
mMirrorSurface = mirrorDisplay(mDisplayId);//Mirror出display的图层
if (!mMirrorSurface.isValid()) {
return;
}
//把Mirror出来的图层挂载到mMirrorSurfaceView下
mTransaction.show(mMirrorSurface)
.reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
modifyWindowMagnification(false);
}
调用堆栈
createMirror:975, WindowMagnificationController (com.android.systemui.accessibility)
surfaceCreated:1311, WindowMagnificationController (com.android.systemui.accessibility)
updateSurface:1240, SurfaceView (android.view)
lambda$new$0:231, SurfaceView (android.view)
onPreDraw:0, SurfaceView$$ExternalSyntheticLambda1 (android.view)
dispatchOnPreDraw:1176, ViewTreeObserver (android.view)
performTraversals:4239, ViewRootImpl (android.view)
doTraversal:2917, ViewRootImpl (android.view)
run:10324, ViewRootImpl$TraversalRunnable (android.view)
run:1406, Choreographer$CallbackRecord (android.view)
run:1415, Choreographer$CallbackRecord (android.view)
doCallbacks:1015, Choreographer (android.view)
doFrame:945, Choreographer (android.view)
run:1389, Choreographer$FrameDisplayEventReceiver (android.view)
handleCallback:959, Handler (android.os)
dispatchMessage:100, Handler (android.os)
loopOnce:232, Looper (android.os)
loop:317, Looper (android.os)
main:8705, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
run:580, RuntimeInit$MethodAndArgsCaller (com.android.internal.os)
main:886, ZygoteInit (com.android.internal.os)
其实就是在放大镜的SurfaceView创建好了以后,就立即触发mirrorDisplay。
但是大家是否有一个很大疑问?那就是既然是mirrorDisplay正应该是整个DisplayContent内容都会Mirror,但是明显看sf的层级结构树只对
WindowedMagnification:0:31 这个节点进行了Mirror,明显看出限制在0-31层,其他的31层以上的都没有Mirror。

那么明明看方法名字是mirrorDisplay啊,为啥又只Mirror了WindowedMagnification:0:31这个节点。
这里其实就是到我们今天主题:Feature之FEATURE_WINDOWED_MAGNIFICATION该上场了。
mirrorDisplay部分的剖析
frameworks/base/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
/**
* Mirrors a specified display. The SurfaceControl returned is the root of the mirrored
* hierarchy.
*
* @param displayId The id of the display to mirror
* @return The SurfaceControl for the root of the mirrored hierarchy.
*/
private SurfaceControl mirrorDisplay(final int displayId) {
try {
SurfaceControl outSurfaceControl = new SurfaceControl();
//这里会调用到wms的mirrorDisplay
WindowManagerGlobal.getWindowManagerService().mirrorDisplay(displayId,
outSurfaceControl);
return outSurfaceControl;
} catch (RemoteException e) {
Log.e(TAG, "Unable to reach window manager", e);
}
return null;
}
来到wms的mirrorDisplay
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@Override
public boolean mirrorDisplay(int displayId, SurfaceControl outSurfaceControl) {
final SurfaceControl displaySc;
synchronized (mGlobalLock) {
//根据传递进来的displayId获取DisplayContent
DisplayContent displayContent = mRoot.getDisplayContent(displayId);
//调用DisplayContent的getWindowingLayer方法获取要mirror的sc
displaySc = displayContent.getWindowingLayer();
}
//这里最后是调用的mirrorSurface方法,而且这个displaySc并不是真的DisplayContent的sc
final SurfaceControl mirror = SurfaceControl.mirrorSurface(displaySc);
outSurfaceControl.copyFrom(mirror, "WMS.mirrorDisplay");
mirror.release();
return true;
}
上面明显可以看出其实wms的mirrorDisplay其实最后还是调用的mirrorSurface,这里并没有使用DisplayContent的SurfaceControl,那么使用是哪个SurfaceControl呢?
这里就需要看displayContent.getWindowingLayer()方法的具体实现了
frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
/**
* The direct child layer of the display to put all non-overlay windows. This is also used for
* screen rotation animation so that there is a parent layer to put the animation leash.
*/
SurfaceControl getWindowingLayer() {
return mDisplayAreaPolicy.getWindowingArea().mSurfaceControl;
}
可以看出这里调用的是DisplayAreaPolicy的getWindowingArea方法,终于和我们前面讲解的Feature部分内容链接上了。
frameworks/base/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@Override
public DisplayArea<? extends WindowContainer> getWindowingArea() {
if (mRoot.mFeatures.isEmpty()) {
throw new IllegalStateException("There must be at least one feature.");
}
//这里会获取定顶部的Feature
final Feature feature = mRoot.mFeatures.get(0);
//会判断是否可以被成为WindowLayer
if (canBeWindowingLayer(feature.mId)) {
//如果可以成为WindowLayer,那么就返会Feature对应的WindowContainer
final List<DisplayArea<WindowContainer>> areas =
mRoot.mFeatureToDisplayAreas.get(feature);
if (areas.size() == 1) {
return areas.get(0);
}
}
}
再来看看canBeWindowingLayer方法
/** Returns {@code true} if the feature id can be used to put all window content. */
static boolean canBeWindowingLayer(int featureId) {
//明显FEATURE_WINDOWED_MAGNIFICATION是可以的
return featureId == FEATURE_WINDOWED_MAGNIFICATION || featureId == FEATURE_WINDOWING_LAYER;
}
这里mFeatures就是最开始config时候有添加进去的,最开始添加就是FEATURE_WINDOWED_MAGNIFICATION这个Feature。

到此就放大镜功能可以联系上了结构树创建时候设置Feature作用了,自然这里返回的WindowContainer就是:WindowedMagnification:0:31

全屏放大
切换成全屏放大后,点击放大镜按钮,点击Activity既可以实现对整体Activity进行放大

原理调研:
可以看出显示的Activity图层Layer的缩放参数变成的1.6倍

那么代码中是如何实现的缩放呢?
抓取一个堆栈看看:
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: setMatrix (tx=2310692409629 sc=OneHanded:17:17) dsdx=1.6 dtdx=0.0 dtdy=0.0 dsdy=1.6
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: java.lang.Throwable
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.SurfaceControlRegistry.checkCallStackDebugging(SurfaceControlRegistry.java:330)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.SurfaceControl$Transaction.setMatrix(SurfaceControl.java:3251)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.WindowContainer.applyMagnificationSpec(WindowContainer.java:2847)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.WindowContainer.applyMagnificationSpec(WindowContainer.java:2854)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.WindowContainer.applyMagnificationSpec(WindowContainer.java:2854)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.DisplayContent.applyMagnificationSpec(DisplayContent.java:5459)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.WindowManagerService.applyMagnificationSpecLocked(WindowManagerService.java:8915)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.AccessibilityController$DisplayMagnifier.setMagnificationSpec(AccessibilityController.java:697)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.AccessibilityController.setMagnificationSpec(AccessibilityController.java:283)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.wm.WindowManagerService$LocalService.setMagnificationSpec(WindowManagerService.java:7887)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.accessibility.magnification.FullScreenMagnificationController$SpecAnimationBridge.setMagnificationSpecLocked(FullScreenMagnificationController.java:2006)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.accessibility.magnification.FullScreenMagnificationController$SpecAnimationBridge.onAnimationUpdate(FullScreenMagnificationController.java:2031)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.Animator$AnimatorCaller.lambda$static$4(Animator.java:855)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.Animator$AnimatorCaller$$ExternalSyntheticLambda6.call(D8$$SyntheticClass:0)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.Animator.callOnList(Animator.java:666)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1645)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1405)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1563)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:344)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.AnimationHandler.-$$Nest$mdoAnimationFrame(Unknown Source:0)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:87)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1404)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1415)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.Choreographer.doCallbacks(Choreographer.java:1015)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.Choreographer.doFrame(Choreographer.java:941)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1389)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.os.Handler.handleCallback(Handler.java:959)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.os.Handler.dispatchMessage(Handler.java:100)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.os.Looper.loopOnce(Looper.java:232)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at android.os.Looper.loop(Looper.java:317)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.SystemServer.run(SystemServer.java:973)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.server.SystemServer.main(SystemServer.java:657)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at java.lang.reflect.Method.invoke(Native Method)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
07-30 15:48:55.978 538 538 E SurfaceControlRegistry: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:864)
找到核心代码如下:
frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void applyMagnificationSpec(Transaction t, MagnificationSpec spec) {
if (shouldMagnify()) {//需要满足shouldMagnify条件才可以进入
t.setMatrix(mSurfaceControl, spec.scale, 0, 0, spec.scale)
.setPosition(mSurfaceControl, spec.offsetX + mLastSurfacePosition.x,
spec.offsetY + mLastSurfacePosition.y);
mLastMagnificationSpec = spec;
} else {
clearMagnificationSpec(t);
for (int i = 0; i < mChildren.size(); i++) {
mChildren.get(i).applyMagnificationSpec(t, spec);
}
}
}
那么接下来看看shouldMagnify的判断:
frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
/**
* @return Whether this WindowContainer should be magnified by the accessibility magnifier.
*/
boolean shouldMagnify() {
if (mSurfaceControl == null) {
return false;
}
for (int i = 0; i < mChildren.size(); i++) {
if (!mChildren.get(i).shouldMagnify()) {//可以看出主要是回去遍历判断child的shouldMagnify
return false;
}
}
//如果所有child都是可以shouldMagnify为true,那么就返回true,只要一个不可以就返回false
return true;
}
那child又是判断的shouldMagnify呢?这里就需要看shouldMagnify的重写,发现只有WindowState才有对shouldMagnify的重写
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
@Override
boolean shouldMagnify() {
//这里会排除以下几种类型窗口,是不可以被缩放的,所以这些窗口就会返回false。
if (mAttrs.type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
|| mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG
|| mAttrs.type == TYPE_MAGNIFICATION_OVERLAY
|| mAttrs.type == TYPE_NAVIGATION_BAR
// It's tempting to wonder: Have we forgotten the rounded corners overlay?
// worry not: it's a fake TYPE_NAVIGATION_BAR_PANEL
|| mAttrs.type == TYPE_NAVIGATION_BAR_PANEL) {
return false;
}
//如果窗口设定了PRIVATE_FLAG_NOT_MAGNIFIABLE,那也不可以被缩放
if ((mAttrs.privateFlags & PRIVATE_FLAG_NOT_MAGNIFIABLE) != 0) {
return false;
}
return true;
}
注意只有WindowState才会有具体业务判断返回,否则都是返回true。
相比局部放大,明显全屏放大明显逻辑简单一些,本质就是排除一些不可以放大窗口,然后对可以放大窗口进行scale既可以。
更多framework实战干货,请关注下面“千里马学框架”

1643

被折叠的 条评论
为什么被折叠?



