Android 12中系统Wallpaper详解1--锁屏透看壁纸和桌面透看壁纸的切换

【问题分析】WMS无焦点窗口的ANR问题【Android 14】 Monkey跑出的Launcher ANR,场景为在Launcher界面,下拉状态栏,然后点击Notification,连续启动多个Activity,这些Activity均是启动后又快速销毁,导致的后续无焦点窗口问题。 阅读详情
AI摘要

本文探讨了Android系统中壁纸如何在桌面和锁屏状态下显示的问题。通过分析WallpaperController类的日志,揭示了壁纸在不同场景下显示的原理。关键在于锁屏窗口动态调整FLAG_SHOW_WALLPAPER属性,当锁屏时该属性被设置,使得壁纸在锁屏状态下可见。这一过程涉及到WindowManager服务和窗口状态的管理。

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;

Android壁纸机制(Android Q与老版本对比) 一、什么是Android壁纸? Android中,壁纸分为动态壁纸和静态壁纸两种。静态壁纸是一张图片,动态壁纸是以动画为表现形式,有的可以对用户的操作作出反应。二者表现形式看似差异很大,但是二者的本质是统一的: 它们都以一个Service的形式运行在系统后台,并在一个类型为TYPE_WALLPAPER的窗口上绘制内容。 实质上,静态壁纸是一种特殊的动态壁纸。 Android壁纸管理的三个层次: ... 阅读详情

相关推荐

Android14 系统Wallpaper详解 锁屏透看壁纸和桌面透看壁纸的切换

桌面Activity的配置主题xml设置一个类似showallpaper的属性既可以,就可以让桌面后面显示壁纸了。

Red风信子的博客 1305

Android T wallpaper相关流程

什么是壁纸? 壁纸即是一个壁纸服务,每换一张壁纸 ,就是将该图片写入壁纸文件,再启动一个壁纸服务读取该壁纸文件显示出来的过程。

yimelancholy的博客 2748

Android14 系统Wallpaper详解 壁纸显示说明

壁纸主要分为两类,锁屏壁纸和桌面壁纸。

Red风信子的博客 1892

Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)

本文查看SystemUI的layout文件,说明了SystemUI的window划分和布局划分,并将其对应到具体的UI视图中

安仔的博客 7428

安卓手机如何无线传输Steam Wallpaper Engine动态壁纸?保姆级教程来了

本文提供安卓手机无线传输Steam Wallpaper Engine动态壁纸的完整教程,涵盖从环境配置到高级技巧的全流程。通过局域网连接,用户可轻松将电脑端的精美动态壁纸传输至手机,实现个性化桌面体验。教程详细解答了连接故障、壁纸优化等常见问题,是Wallpaper Engine用户的实用指南。

k8l9m0n的博客 954

Android多屏壁纸适配:从WallpaperManager到Display机制全解析

Android系统的壁纸机制是桌面与系统UI交互的重要环节,尤其在多屏设备(如平板、车机、折叠屏)普及的今天,壁纸的显示与适配成为开发者不可回避的挑战。系统通过WallpaperManager及底层WallpaperManagerService管理壁纸的创建与绑定,而WallpaperService引擎负责实际渲染,配合Wallpaper Offsets实现分页滚动效果。理解这些概念与原理,能帮助开发者应对副屏无壁纸、拉伸变形、折叠屏展开异常等典型问题。在Launcher定制、动态壁纸开发及多Display

weixin_29189987的博客 174

android壁纸显示逻辑

所有文章仅限自己备忘,并无他用 壁纸主要分为两类,锁屏壁纸和桌面壁纸 一,壁纸服务的启动 壁纸服务WallpaperManagerService中,有一个内部类LifeCycle继承自SystemService,SystemServer在启动系统服务的时候,会创建LifeCycle对象并进行创建的相关逻辑,LifeCycle在onStart方法中会发布Service(publishBinderSe...

weixin_40273792的博客 1259

Android 动态壁纸服务的添加和实现

本文介绍了如何向 Android 系统中的 WallpaperPicker2 应用中添加动态壁纸服务。通过创建壁纸服务类、注册壁纸服务以及处理壁纸选项的点击事件,我们可以实现在 WallpaperPicker2 中添加动态壁纸的功能。本文将介绍如何向 Android 中的 WallpaperPicker2 应用添加动态壁纸服务,并提供相应的源代码。WallpaperPicker2 是 Android 系统中负责壁纸选择功能的应用,可以让用户从安装的壁纸应用中选择并设置壁纸。步骤 1: 创建壁纸服务类。

CyberJolt的博客 997

android 3d壁纸源码,3D Wallpaper Parallax app下载-3D Wallpaper Parallax(3D视差壁纸)下载v1.3安卓版-西西软件下载...

3D Wallpaper Parallax(3D视差壁纸)app是一款非常不错的3D视觉效果特效壁纸软件,软件内有大量精美壁纸免费使用,其中主要特色就是3D视差效果壁纸,如下图屏幕碎裂壁纸,看起来非常立体逼真,还有超多不同风格的壁纸等你使用,需要的可以下载3D Wallpaper Parallax(3D视差壁纸)app使用!软件简介3d视觉壁纸让您的主屏幕和锁屏产生令人惊叹的效果。一共六张高品质的...

weixin_42617406的博客 8803

Android 11.0 禁止系统桌面壁纸缩放功能实现

在11.0的系统rom定制化开发中,在使用应用替换桌面壁纸的时候,发现如果壁纸和系统分辨率大小不一致的情况,会出现 缩放壁纸的情况,所以可以分析下相关的替换壁纸的过程,来实现禁用系统桌面壁纸缩放功能

安卓兼职framework和app工程师的博客 193

Android获取与设置桌面壁纸实战:getWallpaper与setImageDrawable详解

该方法属于实例方法,无需传入任何参数,调用后返回一个Drawable类型的对象。需要注意的是:返回类型为Drawable:这意味着无论原始壁纸是PNG、JPEG还是动态壁纸(Live Wallpaper),最终都会被封装成某种形式的可绘制资源。可能返回 null:在某些极端情况下(如系统未初始化壁纸服务、权限缺失或首次启动尚未设置壁纸),该方法可能返回null。不区分主屏/副屏壁纸。

weixin_42103128的博客 1655

探索艺术之美:Muzei Live Wallpaper——让安卓手机壁纸生动起来

探索艺术之美:Muzei Live Wallpaper——让安卓手机壁纸生动起来 1、项目介绍 想要让你的安卓手机屏幕充满艺术气息吗?那么,Muzei Live Wallpaper正是你需要的。这个创新的动态壁纸应用,每日会为你带来知名的艺术作品,让你的设备变成一个移动的博物馆。不仅如此,它还巧妙地将艺术品模糊化和淡化处理,确保你的图标和小部件始终清晰可见。 通过双击壁纸或者直接打开Muzei应...

gitblog_00008的博客 757

东方通TongWeb虚拟主机配置全流程:从创建到应用部署的保姆级教程

本文提供东方通TongWeb虚拟主机从创建、HTTP通道配置到应用部署的完整实战指南。重点解析虚拟主机的逻辑隔离价值、通道参数调优原理及企业级多应用部署架构,并涵盖常见报错排查与性能优化建议,旨在帮助运维和开发人员高效、稳定地完成应用系统部署。

oil88的博客 530

Android Rotating Image Wallpaper 自动切换壁纸

Rotating Image Wallpaper 有什么用不是很清楚,但是你直接长按桌面,live wallpapers进去后,就可以看到这个,点了没什么效果,就是让你去设置壁纸,而且壁纸也不能换,点设置了也没效果。 后来发现需要从被的app调用,才有效果。每天自动切换壁纸。 1.下载google wallpaper 2.选择Landscapes 3.选择Daily wallpaper 4. 然后一直点继续,最后就到了Rotating Image Wallpaper ...

Aaron121314的博客 1389

tesseract-ocr的字库学习步骤(训练自己的文库),关于ocr的对图片的解析,包括tesseract的安装(史上最全)

tesseract-ocr的字库学习步骤(训练自己的文库) 简介:在网上看了很多案列。都不是很完整。然后自己用了一天时间进行整理,第一次写文章,希望对大家有帮助。 一、安装tesseract 下载地址https://github.com/UB-Mannheim/tesseract/wiki 1.点击下面下载的这个进行运行(安装的时候有点慢) 2.点击next 3.I accept the terms of the License Agreement前的复选框打勾,点击Next。 4.Install f

HAC12的博客 2229

汽车电缆选型实战:基于ISO 19642-3~12的7类电缆电压/材料/场景对照表

本文详细解析了基于ISO 19642-3~12标准的7类汽车电缆选型实战,涵盖电压等级、导体材料和场景应用的对照表。通过全参数速查表和典型选型陷阱分析,帮助工程师快速掌握从低压信号线到高压动力电缆的选型逻辑,提升新能源汽车与智能驾驶技术的安全性和可靠性。

weixin_29043895的博客 366

Android中使用系统桌面背景作为应用背景,支持拖动

在Android应用开发中,使用系统桌面背景作为应用的背景,需要把应用的背景设置为透明背景,然后设置窗口的属性为FLAG_SHOW_WALLPAPER即可显示背景。修改AndroidManifest.xml文件里面activity属性:                           android:label="@string/app_name"                  andro

Yao.GUET 1万+

vue3 web项目引入高拍仪

高拍仪的引入步骤就两步,安装SDK,然后根据官网的api进行开发。根据自己需要的功能,请求对应的接口。

qq_42480170的博客 4116

安卓/iOS设备动态壁纸免费获取与高效设置全攻略

本文提供安卓和iOS设备动态壁纸的免费获取与设置全攻略。详细介绍了Wallpaper Engine等高质量免费资源来源,并分别给出了安卓和iOS系统的具体设置步骤与优化技巧,帮助用户轻松实现个性化手机桌面,同时兼顾续航与性能。

week9的博客 696

基于STM32、HAL库的W25Q01JVZEIQ TR FLASH存储器驱动应用程序设计

1Gb (128MB),分为512个可擦除块(block),每个块256KB。:块擦除约30-50ms,芯片擦除约30s。:标准SPI (支持1/2/4线模式)// 初始化CS引脚为高电平。// 擦除扇区(4KB)// 初始化Flash。/* 状态寄存器位 *//* 指令定义 *//* 超时定义 *//* 函数声明 */

corlin6688的博客 267

camera QXXX架构

This article introduces the QCX camera architecture for Qualcomm’s latest automotive chips including SA8650. It elaborates the layered camera stack under QNX, HGY and HQX systems, covering client applications, stream manager, CamX components and hardware d

qq_39257814的博客 4544

Android 12 内置系统默认动态壁纸(视频资源)实现

Android 动态壁纸视屏资源的方式的实现,以及内置到系统实现

u010351267的博客 3392

Java接入DeepSeek大模型:从零实现流式对话+多轮会话管理(完整项目实战)

emitter.completeWithError(new RuntimeException("连接DeepSeek服务超时"));private static final Set<String> BLACK_WORDS = Set.of("暴力", "色情", "政治敏感");emitter.onCompletion(() -> log.info("SSE连接完成"));emitter.onTimeout(() -> log.warn("SSE连接超时"));// 每个路由基础连接数。

wjianwei666的专栏 931

Android 显示系统live Wallpaper

在实现某些app时,有时需要显示系统的动态背景图片,参照以下步骤则可实现: 1.TestActivity 设置FLAG_SHOW_WALLPAPER 的作用是让系统背景显示在此应用的下层。 protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);

wymhhgg99的专栏 1368

QGC4.0.11界面修改

QGC4.0.11。

超维空间科技的博客 2466

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

上一篇: android 12 framework开发第53节-Activity的reLaunch及onConfigurationChanged android源码分析
下一篇: clearCallingIdentity与restoreCallingIdentity-千里马framework系统源码实战详解
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值