Android 12中系统Wallpaper详解1--锁屏透看壁纸和桌面透看壁纸的切换
那么其实我们可以猜测是不是锁屏window会去动态改变自己的FLAG_SHOW_WALLPAPER属性,在有桌面显示时候锁屏的window实际是没有这个属性,在锁屏状态下是有这个属性。先看桌面情况下壁纸,这个情况应该属于我们最为熟悉的,那么就不用多说,大概就是因为桌面Activity的配置主题xml设置一个类似showallpaper的属性既可以,就可以让桌面后面显示壁纸了。这个窗口在系统中有专门
1 桌面壁纸
先看桌面情况下壁纸,这个情况应该属于我们最为熟悉的,那么就不用多说,大概就是因为桌面Activity的配置主题xml设置一个类似showallpaper的属性既可以,就可以让桌面后面显示壁纸了
2 aosp编译后版本锁屏后点亮屏幕也可以看到桌面壁纸(注意这里还不是专门锁屏壁纸)
大家发现锁屏点亮后确实看到的壁纸和桌面的壁纸一模一样
3 疑惑
这里是不是大家就开始比较疑惑了,请问普通Activity是通过属性配置的,而且壁纸窗口又是在wms属于最底层的状态,他依附于桌面这个可以理解,但是为啥锁屏时候又可以看到壁纸呢?锁屏理论上也只是一个window盖在最顶层,理论即使这个锁屏window透明,那么透看到的也是有桌面Activity的情况,但现实情况是我们只看到了壁纸,并没有看到桌面
针对以上的疑惑,那接下来我们就需要去解答这个疑惑。
首先我们知道壁纸属于系统中一个特殊窗口,一直处于系统最底层。这个窗口在系统中有专门类进行他的显示情况,那就我们的WallpaperController类
这个WallpaperController.java中有log打印,但需要我们将对应标志位给设置一下:
if (DEBUG_WALLPAPER) {
Slog.v(TAG, "Wallpaper visibility: " + visible + " at display "
+ mDisplayContent.getDisplayId());
}
这里我们把DEBUG_WALLPAPER就可以把log打开了
10-23 22:55:41.115 5313 6475 V WindowManager: Win Window{60c77f1 u0 ScreenDecorOverlayBottom}: isOnScreen=true mDrawState=4
10-23 22:55:41.115 5313 6475 V WindowManager: Win Window{df0a78b u0 ScreenDecorOverlay}: isOnScreen=true mDrawState=4
10-23 22:55:41.115 5313 6475 V WindowManager: Win Window{b7a35a u0 NavigationBar0}: isOnScreen=true mDrawState=4
10-23 22:55:41.115 5313 6475 V WindowManager: Win Window{3cd76e8 u0 NotificationShade}: isOnScreen=true mDrawState=4
10-23 22:55:41.115 5313 6475 V WindowManager: Found wallpaper target: Window{3cd76e8 u0 NotificationShade}
10-23 22:55:41.115 5313 6475 V WindowManager: New wallpaper target: Window{3cd76e8 u0 NotificationShade} prevTarget: null
10-23 22:55:41.116 5313 6475 V WindowManager: Report new wp offset Window{803c2b8 u0 com.android.systemui.ImageWallpaper} x=0.0 y=0.5 zoom=0.0
10-23 22:55:41.116 5313 6475 V WindowManager: Wallpaper visibility: true at display 0
10-23 22:55:41.116 5313 6475 D WindowManager: Wallpaper token android.os.Binder@3a6eda2 visible=true
10-23 22:55:41.118 5313 6475 D WindowManager: New wallpaper: target=Window{3cd76e8 u0 NotificationShade} prev=null
10-23 22:55:41.163 5313 5313 D WindowManager: powerPress: eventTime=118823847 interactive=true count=0 beganFromNonInteractive=true mShortPressOnPowerBehavior=1
打开后我们点亮锁屏和在桌面锁屏发现都有类似以下打印
WindowManager: Found wallpaper target: Window{3cd76e8 u0 NotificationShade}
看名字大家大概就知道这个log是在寻找一个wallpaper target:,而且找到的是NotificationShade即锁屏窗口
前面疑惑中就写到正常应该是桌面
10-24 00:18:50.543 10429 10450 V WindowManager: Found wallpaper target: Window{8d79f3 u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}
这日志其实就可以给我们非常重要线索,可以找出对应代码在哪
private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
if ((w.mAttrs.type == TYPE_WALLPAPER)) {
if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) {
mFindResults.setTopWallpaper(w);
mFindResults.resetTopWallpaper = false;
}
return false;
}
mFindResults.resetTopWallpaper = true;
if (mService.mAtmService.getTransitionController().getTransitionPlayer() == null) {
if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
&& !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
// If this window's app token is hidden and not animating, it is of no interest.
if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
return false;
}
} else {
if (w.mActivityRecord != null && !w.mActivityRecord.isVisibleRequested()) {
// An activity that is not going to remain visible shouldn't be the target.
return false;
}
}
if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
+ " mDrawState=" + w.mWinAnimator.mDrawState + " w.mWillReplaceWindow = " + w.mWillReplaceWindow);
if (w.toString().contains("NotificationShade")) {
Slog.v(TAG, "1111 Win " + w + ": isOnScreen=" + w.isOnScreen()
+ " mDrawState=" + w.mWinAnimator.mDrawState + " w.mWillReplaceWindow = " + w.mWillReplaceWindow);
}
if (w.mWillReplaceWindow && mWallpaperTarget == null
&& !mFindResults.useTopWallpaperAsTarget) {
// When we are replacing a window and there was wallpaper before replacement, we want to
// keep the window until the new windows fully appear and can determine the visibility,
// to avoid flickering.
mFindResults.setUseTopWallpaperAsTarget(true);
}
final WindowContainer animatingContainer = w.mActivityRecord != null
? w.mActivityRecord.getAnimatingContainer() : null;
final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
&& animatingContainer.isAnimating(TRANSITION | PARENTS)
&& AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit)
&& (animatingContainer.mTransitFlags
& TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
boolean needsShowWhenLockedWallpaper = false;
if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
&& mService.mPolicy.isKeyguardLocked()
&& (mService.mPolicy.isKeyguardOccluded()
|| mService.mPolicy.isKeyguardUnoccluding())) {
// The lowest show when locked window decides whether we need to put the wallpaper
// behind.
needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
|| (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
}
if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
// Keep the wallpaper during Keyguard exit but also when it's needed for a
// non-fullscreen show when locked activity.
mFindResults.setUseTopWallpaperAsTarget(true);
}
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
final boolean animationWallpaper = animatingContainer != null
&& animatingContainer.getAnimation() != null
&& animatingContainer.getAnimation().getShowWallpaper();
final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper;
final boolean isRecentsTransitionTarget = (recentsAnimationController != null
&& recentsAnimationController.isWallpaperVisible(w));
if (isRecentsTransitionTarget) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
mFindResults.setWallpaperTarget(w);
return true;
} else if (hasWallpaper && w.isOnScreen()
&& (mWallpaperTarget == w || w.isDrawFinishedLw())) {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
mFindResults.setWallpaperTarget(w);
if (w == mWallpaperTarget && w.isAnimating(TRANSITION | PARENTS)) {
// The current wallpaper target is animating, so we'll look behind it for
// another possible target and figure out what is going on later.
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Win " + w + ": token animating, looking behind.");
}
// Found a target! End search.
return true;
}
return false;
};
上面最关键判断代码:
if (hasWallpaper && w.isOnScreen()
&& (mWallpaperTarget == w || w.isDrawFinishedLw()))
这里的 hasWallpaper非常关键
final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper;
主要调用是WindowState的方法
boolean hasWallpaper() {
return (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
|| (mActivityRecord != null && mActivityRecord.hasWallpaperBackgroudForLetterbox());
}
这里其实也就是判断window中是否有FLAG_SHOW_WALLPAPER属性,而且经过额外加log打印发现hasWallpaper值变化在锁屏window解锁前后
那么其实我们可以猜测是不是锁屏window会去动态改变自己的FLAG_SHOW_WALLPAPER属性,在有桌面显示时候锁屏的window实际是没有这个属性,在锁屏状态下是有这个属性。根据猜想去systemui代码中grep相关FLAG_SHOW_WALLPAPER关键字
果然发现有如下:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
private void applyKeyguardFlags(State state) {
final boolean scrimsOccludingWallpaper =
state.mScrimsVisibility == ScrimController.OPAQUE || state.mLightRevealScrimOpaque;
final boolean keyguardOrAod = state.mKeyguardShowing
|| (state.mDozing && mDozeParameters.getAlwaysOn());
if ((keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper)
|| mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
// Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a
// solid backdrop or scrim. Also, show it if we are currently animating between the
// keyguard and the surface behind the keyguard - we want to use the wallpaper as a
// backdrop for this animation.
mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
} else {
mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
}
这里其实就是代表有锁屏时候需要有 mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
锁屏退出时清除锁屏的FLAG_SHOW_WALLPAPER
mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)