1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wallpaper;
18 
19 import static android.app.WallpaperManager.FLAG_LOCK;
20 
21 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
22 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP;
23 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_CROP;
24 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG;
25 import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
26 
27 import android.app.IWallpaperManagerCallback;
28 import android.app.WallpaperColors;
29 import android.app.WallpaperManager.SetWallpaperFlags;
30 import android.content.ComponentName;
31 import android.graphics.Rect;
32 import android.os.RemoteCallbackList;
33 import android.util.SparseArray;
34 
35 import java.io.File;
36 
37 /**
38  * The main wallpaper data model, used internally by the {@link WallpaperManagerService}. <br>
39  * An instance of this class contains all the information about a wallpaper.
40  */
41 class WallpaperData {
42 
43     final int userId;
44 
45     /**
46      * True while the client is writing a new wallpaper
47      */
48     boolean imageWallpaperPending;
49 
50     /**
51      * Which wallpaper is set. Flag values are from {@link SetWallpaperFlags}.
52      */
53     int mWhich;
54 
55     /**
56      * True if the system wallpaper was also used for lock screen before this wallpaper was set.
57      * This is needed to update state after setting the wallpaper.
58      */
59     boolean mSystemWasBoth;
60 
61     /**
62      * Callback once the set + crop is finished
63      */
64     IWallpaperManagerCallback setComplete;
65 
66     /**
67      * Is the OS allowed to back up this wallpaper imagery?
68      */
69     boolean allowBackup;
70 
71     /**
72      * Resource name if using a picture from the wallpaper gallery
73      */
74     String name = "";
75 
76     /**
77      * The component name of the currently set live wallpaper.
78      */
79     ComponentName wallpaperComponent;
80 
81     /**
82      * The component name of the wallpaper that should be set next.
83      */
84     ComponentName nextWallpaperComponent;
85 
86     /**
87      * The ID of this wallpaper
88      */
89     int wallpaperId;
90 
91     /**
92      * Primary colors histogram
93      */
94     WallpaperColors primaryColors;
95 
96     /**
97      * If the wallpaper was set from a foreground app (instead of from a background service).
98      */
99     public boolean fromForegroundApp;
100 
101     WallpaperManagerService.WallpaperConnection connection;
102     long lastDiedTime;
103     boolean wallpaperUpdating;
104     WallpaperManagerService.WallpaperObserver wallpaperObserver;
105 
106     /**
107      * The dim amount to be applied to the wallpaper.
108      */
109     float mWallpaperDimAmount = 0.0f;
110 
111     /**
112      * A map to keep track of the dimming set by different applications. The key is the calling
113      * UID and the value is the dim amount.
114      */
115     SparseArray<Float> mUidToDimAmount = new SparseArray<>();
116 
117     /**
118      * Whether we need to extract the wallpaper colors again to calculate the dark hints
119      * after dimming is applied.
120      */
121     boolean mIsColorExtractedFromDim;
122 
123     /**
124      * List of callbacks registered they should each be notified when the wallpaper is changed.
125      */
126     RemoteCallbackList<IWallpaperManagerCallback> callbacks = new RemoteCallbackList<>();
127 
128     /**
129      * The crop hint supplied for displaying a subset of the source image
130      */
131     final Rect cropHint = new Rect(0, 0, 0, 0);
132 
133     // map of which -> File
134     private final SparseArray<File> mWallpaperFiles = new SparseArray<>();
135     private final SparseArray<File> mCropFiles = new SparseArray<>();
136 
WallpaperData(int userId, @SetWallpaperFlags int wallpaperType)137     WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) {
138         this.userId = userId;
139         this.mWhich = wallpaperType;
140     }
141 
142     /**
143      * Copies the essential properties of a WallpaperData to a new instance, including the id and
144      * WallpaperConnection, usually in preparation for migrating a system+lock wallpaper to system-
145      * or lock-only. NB: the source object retains the pointer to the connection and it is the
146      * caller's responsibility to set this to null or otherwise be sure the connection is not shared
147      * between WallpaperData instances.
148      *
149      * @param source WallpaperData object to copy
150      */
WallpaperData(WallpaperData source)151     WallpaperData(WallpaperData source) {
152         this.userId = source.userId;
153         this.wallpaperComponent = source.wallpaperComponent;
154         this.mWhich = source.mWhich;
155         this.wallpaperId = source.wallpaperId;
156         this.cropHint.set(source.cropHint);
157         this.allowBackup = source.allowBackup;
158         this.primaryColors = source.primaryColors;
159         this.mWallpaperDimAmount = source.mWallpaperDimAmount;
160         this.connection = source.connection;
161         if (this.connection != null) {
162             this.connection.mWallpaper = this;
163         }
164     }
165 
getWallpaperFile()166     File getWallpaperFile() {
167         String fileName = mWhich == FLAG_LOCK ? WALLPAPER_LOCK_ORIG : WALLPAPER;
168         return getFile(mWallpaperFiles, fileName);
169     }
170 
getCropFile()171     File getCropFile() {
172         String fileName = mWhich == FLAG_LOCK ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP;
173         return getFile(mCropFiles, fileName);
174     }
175 
getFile(SparseArray<File> map, String fileName)176     private File getFile(SparseArray<File> map, String fileName) {
177         File result = map.get(mWhich);
178         if (result == null) {
179             result = new File(getWallpaperDir(userId), fileName);
180             map.put(userId, result);
181         }
182         return result;
183     }
184 
185     @Override
toString()186     public String toString() {
187         StringBuilder out = new StringBuilder(defaultString(this));
188         out.append(", id: ");
189         out.append(wallpaperId);
190         out.append(", which: ");
191         out.append(mWhich);
192         out.append(", file mod: ");
193         out.append(getWallpaperFile() != null ? getWallpaperFile().lastModified() : "null");
194         if (connection == null) {
195             out.append(", no connection");
196         } else {
197             out.append(", info: ");
198             out.append(connection.mInfo);
199             out.append(", engine(s):");
200             connection.forEachDisplayConnector(connector -> {
201                 if (connector.mEngine != null) {
202                     out.append(" ");
203                     out.append(defaultString(connector.mEngine));
204                 } else {
205                     out.append(" null");
206                 }
207             });
208         }
209         return out.toString();
210     }
211 
defaultString(Object o)212     private static String defaultString(Object o) {
213         return o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode());
214     }
215 
216     // Called during initialization of a given user's wallpaper bookkeeping
cropExists()217     boolean cropExists() {
218         return getCropFile().exists();
219     }
220 
sourceExists()221     boolean sourceExists() {
222         return getWallpaperFile().exists();
223     }
224 }
225