Android 12 system source code_system wallpaper (2) Live wallpaper setting process

In Android, wallpapers are divided into static and dynamic. A static wallpaper is an image, while a live wallpaper is animated or responds to user actions. These two forms seem to be very different, but in fact the essence of the two is unified. They all run in the background of the system in the form of a Service, and draw content on a window of type TYPE_WALLPAPER. Furthermore, a static wallpaper is a special dynamic wallpaper that only renders a picture on the window and does not respond to user operations.

1. Getting to know Android wallpapers for the first time

In Android, wallpapers are divided into static and dynamic. A static wallpaper is an image, while a live wallpaper is animated or responds to user actions. These two forms seem to be very different, but in fact the essence of the two is unified. They all run in the background of the system in the form of a Service, and draw content on a window of type TYPE_WALLPAPER. Furthermore, a static wallpaper is a special dynamic wallpaper that only renders a picture on the window and does not respond to user operations. Therefore, this chapter will first discuss the implementation and management principles of Android wallpapers through the implementation of dynamic wallpapers, and then introduce the implementation of static wallpapers.

The implementation and management of Android wallpapers are divided into three levels:

1. **WallpaperService and Engine (the realization principle of wallpaper): **Same as SystemUI, wallpaper runs in an Android service, and the name of this service is WallpaperService. When the user selects a wallpaper, the WallpaperService corresponding to the wallpaper will start and start drawing the wallpaper. Therefore, inheriting and customizing the WallpaperService is the first step for developers to develop wallpapers. Engine is an internal class in WallpaperService, which implements the creation of wallpaper windows and the maintenance of Surface. In addition, Engine provides a series of callbacks that can be rewritten by subclasses to notify wallpaper developers about the life cycle of wallpapers, changes in Surface status, and respond to user input events. It can be said that the Engine class is the core of wallpaper implementation. Wallpaper developers need to inherit the Engine class and rewrite the callbacks provided by it to complete the development of wallpapers. The content at this level mainly reflects the realization principle of the wallpaper.

2. **WallpaperManagerService (the way to manage wallpapers): **This system service is used to manage the running and switching of wallpapers, and provides an interface for operating wallpapers to the outside world through the WallpaperManager class. When the wallpaper is switched through the interface of WallpaperManager, WallpaperManagerService will cancel the binding of the WallpaperService of the current wallpaper and start the WallpaperService of the new wallpaper. In addition, the window token used by the Engine class for window creation is also provided by WallpaperManagerService. This level mainly reflects the way Android manages wallpapers.

3. **WindowManagerService (management of wallpaper windows): **Used to calculate the Z order and visibility of the wallpaper window and to animate the wallpaper application window. The Z-order calculation of the wallpaper window (TYPE_WALLPAPER) is different from other types of windows. Other windows will have fixed mBaseLayer and mSubLayer according to their types, and calculate the Z order in combination with the order or creation order of the activities to which they belong, so the Z order of these windows is relatively fixed. The wallpaper window is not the case, its Z order will be constantly adjusted according to the existence of the FLAG_SHOW_WALLPAPER flag in the LayoutParams.flags of other windows. This level mainly reflects the way Android manages the wallpaper window.

2. The setting process of dynamic wallpaper

1. By calling the setWallpaperComponent method of WallpaperManager, we can help us open a custom live wallpaper.

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代理对象
    }
}

The sGlobals object of type Globals, the internal attribute mService is a proxy, and setWallpaperComponent will eventually call the setWallpaperComponentChecked method of WallpaperManagerService.

2. The setWallpaperComponentChecked method of WallpaperManagerService is as follows.

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);
        }
    }
}

Reference article: https://www.kancloud.cn/wizardforcel/deepin-android-vol3/122360
https://www.freesion.com/article/6656482862/

Guess you like

Origin blog.csdn.net/abc6368765/article/details/129448586