Android 12系统源码_系统壁纸(二)动态壁纸的设置流程

在Android中,壁纸分为静态与动态两种。静态壁纸是一张图片,而动态壁纸则以动画为表现形式,或者可以对用户的操作作出反应。这两种形式看似差异很大,其实二者的本质是统一的。它们都以一个Service的形式运行在系统后台,并在一个类型为TYPE_WALLPAPER的窗口上绘制内容。进一步讲,静态壁纸是一种特殊的动态壁纸,它仅在窗口上渲染一张图片,并且不会对用户的操作作出反应。

一、 初识Android壁纸

在Android中,壁纸分为静态与动态两种。静态壁纸是一张图片,而动态壁纸则以动画为表现形式,或者可以对用户的操作作出反应。这两种形式看似差异很大,其实二者的本质是统一的。它们都以一个Service的形式运行在系统后台,并在一个类型为TYPE_WALLPAPER的窗口上绘制内容。进一步讲,静态壁纸是一种特殊的动态壁纸,它仅在窗口上渲染一张图片,并且不会对用户的操作作出反应。因此本章将首先通过动态壁纸的实现讨论Android壁纸的实现与管理原理,然后在对静态壁纸的实现做介绍。

Android壁纸的实现与管理分为三个层次:

1、**WallpaperService和Engine(壁纸的实现原理):**同SystemUI一样,壁纸运行在一个Android服务之中,这个服务的名字叫做WallpaperService。当用户选择了一个壁纸之后,此壁纸所对应的WallpaperService便会启动并开始进行壁纸的绘制工作,因此继承并定制WallpaperService是开发者进行壁纸开发的第一步。Engine是WallpaperService中的一个内部类,实现了壁纸窗口的创建以及Surface的维护工作。另外,Engine提供了可供子类重写的一系列回调,用于通知壁纸开发者关于壁纸的生命周期、Surface状态的变化以及对用户的输入事件进行响应。可以说,Engine类是壁纸实现的核心所在。壁纸开发者需要继承Engine类,并重写其提供的回调以完成壁纸的开发。这一层次的内容主要体现了壁纸的实现原理。

2、**WallpaperManagerService(对壁纸的管理方式):**这个系统服务用于管理壁纸的运行与切换,并通过WallpaperManager类向外界提供操作壁纸的接口。当通过WallpaperManagaer的接口进行壁纸的切换时,WallpaperManagerService会取消当前壁纸的WallpaperService的绑定,并启动新壁纸的WallpaperService。另外,Engine类进行窗口创建时所使用的窗口令牌也是由WallpaperManagerService提供的。这一层次主要体现了Android对壁纸的管理方式。

3、**WindowManagerService(对壁纸窗口的管理):**用于计算壁纸窗口的Z序、可见性以及为壁纸应用窗口动画。壁纸窗口(TYPE_WALLPAPER)的Z序计算不同于其他类型的窗口。其他窗口依照其类型会有固定的mBaseLayer以及mSubLayer,并结合它们所属的Activity的顺序或创建顺序进行Z序的计算,因此这些窗口的Z序相对固定。而壁纸窗口则不然,它的Z序会根据FLAG_SHOW_WALLPAPER标记在其它窗口的LayoutParams.flags中的存在情况而不断地被调整。这一层次主要体现了Android对壁纸窗口的管理方式。

二、动态壁纸的设置流程

1、通过调用WallpaperManager的setWallpaperComponent方法可以帮我们开启自定义动态壁纸。

frameworks/base/core/java/android/app/WallpaperManager.java

public class WallpaperManager {

    @SystemApi
    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
    public boolean setWallpaperComponent(ComponentName name) {
        return setWallpaperComponent(name, mContext.getUserId());
    }

    @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT)
    @UnsupportedAppUsage
    public boolean setWallpaperComponent(ComponentName name, int userId) {
        if (sGlobals.mService == null) {
            Log.w(TAG, "WallpaperService not running");
            throw new RuntimeException(new DeadSystemException());
        }
        try {
        	//通过binder调用WallpaperManagerService的setWallpaperComponentChecked方法
            sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName(),
                    userId);
            return true;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    private static class Globals extends IWallpaperManagerCallback.Stub {
     	private final IWallpaperManager mService;//WallpaperManagerService的binder代理对象
    }
}

类型为Globals的sGlobals对象,内部属性mService是一个代理者,setWallpaperComponent最终会调用WallpaperManagerService的setWallpaperComponentChecked方法。

2、WallpaperManagerService的setWallpaperComponentChecked方法如下所示。

frameworks/base/core/java/android/app/WallpaperManager.java

public class WallpaperManagerService extends IWallpaperManager.Stub
        implements IWallpaperManagerService {
        
    @Override
    public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
            int userId) {
        //权限验证
        if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
            setWallpaperComponent(name, userId);
        }
    }
    
    //设置动态壁纸
    private void setWallpaperComponent(ComponentName name, int userId) {
        userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
        //权限检测
        checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);

        int which = FLAG_SYSTEM;
        boolean shouldNotifyColors = false;
        WallpaperData wallpaper;//壁纸数据

        synchronized (mLock) {
            Slog.v(TAG, "setWallpaperComponent name=" + name);
            wallpaper = mWallpaperMap.get(userId);
            if (wallpaper == null) {
                throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
            }
            final long ident = Binder.clearCallingIdentity();

            // Live wallpapers can't be specified for keyguard.  If we're using a static
            // system+lock image currently, migrate the system wallpaper to be a lock-only
            // image as part of making a different live component active as the system
            // wallpaper.
            if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
                if (mLockWallpaperMap.get(userId) == null) {
                    // We're using the static imagery and there is no lock-specific image in place,
                    // therefore it's a shared system+lock image that we need to migrate.
                    Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
                            + "updating system wallpaper");
                    migrateSystemToLockWallpaperLocked(userId);
                }
            }

            // New live wallpaper is also a lock wallpaper if nothing is set
            if (mLockWallpaperMap.get(userId) == null) {
                which |= FLAG_LOCK;
            }

            try {
                wallpaper.imageWallpaperPending = false;
                boolean same = changingToSame(name, wallpaper);
                //启动新壁纸的WallpaperService
                if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
                    if (!same) {
                        wallpaper.primaryColors = null;
                    } else {
                        if (wallpaper.connection != null) {
                            wallpaper.connection.forEachDisplayConnector(displayConnector -> {
                                try {
                                    if (displayConnector.mEngine != null) {
                                        displayConnector.mEngine.dispatchWallpaperCommand(
                                                COMMAND_REAPPLY, 0, 0, 0, null);
                                    }
                                } catch (RemoteException e) {
                                    Slog.w(TAG, "Error sending apply message to wallpaper", e);
                                }
                            });
                        }
                    }
                    wallpaper.wallpaperId = makeWallpaperIdLocked();
                    notifyCallbacksLocked(wallpaper);
                    shouldNotifyColors = true;
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        if (shouldNotifyColors) {
            notifyWallpaperColorsChanged(wallpaper, which);
            notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
        }
    }
}

参考文章:https://www.kancloud.cn/wizardforcel/deepin-android-vol3/122360
https://www.freesion.com/article/6656482862/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值