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 import static android.app.WallpaperManager.ORIENTATION_UNKNOWN;
21 
22 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER;
23 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_CROP;
24 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_CROP;
25 import static com.android.server.wallpaper.WallpaperUtils.WALLPAPER_LOCK_ORIG;
26 import static com.android.server.wallpaper.WallpaperUtils.getWallpaperDir;
27 
28 import android.app.IWallpaperManagerCallback;
29 import android.app.WallpaperColors;
30 import android.app.WallpaperManager.ScreenOrientation;
31 import android.app.WallpaperManager.SetWallpaperFlags;
32 import android.content.ComponentName;
33 import android.graphics.Rect;
34 import android.os.RemoteCallbackList;
35 import android.util.SparseArray;
36 
37 import java.io.File;
38 
39 /**
40  * The main wallpaper data model, used internally by the {@link WallpaperManagerService}. <br>
41  * An instance of this class contains all the information about a wallpaper.
42  */
43 class WallpaperData {
44 
45     final int userId;
46 
47     /**
48      * True while the client is writing a new wallpaper
49      */
50     boolean imageWallpaperPending;
51 
52     /**
53      * Which wallpaper is set. Flag values are from {@link SetWallpaperFlags}.
54      */
55     int mWhich;
56 
57     /**
58      * True if the system wallpaper was also used for lock screen before this wallpaper was set.
59      * This is needed to update state after setting the wallpaper.
60      */
61     boolean mSystemWasBoth;
62 
63     /**
64      * Callback once the set + crop is finished
65      */
66     IWallpaperManagerCallback setComplete;
67 
68     /**
69      * Is the OS allowed to back up this wallpaper imagery?
70      */
71     boolean allowBackup;
72 
73     /**
74      * Resource name if using a picture from the wallpaper gallery
75      */
76     String name = "";
77 
78     /**
79      * The component name of the currently set live wallpaper.
80      */
81     ComponentName wallpaperComponent;
82 
83     /**
84      * The component name of the wallpaper that should be set next.
85      */
86     ComponentName nextWallpaperComponent;
87 
88     /**
89      * The ID of this wallpaper
90      */
91     int wallpaperId;
92 
93     /**
94      * Primary colors histogram
95      */
96     WallpaperColors primaryColors;
97 
98     /**
99      * If the wallpaper was set from a foreground app (instead of from a background service).
100      */
101     public boolean fromForegroundApp;
102 
103     WallpaperManagerService.WallpaperConnection connection;
104     long lastDiedTime;
105     boolean wallpaperUpdating;
106     WallpaperManagerService.WallpaperObserver wallpaperObserver;
107 
108     /**
109      * The dim amount to be applied to the wallpaper.
110      */
111     float mWallpaperDimAmount = 0.0f;
112 
113     /**
114      * A map to keep track of the dimming set by different applications. The key is the calling
115      * UID and the value is the dim amount.
116      */
117     SparseArray<Float> mUidToDimAmount = new SparseArray<>();
118 
119     /**
120      * Whether we need to extract the wallpaper colors again to calculate the dark hints
121      * after dimming is applied.
122      */
123     boolean mIsColorExtractedFromDim;
124 
125     /**
126      * List of callbacks registered they should each be notified when the wallpaper is changed.
127      */
128     RemoteCallbackList<IWallpaperManagerCallback> callbacks = new RemoteCallbackList<>();
129 
130     /**
131      * Defines which part of the {@link #getWallpaperFile()} image is in the {@link #getCropFile()}.
132      */
133     final Rect cropHint = new Rect(0, 0, 0, 0);
134 
135     /**
136      * How much the crop is sub-sampled. A value > 1 means that the image quality was reduced.
137      * This is the ratio between the cropHint height and the actual {@link #getCropFile()} height.
138      */
139     float mSampleSize = 1f;
140 
141     // Describes the context of a call to WallpaperManagerService#bindWallpaperComponentLocked
142     enum BindSource {
143         UNKNOWN,
144         CONNECT_LOCKED,
145         CONNECTION_TRY_TO_REBIND,
146         INITIALIZE_FALLBACK,
147         PACKAGE_UPDATE_FINISHED,
148         RESTORE_SETTINGS_LIVE_FAILURE,
149         RESTORE_SETTINGS_LIVE_SUCCESS,
150         RESTORE_SETTINGS_STATIC,
151         SET_LIVE,
152         SET_LIVE_TO_CLEAR,
153         SET_STATIC,
154         SWITCH_WALLPAPER_FAILURE,
155         SWITCH_WALLPAPER_SWITCH_USER,
156         SWITCH_WALLPAPER_UNLOCK_USER,
157     }
158 
159     // Context in which this wallpaper was bound. Intended for use in resolving b/301073479 but may
160     // be useful after the issue is resolved as well.
161     BindSource mBindSource = BindSource.UNKNOWN;
162 
163     // map of which -> File
164     private final SparseArray<File> mWallpaperFiles = new SparseArray<>();
165     private final SparseArray<File> mCropFiles = new SparseArray<>();
166 
167     /**
168      * Mapping of {@link ScreenOrientation} -> crop hint. The crop hints are relative to the
169      * original image stored in {@link #getWallpaperFile()}.
170      * Only used when multi crop flag is enabled.
171      */
172     SparseArray<Rect> mCropHints = new SparseArray<>();
173 
174     /**
175      * The phone orientation when the wallpaper was set. Only relevant for image wallpapers
176      */
177     int mOrientationWhenSet = ORIENTATION_UNKNOWN;
178 
WallpaperData(int userId, @SetWallpaperFlags int wallpaperType)179     WallpaperData(int userId, @SetWallpaperFlags int wallpaperType) {
180         this.userId = userId;
181         this.mWhich = wallpaperType;
182     }
183 
184     /**
185      * Copies the essential properties of a WallpaperData to a new instance, including the id and
186      * WallpaperConnection, usually in preparation for migrating a system+lock wallpaper to system-
187      * or lock-only. NB: the source object retains the pointer to the connection and it is the
188      * caller's responsibility to set this to null or otherwise be sure the connection is not shared
189      * between WallpaperData instances.
190      *
191      * @param source WallpaperData object to copy
192      */
WallpaperData(WallpaperData source)193     WallpaperData(WallpaperData source) {
194         this.userId = source.userId;
195         this.wallpaperComponent = source.wallpaperComponent;
196         this.mWhich = source.mWhich;
197         this.wallpaperId = source.wallpaperId;
198         this.cropHint.set(source.cropHint);
199         if (source.mCropHints != null) {
200             this.mCropHints = source.mCropHints.clone();
201         }
202         this.allowBackup = source.allowBackup;
203         this.primaryColors = source.primaryColors;
204         this.mWallpaperDimAmount = source.mWallpaperDimAmount;
205         this.connection = source.connection;
206         if (this.connection != null) {
207             this.connection.mWallpaper = this;
208         }
209     }
210 
getWallpaperFile()211     File getWallpaperFile() {
212         String fileName = mWhich == FLAG_LOCK ? WALLPAPER_LOCK_ORIG : WALLPAPER;
213         return getFile(mWallpaperFiles, fileName);
214     }
215 
getCropFile()216     File getCropFile() {
217         String fileName = mWhich == FLAG_LOCK ? WALLPAPER_LOCK_CROP : WALLPAPER_CROP;
218         return getFile(mCropFiles, fileName);
219     }
220 
getFile(SparseArray<File> map, String fileName)221     private File getFile(SparseArray<File> map, String fileName) {
222         File result = map.get(mWhich);
223         if (result == null) {
224             result = new File(getWallpaperDir(userId), fileName);
225             map.put(userId, result);
226         }
227         return result;
228     }
229 
230     @Override
toString()231     public String toString() {
232         StringBuilder out = new StringBuilder(defaultString(this));
233         out.append(", id: ");
234         out.append(wallpaperId);
235         out.append(", which: ");
236         out.append(mWhich);
237         out.append(", file mod: ");
238         out.append(getWallpaperFile() != null ? getWallpaperFile().lastModified() : "null");
239         if (connection == null) {
240             out.append(", no connection");
241         } else {
242             out.append(", info: ");
243             out.append(connection.mInfo);
244             out.append(", engine(s):");
245             connection.forEachDisplayConnector(connector -> {
246                 if (connector.mEngine != null) {
247                     out.append(" ");
248                     out.append(defaultString(connector.mEngine));
249                 } else {
250                     out.append(" null");
251                 }
252             });
253         }
254         return out.toString();
255     }
256 
defaultString(Object o)257     private static String defaultString(Object o) {
258         return o.getClass().getSimpleName() + "@" + Integer.toHexString(o.hashCode());
259     }
260 
261     // Called during initialization of a given user's wallpaper bookkeeping
cropExists()262     boolean cropExists() {
263         return getCropFile().exists();
264     }
265 
sourceExists()266     boolean sourceExists() {
267         return getWallpaperFile().exists();
268     }
269 }
270