Android 12 システムソースコード_システム壁紙 (2) ライブ壁紙設定手順

Android では、壁紙は静的と動的に分けられます。静的な壁紙は画像ですが、ライブ壁紙はアニメーション化されるか、ユーザーのアクションに応答します。この 2 つの形式は大きく異なっているように見えますが、実際には 2 つの本質は統一されています。これらはすべてサービスの形式でシステムのバックグラウンドで実行され、TYPE_WALLPAPER タイプのウィンドウにコンテンツを描画します。さらに、静的壁紙は、ウィンドウ上に画像を表示するだけで、ユーザーの操作には応答しない特別な動的壁紙です。

1. Android の壁紙について初めて知る

Android では、壁紙は静的と動的に分けられます。静的な壁紙は画像ですが、ライブ壁紙はアニメーション化されるか、ユーザーのアクションに応答します。この 2 つの形式は大きく異なっているように見えますが、実際には 2 つの本質は統一されています。これらはすべてサービスの形式でシステムのバックグラウンドで実行され、TYPE_WALLPAPER タイプのウィンドウにコンテンツを描画します。さらに、静的壁紙は、ウィンドウ上に画像を表示するだけで、ユーザーの操作には応答しない特別な動的壁紙です。したがって、この章では、まず動的壁紙の実装を通じて Android 壁紙の実装と管理の原則について説明し、次に静的壁紙の実装について紹介します。

Android 壁紙の実装と管理は、次の 3 つのレベルに分かれています。

1. **WallpaperService と Engine (壁紙の実現原理): **SystemUI と同様に、壁紙は Android サービス内で動作し、このサービスの名前は、WallpaperService です。ユーザーが壁紙を選択すると、その壁紙に対応するWallpaperServiceが起動し、壁紙の描画が開始されるため、開発者はWallpaperServiceを継承してカスタマイズすることが壁紙開発の第一歩となります。Engine は、壁紙ウィンドウの作成と Surface のメンテナンスを実装する、WallpaperService の内部クラスです。さらに、Engine は、壁紙のライフ サイクル、Surface ステータスの変化を壁紙開発者に通知し、ユーザー入力イベントに応答するために、サブクラスによって書き換えることができる一連のコールバックを提供します。Engineクラスは壁紙実装の中核とも言えます。壁紙の開発者は、壁紙の開発を完了するには、Engine クラスを継承し、それが提供するコールバックを書き直す必要があります。このレベルのコンテンツは主に壁紙の実現原理を反映しています。

2. **WallpaperManagerService (壁紙の管理方法): **このシステム サービスは、壁紙の実行と切り替えを管理するために使用され、WallpaperManager クラスを通じて外部に壁紙を操作するためのインターフェイスを提供します。壁紙がWallpaperManagerのインターフェースを通じて切り替えられると、WallpaperManagerServiceは現在の壁紙のWallpaperServiceのバインドをキャンセルし、新しい壁紙のWallpaperServiceを開始します。さらに、Engine クラスがウィンドウ作成に使用するウィンドウ トークンも、WallpaperManagerService によって提供されます。このレベルは主に Android の壁紙の管理方法を反映します。

3. **WindowManagerService (壁紙ウィンドウの管理): **Z オーダーと壁紙ウィンドウの可視性を計算し、壁紙アプリケーション ウィンドウをアニメーション化するために使用されます。壁紙ウィンドウ (TYPE_WALLPAPER) の Z オーダーの計算は、他のタイプのウィンドウとは異なります。他のウィンドウは、タイプに応じて固定の mBaseLayer と mSubLayer を持ち、それらが属するアクティビティの順序または作成順序と組み合わせて Z オーダーを計算するため、これらのウィンドウの Z オーダーは比較的固定されます。壁紙ウィンドウはそうではありません。その Z オーダーは、他のウィンドウの LayoutParams.flags 内の FLAG_SHOW_WALLPAPER フラグの存在に従って常に調整されます。このレベルは主に Android が壁紙ウィンドウを管理する方法を反映します。

2.ダイナミック壁紙の設定手順

1.WallpaperManager の setWallpaperComponent メソッドを呼び出すと、カスタム ライブ壁紙を開くことができます。

フレームワーク/ベース/コア/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メソッドは以下のとおりです。

フレームワーク/ベース/コア/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/

おすすめ

転載: blog.csdn.net/abc6368765/article/details/129448586