blob: 2115f7ccfe983ee4ff9b1b54366a994705c60cc2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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
Amith Yamasani09e9cdc2013-11-06 14:54:50 -080017package com.android.server.wallpaper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Christopher Tateedf7d042016-03-29 18:24:25 -070019import static android.app.WallpaperManager.FLAG_LOCK;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060020import static android.app.WallpaperManager.FLAG_SYSTEM;
wilsonshihde93f492018-11-01 21:23:40 +080021import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060022import static android.os.ParcelFileDescriptor.MODE_CREATE;
23import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
24import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
25import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070026import static android.view.Display.DEFAULT_DISPLAY;
27import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
Christopher Tate111bd4a2009-06-24 17:29:38 -070028
Lucas Dupin50ba9912017-07-14 11:55:05 -070029import android.annotation.NonNull;
Christopher Tatee409f0e2016-03-21 14:53:15 -070030import android.app.ActivityManager;
Amith Yamasani4e2820c2012-08-28 22:17:23 -070031import android.app.AppGlobals;
Benjamin Franzf3ece362015-02-11 10:51:10 +000032import android.app.AppOpsManager;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070033import android.app.IWallpaperManager;
34import android.app.IWallpaperManagerCallback;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070035import android.app.PendingIntent;
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070036import android.app.UserSwitchObserver;
Lucas Dupin75ec3792017-06-29 14:07:18 -070037import android.app.WallpaperColors;
Dianne Hackborneb034652009-09-07 00:49:58 -070038import android.app.WallpaperInfo;
Jeff Sharkey28f08772014-04-16 09:41:58 -070039import android.app.WallpaperManager;
wilsonshih999ec102019-05-17 18:47:50 +080040import android.app.WallpaperManager.SetWallpaperFlags;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +010041import android.app.admin.DevicePolicyManager;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080042import android.app.backup.WallpaperBackupHelper;
Amith Yamasani13593602012-03-22 16:16:17 -070043import android.content.BroadcastReceiver;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070044import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.content.Context;
46import android.content.Intent;
Amith Yamasani13593602012-03-22 16:16:17 -070047import android.content.IntentFilter;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070048import android.content.ServiceConnection;
Amith Yamasani4e2820c2012-08-28 22:17:23 -070049import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.pm.PackageManager;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060051import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070052import android.content.pm.ResolveInfo;
53import android.content.pm.ServiceInfo;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070054import android.content.pm.UserInfo;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070055import android.content.res.Resources;
Christopher Tate1e1e2e02016-01-25 15:34:36 -080056import android.graphics.Bitmap;
57import android.graphics.BitmapFactory;
58import android.graphics.BitmapRegionDecoder;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -070059import android.graphics.Color;
Dianne Hackborn067e5f62014-09-07 23:14:30 -070060import android.graphics.Rect;
wilsonshihde93f492018-11-01 21:23:40 +080061import android.hardware.display.DisplayManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.os.Binder;
Dianne Hackborn284ac932009-08-28 10:34:25 -070063import android.os.Bundle;
wilsonshiha282bf72018-11-30 12:48:05 +080064import android.os.Debug;
Amith Yamasani13593602012-03-22 16:16:17 -070065import android.os.Environment;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060066import android.os.FileObserver;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070067import android.os.FileUtils;
Christopher Tatec349e59f2017-05-05 17:37:43 -070068import android.os.Handler;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070069import android.os.IBinder;
Lucas Dupin50ba9912017-07-14 11:55:05 -070070import android.os.IInterface;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -070071import android.os.IRemoteCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.ParcelFileDescriptor;
Lucas Dupin75ec3792017-06-29 14:07:18 -070073import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.os.RemoteCallbackList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060075import android.os.RemoteException;
rpcraig554cb0c2012-07-05 06:41:43 -040076import android.os.SELinux;
Dianne Hackborn0cd48872009-08-13 18:51:59 -070077import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070078import android.os.UserHandle;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070079import android.os.UserManager;
Bookatzcfc5d192019-11-05 17:25:53 -080080import android.os.UserManagerInternal;
Jeff Sharkey859856d2019-03-25 11:44:11 -060081import android.os.storage.StorageManager;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070082import android.service.wallpaper.IWallpaperConnection;
83import android.service.wallpaper.IWallpaperEngine;
84import android.service.wallpaper.IWallpaperService;
85import android.service.wallpaper.WallpaperService;
Christopher Tate8347b632016-04-29 18:59:18 -070086import android.system.ErrnoException;
87import android.system.Os;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -070088import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080089import android.util.Slog;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080090import android.util.SparseArray;
wilsonshiha282bf72018-11-30 12:48:05 +080091import android.util.SparseBooleanArray;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070092import android.util.Xml;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -070093import android.view.Display;
Valentin Iftime3047bb12018-12-28 17:02:19 +010094import android.view.DisplayInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060096import com.android.internal.R;
wilsonshih999ec102019-05-17 18:47:50 +080097import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060098import com.android.internal.content.PackageMonitor;
Christopher Tate190e8532016-07-11 11:35:34 -070099import com.android.internal.os.BackgroundThread;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600100import com.android.internal.util.DumpUtils;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600101import com.android.internal.util.FastXmlSerializer;
102import com.android.internal.util.JournaledFile;
103import com.android.server.EventLogTags;
Adrian Roosc3f915e2016-09-06 11:40:53 -0700104import com.android.server.FgThread;
Andrii Kuliandd989612019-02-21 12:13:28 -0800105import com.android.server.LocalServices;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600106import com.android.server.SystemService;
Felipe Leme4e2cbb52019-12-02 16:46:49 -0800107import com.android.server.utils.TimingsTraceAndSlog;
Andrii Kuliandd989612019-02-21 12:13:28 -0800108import com.android.server.wm.WindowManagerInternal;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600109
110import libcore.io.IoUtils;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700111
112import org.xmlpull.v1.XmlPullParser;
113import org.xmlpull.v1.XmlPullParserException;
114import org.xmlpull.v1.XmlSerializer;
115
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600116import java.io.BufferedOutputStream;
117import java.io.File;
118import java.io.FileDescriptor;
119import java.io.FileInputStream;
120import java.io.FileNotFoundException;
121import java.io.FileOutputStream;
122import java.io.IOException;
123import java.io.InputStream;
124import java.io.PrintWriter;
125import java.nio.charset.StandardCharsets;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400126import java.util.ArrayList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600127import java.util.Arrays;
128import java.util.List;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700129import java.util.Objects;
wilsonshihde93f492018-11-01 21:23:40 +0800130import java.util.function.Consumer;
wilsonshiha282bf72018-11-30 12:48:05 +0800131import java.util.function.Predicate;
Christopher Tatead3c2592016-01-20 18:13:17 -0800132
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900133public class WallpaperManagerService extends IWallpaperManager.Stub
134 implements IWallpaperManagerService {
wilsonshiha282bf72018-11-30 12:48:05 +0800135 private static final String TAG = "WallpaperManagerService";
136 private static final boolean DEBUG = false;
137 private static final boolean DEBUG_LIVE = true;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700138
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800139 // This 100MB limitation is defined in RecordingCanvas.
140 private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024;
141
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600142 public static class Lifecycle extends SystemService {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900143 private IWallpaperManagerService mService;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600144
145 public Lifecycle(Context context) {
146 super(context);
147 }
148
149 @Override
150 public void onStart() {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900151 try {
152 final Class<? extends IWallpaperManagerService> klass =
153 (Class<? extends IWallpaperManagerService>)Class.forName(
154 getContext().getResources().getString(
155 R.string.config_wallpaperManagerServiceName));
156 mService = klass.getConstructor(Context.class).newInstance(getContext());
157 publishBinderService(Context.WALLPAPER_SERVICE, mService);
158 } catch (Exception exp) {
159 Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp);
160 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600161 }
162
163 @Override
164 public void onBootPhase(int phase) {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900165 if (mService != null) {
166 mService.onBootPhase(phase);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600167 }
168 }
169
170 @Override
171 public void onUnlockUser(int userHandle) {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900172 if (mService != null) {
173 mService.onUnlockUser(userHandle);
174 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600175 }
176 }
177
wilsonshiha282bf72018-11-30 12:48:05 +0800178 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700180 /**
181 * Minimum time between crashes of a wallpaper service for us to consider
182 * restarting it vs. just reverting to the static wallpaper.
183 */
wilsonshiha282bf72018-11-30 12:48:05 +0800184 private static final long MIN_WALLPAPER_CRASH_TIME = 10000;
185 private static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800186 static final String WALLPAPER = "wallpaper_orig";
187 static final String WALLPAPER_CROP = "wallpaper";
Christopher Tatebe132e62016-02-10 12:59:49 -0800188 static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
189 static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800190 static final String WALLPAPER_INFO = "wallpaper_info.xml";
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700191
Christopher Tatebe132e62016-02-10 12:59:49 -0800192 // All the various per-user state files we need to be aware of
wilsonshiha282bf72018-11-30 12:48:05 +0800193 private static final String[] sPerUserFiles = new String[] {
Christopher Tatebe132e62016-02-10 12:59:49 -0800194 WALLPAPER, WALLPAPER_CROP,
195 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
196 WALLPAPER_INFO
197 };
198
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700199 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
201 * that the wallpaper has changed. The CREATE is triggered when there is no
202 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
Christopher Tate190e8532016-07-11 11:35:34 -0700203 * every time the wallpaper is changed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 */
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800205 private class WallpaperObserver extends FileObserver {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700206
Christopher Tatebe132e62016-02-10 12:59:49 -0800207 final int mUserId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800208 final WallpaperData mWallpaper;
209 final File mWallpaperDir;
210 final File mWallpaperFile;
Christopher Tatebe132e62016-02-10 12:59:49 -0800211 final File mWallpaperLockFile;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800212
213 public WallpaperObserver(WallpaperData wallpaper) {
214 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
Christopher Tateda058e22014-10-08 14:51:09 -0700215 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
Christopher Tatebe132e62016-02-10 12:59:49 -0800216 mUserId = wallpaper.userId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800217 mWallpaperDir = getWallpaperDir(wallpaper.userId);
218 mWallpaper = wallpaper;
219 mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
Christopher Tatebe132e62016-02-10 12:59:49 -0800220 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800221 }
222
Christopher Tatebe132e62016-02-10 12:59:49 -0800223 private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
224 WallpaperData wallpaper = null;
225 synchronized (mLock) {
226 if (lockChanged) {
227 wallpaper = mLockWallpaperMap.get(mUserId);
228 }
229 if (wallpaper == null) {
230 // no lock-specific wallpaper exists, or sys case, handled together
231 wallpaper = mWallpaperMap.get(mUserId);
232 }
233 }
234 return (wallpaper != null) ? wallpaper : mWallpaper;
235 }
236
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800237 @Override
238 public void onEvent(int event, String path) {
239 if (path == null) {
240 return;
241 }
Christopher Tated7faf532016-02-25 12:43:38 -0800242 final boolean moved = (event == MOVED_TO);
243 final boolean written = (event == CLOSE_WRITE || moved);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800244 final File changedFile = new File(mWallpaperDir, path);
245
Christopher Tatebe132e62016-02-10 12:59:49 -0800246 // System and system+lock changes happen on the system wallpaper input file;
247 // lock-only changes happen on the dedicated lock wallpaper input file
248 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
249 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700250 int notifyColorsWhich = 0;
Christopher Tatebe132e62016-02-10 12:59:49 -0800251 WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
252
253 if (DEBUG) {
254 Slog.v(TAG, "Wallpaper file change: evt=" + event
255 + " path=" + path
256 + " sys=" + sysWallpaperChanged
257 + " lock=" + lockWallpaperChanged
258 + " imagePending=" + wallpaper.imageWallpaperPending
259 + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
260 + " written=" + written);
261 }
Christopher Tate8347b632016-04-29 18:59:18 -0700262
263 if (moved && lockWallpaperChanged) {
264 // We just migrated sys -> lock to preserve imagery for an impending
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700265 // new system-only wallpaper. Tell keyguard about it and make sure it
266 // has the right SELinux label.
Christopher Tate8347b632016-04-29 18:59:18 -0700267 if (DEBUG) {
268 Slog.i(TAG, "Sys -> lock MOVED_TO");
269 }
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700270 SELinux.restorecon(changedFile);
Christopher Tate8347b632016-04-29 18:59:18 -0700271 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700272 notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK);
Christopher Tate8347b632016-04-29 18:59:18 -0700273 return;
274 }
275
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800276 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800277 if (sysWallpaperChanged || lockWallpaperChanged) {
278 notifyCallbacksLocked(wallpaper);
279 if (wallpaper.wallpaperComponent == null
Christopher Tateda058e22014-10-08 14:51:09 -0700280 || event != CLOSE_WRITE // includes the MOVED_TO case
Christopher Tatebe132e62016-02-10 12:59:49 -0800281 || wallpaper.imageWallpaperPending) {
Christopher Tateda058e22014-10-08 14:51:09 -0700282 if (written) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800283 // The image source has finished writing the source image,
284 // so we now produce the crop rect (in the background), and
285 // only publish the new displayable (sub)image as a result
286 // of that work.
Christopher Tatebe132e62016-02-10 12:59:49 -0800287 if (DEBUG) {
288 Slog.v(TAG, "Wallpaper written; generating crop");
289 }
Christopher Tateebadfb12016-07-25 14:50:08 -0700290 SELinux.restorecon(changedFile);
Christopher Tated7faf532016-02-25 12:43:38 -0800291 if (moved) {
292 // This is a restore, so generate the crop using any just-restored new
293 // crop guidelines, making sure to preserve our local dimension hints.
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700294 // We also make sure to reapply the correct SELinux label.
Christopher Tated7faf532016-02-25 12:43:38 -0800295 if (DEBUG) {
296 Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
297 }
298 loadSettingsLocked(wallpaper.userId, true);
299 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800300 generateCrop(wallpaper);
301 if (DEBUG) {
302 Slog.v(TAG, "Crop done; invoking completion callback");
303 }
304 wallpaper.imageWallpaperPending = false;
Christopher Tatebe132e62016-02-10 12:59:49 -0800305 if (sysWallpaperChanged) {
306 // If this was the system wallpaper, rebind...
307 bindWallpaperComponentLocked(mImageWallpaper, true,
308 false, wallpaper, null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700309 notifyColorsWhich |= FLAG_SYSTEM;
Christopher Tatebe132e62016-02-10 12:59:49 -0800310 }
311 if (lockWallpaperChanged
Christopher Tateedf7d042016-03-29 18:24:25 -0700312 || (wallpaper.whichPending & FLAG_LOCK) != 0) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800313 if (DEBUG) {
Christopher Tatedb27b842016-02-25 14:39:17 -0800314 Slog.i(TAG, "Lock-relevant wallpaper changed");
Christopher Tatebe132e62016-02-10 12:59:49 -0800315 }
Christopher Tatedb27b842016-02-25 14:39:17 -0800316 // either a lock-only wallpaper commit or a system+lock event.
317 // if it's system-plus-lock we need to wipe the lock bookkeeping;
318 // we're falling back to displaying the system wallpaper there.
319 if (!lockWallpaperChanged) {
320 mLockWallpaperMap.remove(wallpaper.userId);
321 }
322 // and in any case, tell keyguard about it
Christopher Tate8347b632016-04-29 18:59:18 -0700323 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700324 notifyColorsWhich |= FLAG_LOCK;
Christopher Tatebe132e62016-02-10 12:59:49 -0800325 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700326
Christopher Tatedb27b842016-02-25 14:39:17 -0800327 saveSettingsLocked(wallpaper.userId);
Christopher Tate8efbe0d2017-08-29 16:50:13 -0700328
329 // Publish completion *after* we've persisted the changes
330 if (wallpaper.setComplete != null) {
331 try {
332 wallpaper.setComplete.onWallpaperChanged();
333 } catch (RemoteException e) {
334 // if this fails we don't really care; the setting app may just
335 // have crashed and that sort of thing is a fact of life.
336 }
337 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
340 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800341 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700342
343 // Outside of the lock since it will synchronize itself
344 if (notifyColorsWhich != 0) {
345 notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
346 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800347 }
348 }
349
wilsonshiha282bf72018-11-30 12:48:05 +0800350 private void notifyLockWallpaperChanged() {
Christopher Tate8347b632016-04-29 18:59:18 -0700351 final IWallpaperManagerCallback cb = mKeyguardListener;
352 if (cb != null) {
353 try {
354 cb.onWallpaperChanged();
355 } catch (RemoteException e) {
356 // Oh well it went away; no big deal
357 }
358 }
359 }
360
Lucas Dupin50ba9912017-07-14 11:55:05 -0700361 private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
wilsonshih36597d42018-12-05 18:56:39 +0800362 if (wallpaper.connection != null) {
363 wallpaper.connection.forEachDisplayConnector(connector -> {
364 notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId);
365 });
366 } else { // Lock wallpaper does not have WallpaperConnection.
367 notifyWallpaperColorsChangedOnDisplay(wallpaper, which, DEFAULT_DISPLAY);
368 }
369 }
370
371 private RemoteCallbackList<IWallpaperManagerCallback> getWallpaperCallbacks(int userId,
372 int displayId) {
373 RemoteCallbackList<IWallpaperManagerCallback> listeners = null;
374 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> displayListeners =
375 mColorsChangedListeners.get(userId);
376 if (displayListeners != null) {
377 listeners = displayListeners.get(displayId);
378 }
379 return listeners;
380 }
381
382 private void notifyWallpaperColorsChangedOnDisplay(@NonNull WallpaperData wallpaper, int which,
383 int displayId) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700384 boolean needsExtraction;
385 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700386 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
wilsonshih36597d42018-12-05 18:56:39 +0800387 getWallpaperCallbacks(wallpaper.userId, displayId);
Lucas Dupin50ba9912017-07-14 11:55:05 -0700388 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
wilsonshih36597d42018-12-05 18:56:39 +0800389 getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
Lucas Dupin50ba9912017-07-14 11:55:05 -0700390 // No-op until someone is listening to it.
391 if (emptyCallbackList(currentUserColorListeners) &&
392 emptyCallbackList(userAllColorListeners)) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700393 return;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700394 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700395
396 if (DEBUG) {
wilsonshih36597d42018-12-05 18:56:39 +0800397 Slog.v(TAG, "notifyWallpaperColorsChangedOnDisplay " + which);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700398 }
399
400 needsExtraction = wallpaper.primaryColors == null;
401 }
402
Lucas Dupin75ec3792017-06-29 14:07:18 -0700403 // Let's notify the current values, it's fine if it's null, it just means
404 // that we don't know yet.
wilsonshih36597d42018-12-05 18:56:39 +0800405 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700406
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700407 if (needsExtraction) {
408 extractColors(wallpaper);
Lucas Dupin50ba9912017-07-14 11:55:05 -0700409 synchronized (mLock) {
410 // Don't need to notify if nothing changed.
411 if (wallpaper.primaryColors == null) {
412 return;
413 }
414 }
wilsonshih36597d42018-12-05 18:56:39 +0800415 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId, displayId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700416 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700417 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700418
Lucas Dupin50ba9912017-07-14 11:55:05 -0700419 private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
420 return (list == null || list.getRegisteredCallbackCount() == 0);
421 }
422
423 private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
wilsonshih36597d42018-12-05 18:56:39 +0800424 int userId, int displayId) {
Lucas Dupin75ec3792017-06-29 14:07:18 -0700425 final IWallpaperManagerCallback keyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400426 final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700427 synchronized (mLock) {
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400428 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
wilsonshih36597d42018-12-05 18:56:39 +0800429 getWallpaperCallbacks(userId, displayId);
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400430 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
wilsonshih36597d42018-12-05 18:56:39 +0800431 getWallpaperCallbacks(UserHandle.USER_ALL, displayId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700432 keyguardListener = mKeyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400433
434 if (currentUserColorListeners != null) {
435 final int count = currentUserColorListeners.beginBroadcast();
436 for (int i = 0; i < count; i++) {
437 colorListeners.add(currentUserColorListeners.getBroadcastItem(i));
438 }
439 currentUserColorListeners.finishBroadcast();
440 }
441
442 if (userAllColorListeners != null) {
443 final int count = userAllColorListeners.beginBroadcast();
444 for (int i = 0; i < count; i++) {
445 colorListeners.add(userAllColorListeners.getBroadcastItem(i));
446 }
447 userAllColorListeners.finishBroadcast();
448 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700449 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700450
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400451 final int count = colorListeners.size();
452 for (int i = 0; i < count; i++) {
453 try {
454 colorListeners.get(i).onWallpaperColorsChanged(wallpaperColors, which, userId);
455 } catch (RemoteException e) {
456 // Callback is gone, it's not necessary to unregister it since
457 // RemoteCallbackList#getBroadcastItem will take care of it.
Lucas Dupin75ec3792017-06-29 14:07:18 -0700458 }
459 }
460
wilsonshih36597d42018-12-05 18:56:39 +0800461 // Only shows Keyguard on default display
462 if (keyguardListener != null && displayId == DEFAULT_DISPLAY) {
Lucas Dupin75ec3792017-06-29 14:07:18 -0700463 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700464 keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700465 } catch (RemoteException e) {
466 // Oh well it went away; no big deal
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700467 }
468 }
469 }
470
Lucas Dupinbcae5852017-05-03 12:42:58 -0700471 /**
472 * We can easily extract colors from an ImageWallpaper since it's only a bitmap.
Lucas Dupin284836b2017-06-23 15:28:41 -0700473 * In this case, using the crop is more than enough. Live wallpapers are just ignored.
Lucas Dupinbcae5852017-05-03 12:42:58 -0700474 *
475 * @param wallpaper a wallpaper representation
476 */
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700477 private void extractColors(WallpaperData wallpaper) {
478 String cropFile = null;
wilsonshih31d70a12019-01-14 12:42:35 +0800479 boolean defaultImageWallpaper = false;
Lucas Dupin284836b2017-06-23 15:28:41 -0700480 int wallpaperId;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700481
wilsonshih36597d42018-12-05 18:56:39 +0800482 if (wallpaper.equals(mFallbackWallpaper)) {
wilsonshihfa24e4f2019-02-22 10:29:19 +0800483 synchronized (mLock) {
484 if (mFallbackWallpaper.primaryColors != null) return;
485 }
486 final WallpaperColors colors = extractDefaultImageWallpaperColors();
487 synchronized (mLock) {
488 mFallbackWallpaper.primaryColors = colors;
489 }
wilsonshih36597d42018-12-05 18:56:39 +0800490 return;
491 }
492
Lucas Dupinbcae5852017-05-03 12:42:58 -0700493 synchronized (mLock) {
Lucas Dupin284836b2017-06-23 15:28:41 -0700494 // Not having a wallpaperComponent means it's a lock screen wallpaper.
495 final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
Lucas Dupinbcae5852017-05-03 12:42:58 -0700496 || wallpaper.wallpaperComponent == null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700497 if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
498 cropFile = wallpaper.cropFile.getAbsolutePath();
wilsonshih31d70a12019-01-14 12:42:35 +0800499 } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) {
500 defaultImageWallpaper = true;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700501 }
502 wallpaperId = wallpaper.wallpaperId;
503 }
504
Lucas Dupin84b89d92017-05-09 12:16:19 -0700505 WallpaperColors colors = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700506 if (cropFile != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700507 Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
Lucas Dupin284836b2017-06-23 15:28:41 -0700508 if (bitmap != null) {
Lucas Dupinb5e50532018-05-24 16:33:14 +0000509 colors = WallpaperColors.fromBitmap(bitmap);
Lucas Dupin284836b2017-06-23 15:28:41 -0700510 bitmap.recycle();
511 }
wilsonshih31d70a12019-01-14 12:42:35 +0800512 } else if (defaultImageWallpaper) {
513 // There is no crop and source file because this is default image wallpaper.
wilsonshihfa24e4f2019-02-22 10:29:19 +0800514 colors = extractDefaultImageWallpaperColors();
Lucas Dupinbcae5852017-05-03 12:42:58 -0700515 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700516
Lucas Dupin84b89d92017-05-09 12:16:19 -0700517 if (colors == null) {
Lucas Dupinbcae5852017-05-03 12:42:58 -0700518 Slog.w(TAG, "Cannot extract colors because wallpaper could not be read.");
519 return;
520 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700521
Lucas Dupinbcae5852017-05-03 12:42:58 -0700522 synchronized (mLock) {
523 if (wallpaper.wallpaperId == wallpaperId) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700524 wallpaper.primaryColors = colors;
Lucas Dupin75ec3792017-06-29 14:07:18 -0700525 // Now that we have the colors, let's save them into the xml
526 // to avoid having to run this again.
527 saveSettingsLocked(wallpaper.userId);
Lucas Dupinbcae5852017-05-03 12:42:58 -0700528 } else {
529 Slog.w(TAG, "Not setting primary colors since wallpaper changed");
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700530 }
531 }
532 }
533
wilsonshihfa24e4f2019-02-22 10:29:19 +0800534 private WallpaperColors extractDefaultImageWallpaperColors() {
535 if (DEBUG) Slog.d(TAG, "Extract default image wallpaper colors");
536
wilsonshih36597d42018-12-05 18:56:39 +0800537 synchronized (mLock) {
wilsonshihfa24e4f2019-02-22 10:29:19 +0800538 if (mCacheDefaultImageWallpaperColors != null) return mCacheDefaultImageWallpaperColors;
wilsonshih36597d42018-12-05 18:56:39 +0800539 }
540
wilsonshih36597d42018-12-05 18:56:39 +0800541 WallpaperColors colors = null;
wilsonshihfa24e4f2019-02-22 10:29:19 +0800542 try (InputStream is = WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) {
543 if (is == null) {
544 Slog.w(TAG, "Can't open default wallpaper stream");
545 return null;
wilsonshih36597d42018-12-05 18:56:39 +0800546 }
wilsonshihfa24e4f2019-02-22 10:29:19 +0800547
548 final BitmapFactory.Options options = new BitmapFactory.Options();
549 final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
550 if (bitmap != null) {
551 colors = WallpaperColors.fromBitmap(bitmap);
552 bitmap.recycle();
553 }
554 } catch (OutOfMemoryError e) {
555 Slog.w(TAG, "Can't decode default wallpaper stream", e);
556 } catch (IOException e) {
557 Slog.w(TAG, "Can't close default wallpaper stream", e);
wilsonshih36597d42018-12-05 18:56:39 +0800558 }
559
560 if (colors == null) {
561 Slog.e(TAG, "Extract default image wallpaper colors failed");
wilsonshihfa24e4f2019-02-22 10:29:19 +0800562 } else {
563 synchronized (mLock) {
564 mCacheDefaultImageWallpaperColors = colors;
565 }
wilsonshih36597d42018-12-05 18:56:39 +0800566 }
567
wilsonshihfa24e4f2019-02-22 10:29:19 +0800568 return colors;
wilsonshih36597d42018-12-05 18:56:39 +0800569 }
570
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800571 /**
572 * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
573 * for display.
574 */
575 private void generateCrop(WallpaperData wallpaper) {
576 boolean success = false;
Christopher Tate1a96b632016-03-22 15:25:42 -0700577
wilsonshih81e10a72018-11-15 10:54:21 +0800578 // Only generate crop for default display.
wilsonshiha282bf72018-11-30 12:48:05 +0800579 final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800580 final Rect cropHint = new Rect(wallpaper.cropHint);
581 final DisplayInfo displayInfo = new DisplayInfo();
582 mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo);
Christopher Tatebe132e62016-02-10 12:59:49 -0800583
584 if (DEBUG) {
585 Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
586 + Integer.toHexString(wallpaper.whichPending)
Christopher Tate1a96b632016-03-22 15:25:42 -0700587 + " to " + wallpaper.cropFile.getName()
588 + " crop=(" + cropHint.width() + 'x' + cropHint.height()
wilsonshih81e10a72018-11-15 10:54:21 +0800589 + ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')');
Christopher Tatebe132e62016-02-10 12:59:49 -0800590 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800591
592 // Analyse the source; needed in multiple cases
593 BitmapFactory.Options options = new BitmapFactory.Options();
594 options.inJustDecodeBounds = true;
595 BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
Christopher Tate1a96b632016-03-22 15:25:42 -0700596 if (options.outWidth <= 0 || options.outHeight <= 0) {
Joe LaPennac298b162016-05-02 15:25:50 -0700597 Slog.w(TAG, "Invalid wallpaper data");
Christopher Tate1a96b632016-03-22 15:25:42 -0700598 success = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800599 } else {
Christopher Tate1a96b632016-03-22 15:25:42 -0700600 boolean needCrop = false;
601 boolean needScale = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800602
Christopher Tate1a96b632016-03-22 15:25:42 -0700603 // Empty crop means use the full image
604 if (cropHint.isEmpty()) {
605 cropHint.left = cropHint.top = 0;
606 cropHint.right = options.outWidth;
607 cropHint.bottom = options.outHeight;
608 } else {
609 // force the crop rect to lie within the measured bounds
610 cropHint.offset(
611 (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
612 (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
613
Adrian Roos5c97ff22016-08-31 10:25:38 -0700614 // If the crop hint was larger than the image we just overshot. Patch things up.
615 if (cropHint.left < 0) {
616 cropHint.left = 0;
617 }
618 if (cropHint.top < 0) {
619 cropHint.top = 0;
620 }
621
Christopher Tate1a96b632016-03-22 15:25:42 -0700622 // Don't bother cropping if what we're left with is identity
Christopher Tateebadfb12016-07-25 14:50:08 -0700623 needCrop = (options.outHeight > cropHint.height()
Adrian Roos5c97ff22016-08-31 10:25:38 -0700624 || options.outWidth > cropHint.width());
Christopher Tate1a96b632016-03-22 15:25:42 -0700625 }
626
627 // scale if the crop height winds up not matching the recommended metrics
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800628 needScale = wpData.mHeight != cropHint.height()
629 || cropHint.height() > GLHelper.getMaxTextureSize()
630 || cropHint.width() > GLHelper.getMaxTextureSize();
Christopher Tate1a96b632016-03-22 15:25:42 -0700631
Valentin Iftime3047bb12018-12-28 17:02:19 +0100632 //make sure screen aspect ratio is preserved if width is scaled under screen size
633 if (needScale) {
Valentin Iftime3047bb12018-12-28 17:02:19 +0100634 final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height();
635 final int newWidth = (int) (cropHint.width() * scaleByHeight);
636 if (newWidth < displayInfo.logicalWidth) {
637 final float screenAspectRatio =
638 (float) displayInfo.logicalHeight / (float) displayInfo.logicalWidth;
639 cropHint.bottom = (int) (cropHint.width() * screenAspectRatio);
640 needCrop = true;
641 }
642 }
643
Christopher Tate1a96b632016-03-22 15:25:42 -0700644 if (DEBUG) {
645 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
wilsonshih81e10a72018-11-15 10:54:21 +0800646 Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
Christopher Tate1a96b632016-03-22 15:25:42 -0700647 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
648 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
649 }
650
651 if (!needCrop && !needScale) {
652 // Simple case: the nominal crop fits what we want, so we take
653 // the whole thing and just copy the image file directly.
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800654
655 // TODO: It is not accurate to estimate bitmap size without decoding it,
656 // may be we can try to remove this optimized way in the future,
657 // that means, we will always go into the 'else' block.
658
659 // This is just a quick estimation, may be smaller than it is.
660 long estimateSize = options.outWidth * options.outHeight * 4;
661
662 // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail.
663 // Please see: RecordingCanvas#throwIfCannotDraw.
664 if (estimateSize < MAX_BITMAP_SIZE) {
665 success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800666 }
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800667
Christopher Tate1a96b632016-03-22 15:25:42 -0700668 if (!success) {
669 wallpaper.cropFile.delete();
670 // TODO: fall back to default wallpaper in this case
671 }
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800672
673 if (DEBUG) {
674 Slog.v(TAG, "Null crop of new wallpaper, estimate size="
675 + estimateSize + ", success=" + success);
676 }
Christopher Tate1a96b632016-03-22 15:25:42 -0700677 } else {
678 // Fancy case: crop and scale. First, we decode and scale down if appropriate.
679 FileOutputStream f = null;
680 BufferedOutputStream bos = null;
681 try {
682 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
683 wallpaper.wallpaperFile.getAbsolutePath(), false);
684
685 // This actually downsamples only by powers of two, but that's okay; we do
686 // a proper scaling blit later. This is to minimize transient RAM use.
687 // We calculate the largest power-of-two under the actual ratio rather than
688 // just let the decode take care of it because we also want to remap where the
689 // cropHint rectangle lies in the decoded [super]rect.
wilsonshih81e10a72018-11-15 10:54:21 +0800690 final int actualScale = cropHint.height() / wpData.mHeight;
Christopher Tate1a96b632016-03-22 15:25:42 -0700691 int scale = 1;
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800692 while (2 * scale <= actualScale) {
Christopher Tate1a96b632016-03-22 15:25:42 -0700693 scale *= 2;
694 }
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800695 options.inSampleSize = scale;
696 options.inJustDecodeBounds = false;
697
698 final Rect estimateCrop = new Rect(cropHint);
699 estimateCrop.scale(1f / options.inSampleSize);
700 final float hRatio = (float) wpData.mHeight / estimateCrop.height();
701 final int destHeight = (int) (estimateCrop.height() * hRatio);
702 final int destWidth = (int) (estimateCrop.width() * hRatio);
703
704 // We estimated an invalid crop, try to adjust the cropHint to get a valid one.
705 if (destWidth > GLHelper.getMaxTextureSize()) {
706 int newHeight = (int) (wpData.mHeight / hRatio);
707 int newWidth = (int) (wpData.mWidth / hRatio);
708
Christopher Tate1a96b632016-03-22 15:25:42 -0700709 if (DEBUG) {
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800710 Slog.v(TAG, "Invalid crop dimensions, trying to adjust.");
Christopher Tate1a96b632016-03-22 15:25:42 -0700711 }
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800712
713 estimateCrop.set(cropHint);
714 estimateCrop.left += (cropHint.width() - newWidth) / 2;
715 estimateCrop.top += (cropHint.height() - newHeight) / 2;
716 estimateCrop.right = estimateCrop.left + newWidth;
717 estimateCrop.bottom = estimateCrop.top + newHeight;
718 cropHint.set(estimateCrop);
719 estimateCrop.scale(1f / options.inSampleSize);
Christopher Tate1a96b632016-03-22 15:25:42 -0700720 }
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800721
722 // We've got the safe cropHint; now we want to scale it properly to
723 // the desired rectangle.
724 // That's a height-biased operation: make it fit the hinted height.
725 final int safeHeight = (int) (estimateCrop.height() * hRatio);
726 final int safeWidth = (int) (estimateCrop.width() * hRatio);
727
728 if (DEBUG) {
729 Slog.v(TAG, "Decode parameters:");
730 Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop);
731 Slog.v(TAG, " down sampling=" + options.inSampleSize
732 + ", hRatio=" + hRatio);
733 Slog.v(TAG, " dest=" + destWidth + "x" + destHeight);
734 Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight);
735 Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize());
736 }
737
738 Bitmap cropped = decoder.decodeRegion(cropHint, options);
Christopher Tate1a96b632016-03-22 15:25:42 -0700739 decoder.recycle();
740
741 if (cropped == null) {
742 Slog.e(TAG, "Could not decode new wallpaper");
743 } else {
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800744 // We are safe to create final crop with safe dimensions now.
Christopher Tate1a96b632016-03-22 15:25:42 -0700745 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800746 safeWidth, safeHeight, true);
Christopher Tate1a96b632016-03-22 15:25:42 -0700747 if (DEBUG) {
748 Slog.v(TAG, "Final extract:");
wilsonshih81e10a72018-11-15 10:54:21 +0800749 Slog.v(TAG, " dims: w=" + wpData.mWidth
750 + " h=" + wpData.mHeight);
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800751 Slog.v(TAG, " out: w=" + finalCrop.getWidth()
Christopher Tate1a96b632016-03-22 15:25:42 -0700752 + " h=" + finalCrop.getHeight());
753 }
754
Ahan Wu32c6a7c2019-10-03 12:36:59 +0800755 // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail.
756 // Please see: RecordingCanvas#throwIfCannotDraw.
757 if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) {
758 throw new RuntimeException(
759 "Too large bitmap, limit=" + MAX_BITMAP_SIZE);
760 }
761
Christopher Tate1a96b632016-03-22 15:25:42 -0700762 f = new FileOutputStream(wallpaper.cropFile);
763 bos = new BufferedOutputStream(f, 32*1024);
Christopher Tatec484f542016-05-11 14:31:34 -0700764 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
Christopher Tate1a96b632016-03-22 15:25:42 -0700765 bos.flush(); // don't rely on the implicit flush-at-close when noting success
766 success = true;
767 }
768 } catch (Exception e) {
769 if (DEBUG) {
770 Slog.e(TAG, "Error decoding crop", e);
771 }
772 } finally {
773 IoUtils.closeQuietly(bos);
774 IoUtils.closeQuietly(f);
775 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800776 }
777 }
778
779 if (!success) {
780 Slog.e(TAG, "Unable to apply new wallpaper");
781 wallpaper.cropFile.delete();
782 }
783
784 if (wallpaper.cropFile.exists()) {
785 boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
786 if (DEBUG) {
787 Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
788 }
789 }
790 }
791
wilsonshiha282bf72018-11-30 12:48:05 +0800792 private final Context mContext;
Andrii Kuliandd989612019-02-21 12:13:28 -0800793 private final WindowManagerInternal mWindowManagerInternal;
wilsonshiha282bf72018-11-30 12:48:05 +0800794 private final IPackageManager mIPackageManager;
795 private final MyPackageMonitor mMonitor;
796 private final AppOpsManager mAppOpsManager;
wilsonshihde93f492018-11-01 21:23:40 +0800797
798 private final DisplayManager mDisplayManager;
799 private final DisplayManager.DisplayListener mDisplayListener =
800 new DisplayManager.DisplayListener() {
801
802 @Override
803 public void onDisplayAdded(int displayId) {
wilsonshihde93f492018-11-01 21:23:40 +0800804 }
805
806 @Override
807 public void onDisplayRemoved(int displayId) {
808 synchronized (mLock) {
809 if (mLastWallpaper != null) {
wilsonshiha282bf72018-11-30 12:48:05 +0800810 WallpaperData targetWallpaper = null;
811 if (mLastWallpaper.connection.containsDisplay(displayId)) {
812 targetWallpaper = mLastWallpaper;
813 } else if (mFallbackWallpaper.connection.containsDisplay(displayId)) {
814 targetWallpaper = mFallbackWallpaper;
815 }
816 if (targetWallpaper == null) return;
817 WallpaperConnection.DisplayConnector connector =
818 targetWallpaper.connection.getDisplayConnectorOrCreate(displayId);
wilsonshihde93f492018-11-01 21:23:40 +0800819 if (connector == null) return;
820 connector.disconnectLocked();
wilsonshiha282bf72018-11-30 12:48:05 +0800821 targetWallpaper.connection.removeDisplayConnector(displayId);
822 removeDisplayData(displayId);
wilsonshihde93f492018-11-01 21:23:40 +0800823 }
wilsonshih36597d42018-12-05 18:56:39 +0800824 for (int i = mColorsChangedListeners.size() - 1; i >= 0; i--) {
825 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> callbacks =
826 mColorsChangedListeners.valueAt(i);
827 callbacks.delete(displayId);
828 }
wilsonshihde93f492018-11-01 21:23:40 +0800829 }
830 }
831
832 @Override
833 public void onDisplayChanged(int displayId) {
wilsonshihde93f492018-11-01 21:23:40 +0800834 }
835 };
836
Lucas Dupin50ba9912017-07-14 11:55:05 -0700837 /**
838 * Map of color listeners per user id.
wilsonshih36597d42018-12-05 18:56:39 +0800839 * The first key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
840 * The secondary key will be the display id, which means which display the listener is
841 * interested in.
Lucas Dupin50ba9912017-07-14 11:55:05 -0700842 */
wilsonshih36597d42018-12-05 18:56:39 +0800843 private final SparseArray<SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>>
wilsonshiha282bf72018-11-30 12:48:05 +0800844 mColorsChangedListeners;
wilsonshih999ec102019-05-17 18:47:50 +0800845 protected WallpaperData mLastWallpaper;
wilsonshiha282bf72018-11-30 12:48:05 +0800846 private IWallpaperManagerCallback mKeyguardListener;
847 private boolean mWaitingForUnlock;
848 private boolean mShuttingDown;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849
Justin Koh29c30162014-09-05 17:10:10 -0700850 /**
Christopher Tatead3c2592016-01-20 18:13:17 -0800851 * ID of the current wallpaper, changed every time anything sets a wallpaper.
852 * This is used for external detection of wallpaper update activity.
853 */
wilsonshiha282bf72018-11-30 12:48:05 +0800854 private int mWallpaperId;
Christopher Tatead3c2592016-01-20 18:13:17 -0800855
856 /**
Justin Koh29c30162014-09-05 17:10:10 -0700857 * Name of the component used to display bitmap wallpapers from either the gallery or
858 * built-in wallpapers.
859 */
wilsonshiha282bf72018-11-30 12:48:05 +0800860 private final ComponentName mImageWallpaper;
Justin Koh29c30162014-09-05 17:10:10 -0700861
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700862 /**
wilsonshihfa24e4f2019-02-22 10:29:19 +0800863 * Default image wallpaper shall never changed after system service started, caching it when we
864 * first read the image file.
865 */
866 private WallpaperColors mCacheDefaultImageWallpaperColors;
867
868 /**
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700869 * Name of the default wallpaper component; might be different from mImageWallpaper
870 */
wilsonshiha282bf72018-11-30 12:48:05 +0800871 private final ComponentName mDefaultWallpaperComponent;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700872
wilsonshiha282bf72018-11-30 12:48:05 +0800873 private final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
874 private final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
Dianne Hackborn07213e62011-08-24 20:05:39 -0700875
wilsonshiha282bf72018-11-30 12:48:05 +0800876 private SparseArray<DisplayData> mDisplayDatas = new SparseArray<>();
877
wilsonshih999ec102019-05-17 18:47:50 +0800878 protected WallpaperData mFallbackWallpaper;
wilsonshiha282bf72018-11-30 12:48:05 +0800879
880 private final SparseBooleanArray mUserRestorecon = new SparseBooleanArray();
881 private int mCurrentUserId = UserHandle.USER_NULL;
882 private boolean mInAmbientMode;
Dianne Hackborn07213e62011-08-24 20:05:39 -0700883
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800884 static class WallpaperData {
885
886 int userId;
887
Christopher Tatebe132e62016-02-10 12:59:49 -0800888 final File wallpaperFile; // source image
889 final File cropFile; // eventual destination
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800890
891 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800892 * True while the client is writing a new wallpaper
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800893 */
894 boolean imageWallpaperPending;
895
896 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800897 * Which new wallpapers are being written; mirrors the 'which'
898 * selector bit field to setWallpaper().
899 */
900 int whichPending;
901
902 /**
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800903 * Callback once the set + crop is finished
904 */
905 IWallpaperManagerCallback setComplete;
906
907 /**
Christopher Tated7faf532016-02-25 12:43:38 -0800908 * Is the OS allowed to back up this wallpaper imagery?
909 */
910 boolean allowBackup;
911
912 /**
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800913 * Resource name if using a picture from the wallpaper gallery
914 */
915 String name = "";
916
917 /**
918 * The component name of the currently set live wallpaper.
919 */
920 ComponentName wallpaperComponent;
921
922 /**
923 * The component name of the wallpaper that should be set next.
924 */
925 ComponentName nextWallpaperComponent;
926
Christopher Tatead3c2592016-01-20 18:13:17 -0800927 /**
928 * The ID of this wallpaper
929 */
930 int wallpaperId;
931
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700932 /**
933 * Primary colors histogram
934 */
935 WallpaperColors primaryColors;
936
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800937 WallpaperConnection connection;
938 long lastDiedTime;
939 boolean wallpaperUpdating;
940 WallpaperObserver wallpaperObserver;
941
942 /**
943 * List of callbacks registered they should each be notified when the wallpaper is changed.
944 */
945 private RemoteCallbackList<IWallpaperManagerCallback> callbacks
946 = new RemoteCallbackList<IWallpaperManagerCallback>();
947
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800948 /**
949 * The crop hint supplied for displaying a subset of the source image
950 */
951 final Rect cropHint = new Rect(0, 0, 0, 0);
952
wilsonshih999ec102019-05-17 18:47:50 +0800953 WallpaperData(int userId, File wallpaperDir, String inputFileName, String cropFileName) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800954 this.userId = userId;
Christopher Tatebe132e62016-02-10 12:59:49 -0800955 wallpaperFile = new File(wallpaperDir, inputFileName);
956 cropFile = new File(wallpaperDir, cropFileName);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800957 }
958
Christopher Tatebe132e62016-02-10 12:59:49 -0800959 // Called during initialization of a given user's wallpaper bookkeeping
Christopher Tate41297ff2016-03-10 16:46:15 -0800960 boolean cropExists() {
961 return cropFile.exists();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800962 }
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700963
964 boolean sourceExists() {
965 return wallpaperFile.exists();
966 }
wilsonshiha282bf72018-11-30 12:48:05 +0800967 }
wilsonshih81e10a72018-11-15 10:54:21 +0800968
wilsonshih999ec102019-05-17 18:47:50 +0800969 @VisibleForTesting
970 static final class DisplayData {
wilsonshiha282bf72018-11-30 12:48:05 +0800971 int mWidth = -1;
972 int mHeight = -1;
973 final Rect mPadding = new Rect(0, 0, 0, 0);
974 final int mDisplayId;
975
976 DisplayData(int displayId) {
977 mDisplayId = displayId;
wilsonshih81e10a72018-11-15 10:54:21 +0800978 }
979 }
980
wilsonshiha282bf72018-11-30 12:48:05 +0800981 private void removeDisplayData(int displayId) {
982 mDisplayDatas.remove(displayId);
983 }
984
985 private DisplayData getDisplayDataOrCreate(int displayId) {
986 DisplayData wpdData = mDisplayDatas.get(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +0800987 if (wpdData == null) {
wilsonshiha282bf72018-11-30 12:48:05 +0800988 wpdData = new DisplayData(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +0800989 ensureSaneWallpaperDisplaySize(wpdData, displayId);
wilsonshiha282bf72018-11-30 12:48:05 +0800990 mDisplayDatas.append(displayId, wpdData);
wilsonshih81e10a72018-11-15 10:54:21 +0800991 }
992 return wpdData;
993 }
994
wilsonshiha282bf72018-11-30 12:48:05 +0800995 private void ensureSaneWallpaperDisplaySize(DisplayData wpdData, int displayId) {
wilsonshih81e10a72018-11-15 10:54:21 +0800996 // We always want to have some reasonable width hint.
997 final int baseSize = getMaximumSizeDimension(displayId);
998 if (wpdData.mWidth < baseSize) {
999 wpdData.mWidth = baseSize;
1000 }
1001 if (wpdData.mHeight < baseSize) {
1002 wpdData.mHeight = baseSize;
1003 }
1004 }
1005
1006 private int getMaximumSizeDimension(int displayId) {
1007 Display display = mDisplayManager.getDisplay(displayId);
wilsonshiha282bf72018-11-30 12:48:05 +08001008 if (display == null) {
1009 Slog.w(TAG, "Invalid displayId=" + displayId + " " + Debug.getCallers(4));
1010 display = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
1011 }
wilsonshih81e10a72018-11-15 10:54:21 +08001012 return display.getMaximumSizeDimension();
1013 }
1014
wilsonshiha282bf72018-11-30 12:48:05 +08001015 void forEachDisplayData(Consumer<DisplayData> action) {
1016 for (int i = mDisplayDatas.size() - 1; i >= 0; i--) {
1017 final DisplayData wpdData = mDisplayDatas.valueAt(i);
wilsonshih81e10a72018-11-15 10:54:21 +08001018 action.accept(wpdData);
1019 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001020 }
1021
Christopher Tatead3c2592016-01-20 18:13:17 -08001022 int makeWallpaperIdLocked() {
1023 do {
1024 ++mWallpaperId;
1025 } while (mWallpaperId == 0);
1026 return mWallpaperId;
1027 }
1028
wilsonshiha282bf72018-11-30 12:48:05 +08001029 private boolean supportsMultiDisplay(WallpaperConnection connection) {
1030 if (connection != null) {
1031 return connection.mInfo == null // This is image wallpaper
1032 || connection.mInfo.supportsMultipleDisplays();
1033 }
1034 return false;
1035 }
1036
1037 private void updateFallbackConnection() {
1038 if (mLastWallpaper == null || mFallbackWallpaper == null) return;
1039 final WallpaperConnection systemConnection = mLastWallpaper.connection;
1040 final WallpaperConnection fallbackConnection = mFallbackWallpaper.connection;
wilsonshih78268c32018-12-18 20:48:28 +08001041 if (fallbackConnection == null) {
1042 Slog.w(TAG, "Fallback wallpaper connection has not been created yet!!");
1043 return;
1044 }
wilsonshih507ada52019-01-19 11:22:09 +08001045 if (supportsMultiDisplay(systemConnection)) {
1046 if (fallbackConnection.mDisplayConnector.size() != 0) {
1047 fallbackConnection.forEachDisplayConnector(connector -> {
1048 if (connector.mEngine != null) {
1049 connector.disconnectLocked();
1050 }
1051 });
1052 fallbackConnection.mDisplayConnector.clear();
1053 }
wilsonshiha282bf72018-11-30 12:48:05 +08001054 } else {
1055 fallbackConnection.appendConnectorWithCondition(display ->
1056 fallbackConnection.isUsableDisplay(display)
1057 && display.getDisplayId() != DEFAULT_DISPLAY
1058 && !fallbackConnection.containsDisplay(display.getDisplayId()));
1059 fallbackConnection.forEachDisplayConnector(connector -> {
1060 if (connector.mEngine == null) {
1061 connector.connectLocked(fallbackConnection, mFallbackWallpaper);
1062 }
1063 });
1064 }
1065 }
1066
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001067 class WallpaperConnection extends IWallpaperConnection.Stub
1068 implements ServiceConnection {
Adrian Roosc3f915e2016-09-06 11:40:53 -07001069
wilsonshihde93f492018-11-01 21:23:40 +08001070 /**
1071 * Collect needed info for a display.
1072 */
1073 private final class DisplayConnector {
1074 final int mDisplayId;
1075 final Binder mToken = new Binder();
1076 IWallpaperEngine mEngine;
1077 boolean mDimensionsChanged;
1078 boolean mPaddingChanged;
1079
1080 DisplayConnector(int displayId) {
1081 mDisplayId = displayId;
1082 }
1083
1084 void ensureStatusHandled() {
wilsonshiha282bf72018-11-30 12:48:05 +08001085 final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);
wilsonshihde93f492018-11-01 21:23:40 +08001086 if (mDimensionsChanged) {
1087 try {
wilsonshih81e10a72018-11-15 10:54:21 +08001088 mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight);
wilsonshihde93f492018-11-01 21:23:40 +08001089 } catch (RemoteException e) {
1090 Slog.w(TAG, "Failed to set wallpaper dimensions", e);
1091 }
1092 mDimensionsChanged = false;
1093 }
1094 if (mPaddingChanged) {
1095 try {
wilsonshih81e10a72018-11-15 10:54:21 +08001096 mEngine.setDisplayPadding(wpdData.mPadding);
wilsonshihde93f492018-11-01 21:23:40 +08001097 } catch (RemoteException e) {
1098 Slog.w(TAG, "Failed to set wallpaper padding", e);
1099 }
1100 mPaddingChanged = false;
1101 }
1102 }
1103
1104 void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
wilsonshih674a4a02018-12-19 11:47:25 +08001105 if (connection.mService == null) {
1106 Slog.w(TAG, "WallpaperService is not connected yet");
1107 return;
1108 }
wilsonshihde93f492018-11-01 21:23:40 +08001109 if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
wilsonshih999ec102019-05-17 18:47:50 +08001110 mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId);
wilsonshiha282bf72018-11-30 12:48:05 +08001111 final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);
wilsonshihde93f492018-11-01 21:23:40 +08001112 try {
wilsonshihde93f492018-11-01 21:23:40 +08001113 connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
wilsonshih81e10a72018-11-15 10:54:21 +08001114 wpdData.mWidth, wpdData.mHeight,
1115 wpdData.mPadding, mDisplayId);
wilsonshihde93f492018-11-01 21:23:40 +08001116 } catch (RemoteException e) {
1117 Slog.w(TAG, "Failed attaching wallpaper on display", e);
wilsonshih674a4a02018-12-19 11:47:25 +08001118 if (wallpaper != null && !wallpaper.wallpaperUpdating
wilsonshih81e10a72018-11-15 10:54:21 +08001119 && connection.getConnectedEngineSize() == 0) {
wilsonshihde93f492018-11-01 21:23:40 +08001120 bindWallpaperComponentLocked(null /* componentName */, false /* force */,
1121 false /* fromUser */, wallpaper, null /* reply */);
1122 }
1123 }
1124 }
1125
1126 void disconnectLocked() {
1127 if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken);
wilsonshih999ec102019-05-17 18:47:50 +08001128 mWindowManagerInternal.removeWindowToken(mToken, false/* removeWindows */,
1129 mDisplayId);
wilsonshihde93f492018-11-01 21:23:40 +08001130 try {
1131 if (mEngine != null) {
1132 mEngine.destroy();
1133 }
1134 } catch (RemoteException e) {
1135 }
1136 mEngine = null;
1137 }
1138 }
1139
1140 /**
1141 * A map for each display.
1142 * Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable.
1143 */
1144 private SparseArray<DisplayConnector> mDisplayConnector = new SparseArray<>();
1145
Adrian Roosc3f915e2016-09-06 11:40:53 -07001146 /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
1147 * middle of an update). If exceeded, the wallpaper gets reset to the system default. */
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001148 private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000;
Adrian Roosc3f915e2016-09-06 11:40:53 -07001149
Dianne Hackborneb034652009-09-07 00:49:58 -07001150 final WallpaperInfo mInfo;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001151 IWallpaperService mService;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001152 WallpaperData mWallpaper;
wilsonshihde93f492018-11-01 21:23:40 +08001153 final int mClientUid;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001154 IRemoteCallback mReply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155
Adrian Roosc3f915e2016-09-06 11:40:53 -07001156 private Runnable mResetRunnable = () -> {
1157 synchronized (mLock) {
Christopher Tate762dfd12016-10-10 17:44:48 -07001158 if (mShuttingDown) {
1159 // Don't expect wallpaper services to relaunch during shutdown
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001160 if (DEBUG_LIVE) {
Christopher Tate762dfd12016-10-10 17:44:48 -07001161 Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
1162 }
1163 return;
1164 }
1165
Adrian Roosc3f915e2016-09-06 11:40:53 -07001166 if (!mWallpaper.wallpaperUpdating
1167 && mWallpaper.userId == mCurrentUserId) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001168 Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
1169 + ", reverting to built-in wallpaper!");
Adrian Roosc3f915e2016-09-06 11:40:53 -07001170 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
1171 null);
1172 }
1173 }
1174 };
1175
wilsonshihde93f492018-11-01 21:23:40 +08001176 WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) {
Dianne Hackborneb034652009-09-07 00:49:58 -07001177 mInfo = info;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001178 mWallpaper = wallpaper;
wilsonshihde93f492018-11-01 21:23:40 +08001179 mClientUid = clientUid;
1180 initDisplayState();
1181 }
1182
1183 private void initDisplayState() {
wilsonshiha282bf72018-11-30 12:48:05 +08001184 // Do not initialize fallback wallpaper
1185 if (!mWallpaper.equals(mFallbackWallpaper)) {
1186 if (supportsMultiDisplay(this)) {
1187 // The system wallpaper is image wallpaper or it can supports multiple displays.
1188 appendConnectorWithCondition(this::isUsableDisplay);
1189 } else {
1190 // The system wallpaper does not support multiple displays, so just attach it on
1191 // default display.
1192 mDisplayConnector.append(DEFAULT_DISPLAY,
1193 new DisplayConnector(DEFAULT_DISPLAY));
wilsonshihde93f492018-11-01 21:23:40 +08001194 }
1195 }
1196 }
1197
wilsonshiha282bf72018-11-30 12:48:05 +08001198 private void appendConnectorWithCondition(Predicate<Display> tester) {
1199 final Display[] displays = mDisplayManager.getDisplays();
1200 for (Display display : displays) {
1201 if (tester.test(display)) {
1202 final int displayId = display.getDisplayId();
wilsonshih674a4a02018-12-19 11:47:25 +08001203 final DisplayConnector connector = mDisplayConnector.get(displayId);
1204 if (connector == null) {
1205 mDisplayConnector.append(displayId,
1206 new DisplayConnector(displayId));
1207 }
wilsonshiha282bf72018-11-30 12:48:05 +08001208 }
1209 }
1210 }
1211
wilsonshihde93f492018-11-01 21:23:40 +08001212 private boolean isUsableDisplay(Display display) {
Andrii Kuliandd989612019-02-21 12:13:28 -08001213 if (display == null || !display.hasAccess(mClientUid)) {
1214 return false;
1215 }
1216 final int displayId = display.getDisplayId();
wilsonshih0d5792e2019-07-04 11:23:54 +08001217 if (displayId == DEFAULT_DISPLAY) {
1218 return true;
1219 }
1220
1221 final long ident = Binder.clearCallingIdentity();
1222 try {
1223 return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
1224 } finally {
1225 Binder.restoreCallingIdentity(ident);
1226 }
wilsonshihde93f492018-11-01 21:23:40 +08001227 }
1228
1229 void forEachDisplayConnector(Consumer<DisplayConnector> action) {
1230 for (int i = mDisplayConnector.size() - 1; i >= 0; i--) {
wilsonshih81e10a72018-11-15 10:54:21 +08001231 final DisplayConnector connector = mDisplayConnector.valueAt(i);
wilsonshihde93f492018-11-01 21:23:40 +08001232 action.accept(connector);
1233 }
1234 }
1235
wilsonshih81e10a72018-11-15 10:54:21 +08001236 int getConnectedEngineSize() {
1237 int engineSize = 0;
1238 for (int i = mDisplayConnector.size() - 1; i >= 0; i--) {
1239 final DisplayConnector connector = mDisplayConnector.valueAt(i);
1240 if (connector.mEngine != null) engineSize++;
1241 }
1242 return engineSize;
1243 }
1244
wilsonshihde93f492018-11-01 21:23:40 +08001245 DisplayConnector getDisplayConnectorOrCreate(int displayId) {
1246 DisplayConnector connector = mDisplayConnector.get(displayId);
1247 if (connector == null) {
1248 final Display display = mDisplayManager.getDisplay(displayId);
1249 if (isUsableDisplay(display)) {
1250 connector = new DisplayConnector(displayId);
1251 mDisplayConnector.append(displayId, connector);
1252 }
1253 }
1254 return connector;
1255 }
1256
wilsonshiha282bf72018-11-30 12:48:05 +08001257 boolean containsDisplay(int displayId) {
1258 return mDisplayConnector.get(displayId) != null;
1259 }
1260
wilsonshihde93f492018-11-01 21:23:40 +08001261 void removeDisplayConnector(int displayId) {
1262 final DisplayConnector connector = mDisplayConnector.get(displayId);
1263 if (connector != null) {
1264 mDisplayConnector.remove(displayId);
1265 }
Dianne Hackborneb034652009-09-07 00:49:58 -07001266 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001267
1268 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001269 public void onServiceConnected(ComponentName name, IBinder service) {
1270 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001271 if (mWallpaper.connection == this) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001272 mService = IWallpaperService.Stub.asInterface(service);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001273 attachServiceLocked(this, mWallpaper);
Dianne Hackborneb034652009-09-07 00:49:58 -07001274 // XXX should probably do saveSettingsLocked() later
1275 // when we have an engine, but I'm not sure about
1276 // locking there and anyway we always need to be able to
1277 // recover if there is something wrong.
wilsonshiha282bf72018-11-30 12:48:05 +08001278 if (!mWallpaper.equals(mFallbackWallpaper)) {
1279 saveSettingsLocked(mWallpaper.userId);
1280 }
Adrian Roosc3f915e2016-09-06 11:40:53 -07001281 FgThread.getHandler().removeCallbacks(mResetRunnable);
wilsonshihb8753022019-10-09 20:50:44 +08001282 mContext.getMainThreadHandler().removeCallbacks(this::tryToRebind);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001283 }
1284 }
1285 }
1286
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001287 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001288 public void onServiceDisconnected(ComponentName name) {
1289 synchronized (mLock) {
Christopher Tatec349e59f2017-05-05 17:37:43 -07001290 Slog.w(TAG, "Wallpaper service gone: " + name);
1291 if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
1292 Slog.e(TAG, "Does not match expected wallpaper component "
1293 + mWallpaper.wallpaperComponent);
1294 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001295 mService = null;
wilsonshihde93f492018-11-01 21:23:40 +08001296 forEachDisplayConnector(connector -> connector.mEngine = null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001297 if (mWallpaper.connection == this) {
Christopher Tatec349e59f2017-05-05 17:37:43 -07001298 // There is an inherent ordering race between this callback and the
1299 // package monitor that receives notice that a package is being updated,
1300 // so we cannot quite trust at this moment that we know for sure that
1301 // this is not an update. If we think this is a genuine non-update
1302 // wallpaper outage, we do our "wait for reset" work as a continuation,
1303 // a short time in the future, specifically to allow any pending package
1304 // update message on this same looper thread to be processed.
1305 if (!mWallpaper.wallpaperUpdating) {
1306 mContext.getMainThreadHandler().postDelayed(() -> processDisconnect(this),
1307 1000);
1308 }
1309 }
1310 }
1311 }
1312
Tetsutoki Shiozawa06919212018-02-02 14:18:43 +09001313 public void scheduleTimeoutLocked() {
1314 // If we didn't reset it right away, do so after we couldn't connect to
1315 // it for an extended amount of time to avoid having a black wallpaper.
1316 final Handler fgHandler = FgThread.getHandler();
1317 fgHandler.removeCallbacks(mResetRunnable);
1318 fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
1319 if (DEBUG_LIVE) {
wilsonshihde93f492018-11-01 21:23:40 +08001320 Slog.i(TAG,
1321 "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
Tetsutoki Shiozawa06919212018-02-02 14:18:43 +09001322 }
1323 }
1324
wilsonshihb8753022019-10-09 20:50:44 +08001325 private void tryToRebind() {
1326 synchronized (mLock) {
1327 if (mWallpaper.wallpaperUpdating) {
1328 return;
1329 }
1330 final ComponentName wpService = mWallpaper.wallpaperComponent;
1331 // The broadcast of package update could be delayed after service disconnected. Try
1332 // to re-bind the service for 10 seconds.
1333 if (bindWallpaperComponentLocked(
1334 wpService, true, false, mWallpaper, null)) {
1335 mWallpaper.connection.scheduleTimeoutLocked();
1336 } else if (SystemClock.uptimeMillis() - mWallpaper.lastDiedTime
1337 < WALLPAPER_RECONNECT_TIMEOUT_MS) {
1338 // Bind fail without timeout, schedule rebind
1339 Slog.w(TAG, "Rebind fail! Try again later");
1340 mContext.getMainThreadHandler().postDelayed(this::tryToRebind, 1000);
1341 } else {
1342 // Timeout
1343 Slog.w(TAG, "Reverting to built-in wallpaper!");
1344 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
1345 final String flattened = wpService.flattenToString();
1346 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
1347 flattened.substring(0, Math.min(flattened.length(),
1348 MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
1349 }
1350 }
1351 }
1352
Christopher Tatec349e59f2017-05-05 17:37:43 -07001353 private void processDisconnect(final ServiceConnection connection) {
1354 synchronized (mLock) {
1355 // The wallpaper disappeared. If this isn't a system-default one, track
1356 // crashes and fall back to default if it continues to misbehave.
1357 if (connection == mWallpaper.connection) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001358 final ComponentName wpService = mWallpaper.wallpaperComponent;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001359 if (!mWallpaper.wallpaperUpdating
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001360 && mWallpaper.userId == mCurrentUserId
1361 && !Objects.equals(mDefaultWallpaperComponent, wpService)
1362 && !Objects.equals(mImageWallpaper, wpService)) {
Selim Cinekebebadb2014-03-05 22:17:26 +01001363 // There is a race condition which causes
1364 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is
1365 // currently updating since the broadcast notifying us is async.
1366 // This race is overcome by the general rule that we only reset the
1367 // wallpaper if its service was shut down twice
1368 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
1369 if (mWallpaper.lastDiedTime != 0
1370 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
Christopher Tatec349e59f2017-05-05 17:37:43 -07001371 > SystemClock.uptimeMillis()) {
Selim Cinekebebadb2014-03-05 22:17:26 +01001372 Slog.w(TAG, "Reverting to built-in wallpaper!");
Christopher Tateedf7d042016-03-29 18:24:25 -07001373 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Selim Cinekebebadb2014-03-05 22:17:26 +01001374 } else {
1375 mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
wilsonshihb8753022019-10-09 20:50:44 +08001376 tryToRebind();
Selim Cinekebebadb2014-03-05 22:17:26 +01001377 }
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001378 }
Christopher Tatec349e59f2017-05-05 17:37:43 -07001379 } else {
1380 if (DEBUG_LIVE) {
1381 Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring");
1382 }
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001383 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001384 }
1385 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001386
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001387 /**
1388 * Called by a live wallpaper if its colors have changed.
1389 * @param primaryColors representation of wallpaper primary colors
wilsonshih36597d42018-12-05 18:56:39 +08001390 * @param displayId for which display
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001391 */
1392 @Override
wilsonshih36597d42018-12-05 18:56:39 +08001393 public void onWallpaperColorsChanged(WallpaperColors primaryColors, int displayId) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001394 int which;
1395 synchronized (mLock) {
1396 // Do not broadcast changes on ImageWallpaper since it's handled
1397 // internally by this class.
1398 if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
1399 return;
1400 }
1401
1402 mWallpaper.primaryColors = primaryColors;
1403
1404 // Live wallpapers always are system wallpapers.
1405 which = FLAG_SYSTEM;
wilsonshih36597d42018-12-05 18:56:39 +08001406 // It's also the lock screen wallpaper when we don't have a bitmap in there.
1407 if (displayId == DEFAULT_DISPLAY) {
1408 final WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
1409 if (lockedWallpaper == null) {
1410 which |= FLAG_LOCK;
1411 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001412 }
1413 }
1414 if (which != 0) {
wilsonshih36597d42018-12-05 18:56:39 +08001415 notifyWallpaperColorsChangedOnDisplay(mWallpaper, which, displayId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001416 }
1417 }
1418
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001419 @Override
wilsonshihde93f492018-11-01 21:23:40 +08001420 public void attachEngine(IWallpaperEngine engine, int displayId) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001421 synchronized (mLock) {
wilsonshihde93f492018-11-01 21:23:40 +08001422 final DisplayConnector connector = getDisplayConnectorOrCreate(displayId);
1423 if (connector == null) {
Michael Wright5203a8b2013-10-03 14:16:42 -07001424 try {
wilsonshihde93f492018-11-01 21:23:40 +08001425 engine.destroy();
Michael Wright5203a8b2013-10-03 14:16:42 -07001426 } catch (RemoteException e) {
wilsonshihde93f492018-11-01 21:23:40 +08001427 Slog.w(TAG, "Failed to destroy engine", e);
Michael Wright5203a8b2013-10-03 14:16:42 -07001428 }
wilsonshihde93f492018-11-01 21:23:40 +08001429 return;
Michael Wright5203a8b2013-10-03 14:16:42 -07001430 }
wilsonshihde93f492018-11-01 21:23:40 +08001431 connector.mEngine = engine;
1432 connector.ensureStatusHandled();
1433
1434 // TODO(multi-display) TBD.
1435 if (mInfo != null && mInfo.supportsAmbientMode() && displayId == DEFAULT_DISPLAY) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001436 try {
Lucas Dupin4c8c3272018-11-06 17:47:48 -08001437 connector.mEngine.setInAmbientMode(mInAmbientMode, 0L /* duration */);
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001438 } catch (RemoteException e) {
1439 Slog.w(TAG, "Failed to set ambient mode state", e);
1440 }
1441 }
wilsonshih36597d42018-12-05 18:56:39 +08001442 try {
1443 // This will trigger onComputeColors in the wallpaper engine.
1444 // It's fine to be locked in here since the binder is oneway.
1445 connector.mEngine.requestWallpaperColors();
1446 } catch (RemoteException e) {
1447 Slog.w(TAG, "Failed to request wallpaper colors", e);
Lucas Dupin50ba9912017-07-14 11:55:05 -07001448 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001449 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001450 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001451
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001452 @Override
1453 public void engineShown(IWallpaperEngine engine) {
1454 synchronized (mLock) {
1455 if (mReply != null) {
1456 long ident = Binder.clearCallingIdentity();
1457 try {
1458 mReply.sendResult(null);
1459 } catch (RemoteException e) {
1460 Binder.restoreCallingIdentity(ident);
1461 }
1462 mReply = null;
1463 }
1464 }
1465 }
1466
1467 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001468 public ParcelFileDescriptor setWallpaper(String name) {
1469 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001470 if (mWallpaper.connection == this) {
Christopher Tatead3c2592016-01-20 18:13:17 -08001471 return updateWallpaperBitmapLocked(name, mWallpaper, null);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001472 }
1473 return null;
1474 }
1475 }
1476 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001477
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001478 class MyPackageMonitor extends PackageMonitor {
1479 @Override
1480 public void onPackageUpdateFinished(String packageName, int uid) {
1481 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001482 if (mCurrentUserId != getChangingUserId()) {
1483 return;
1484 }
1485 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1486 if (wallpaper != null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001487 final ComponentName wpService = wallpaper.wallpaperComponent;
1488 if (wpService != null && wpService.getPackageName().equals(packageName)) {
1489 if (DEBUG_LIVE) {
1490 Slog.i(TAG, "Wallpaper " + wpService + " update has finished");
1491 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001492 wallpaper.wallpaperUpdating = false;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001493 clearWallpaperComponentLocked(wallpaper);
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001494 if (!bindWallpaperComponentLocked(wpService, false, false,
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001495 wallpaper, null)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001496 Slog.w(TAG, "Wallpaper " + wpService
1497 + " no longer available; reverting to default");
Christopher Tateedf7d042016-03-29 18:24:25 -07001498 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001499 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001500 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001501 }
1502 }
1503 }
1504
1505 @Override
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001506 public void onPackageModified(String packageName) {
1507 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001508 if (mCurrentUserId != getChangingUserId()) {
1509 return;
1510 }
1511 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1512 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001513 if (wallpaper.wallpaperComponent == null
1514 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001515 return;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001516 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001517 doPackagesChangedLocked(true, wallpaper);
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001518 }
1519 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001520 }
1521
1522 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001523 public void onPackageUpdateStarted(String packageName, int uid) {
1524 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001525 if (mCurrentUserId != getChangingUserId()) {
1526 return;
1527 }
1528 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1529 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001530 if (wallpaper.wallpaperComponent != null
1531 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001532 if (DEBUG_LIVE) {
1533 Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent
1534 + " is updating");
1535 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001536 wallpaper.wallpaperUpdating = true;
Adrian Roosc3f915e2016-09-06 11:40:53 -07001537 if (wallpaper.connection != null) {
1538 FgThread.getHandler().removeCallbacks(
1539 wallpaper.connection.mResetRunnable);
1540 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001541 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001542 }
1543 }
1544 }
1545
1546 @Override
1547 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001548 synchronized (mLock) {
1549 boolean changed = false;
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001550 if (mCurrentUserId != getChangingUserId()) {
1551 return false;
1552 }
1553 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1554 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001555 boolean res = doPackagesChangedLocked(doit, wallpaper);
1556 changed |= res;
1557 }
1558 return changed;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001559 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001560 }
1561
1562 @Override
1563 public void onSomePackagesChanged() {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001564 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001565 if (mCurrentUserId != getChangingUserId()) {
1566 return;
1567 }
1568 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1569 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001570 doPackagesChangedLocked(true, wallpaper);
1571 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001572 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001573 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001574
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001575 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001576 boolean changed = false;
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001577 if (wallpaper.wallpaperComponent != null) {
1578 int change = isPackageDisappearing(wallpaper.wallpaperComponent
1579 .getPackageName());
1580 if (change == PACKAGE_PERMANENT_CHANGE
1581 || change == PACKAGE_TEMPORARY_CHANGE) {
1582 changed = true;
1583 if (doit) {
1584 Slog.w(TAG, "Wallpaper uninstalled, removing: "
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001585 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001586 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001587 }
1588 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001589 }
1590 if (wallpaper.nextWallpaperComponent != null) {
1591 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
1592 .getPackageName());
1593 if (change == PACKAGE_PERMANENT_CHANGE
1594 || change == PACKAGE_TEMPORARY_CHANGE) {
1595 wallpaper.nextWallpaperComponent = null;
1596 }
1597 }
1598 if (wallpaper.wallpaperComponent != null
1599 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
1600 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001601 mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
1602 PackageManager.MATCH_DIRECT_BOOT_AWARE
1603 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001604 } catch (NameNotFoundException e) {
1605 Slog.w(TAG, "Wallpaper component gone, removing: "
1606 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001607 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001608 }
1609 }
1610 if (wallpaper.nextWallpaperComponent != null
1611 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
1612 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001613 mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
1614 PackageManager.MATCH_DIRECT_BOOT_AWARE
1615 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001616 } catch (NameNotFoundException e) {
1617 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001618 }
1619 }
1620 return changed;
1621 }
1622 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001623
wilsonshih999ec102019-05-17 18:47:50 +08001624 @VisibleForTesting
1625 WallpaperData getCurrentWallpaperData(@SetWallpaperFlags int which, int userId) {
1626 synchronized (mLock) {
1627 final SparseArray<WallpaperData> wallpaperDataMap =
1628 which == FLAG_SYSTEM ? mWallpaperMap : mLockWallpaperMap;
1629 return wallpaperDataMap.get(userId);
1630 }
1631 }
1632
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001633 public WallpaperManagerService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001634 if (DEBUG) Slog.v(TAG, "WallpaperService startup");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 mContext = context;
Christopher Tate762dfd12016-10-10 17:44:48 -07001636 mShuttingDown = false;
Justin Koh29c30162014-09-05 17:10:10 -07001637 mImageWallpaper = ComponentName.unflattenFromString(
1638 context.getResources().getString(R.string.image_wallpaper_component));
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001639 mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context);
Andrii Kuliandd989612019-02-21 12:13:28 -08001640 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001641 mIPackageManager = AppGlobals.getPackageManager();
Benjamin Franzf3ece362015-02-11 10:51:10 +00001642 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
wilsonshihde93f492018-11-01 21:23:40 +08001643 mDisplayManager = mContext.getSystemService(DisplayManager.class);
1644 mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001645 mMonitor = new MyPackageMonitor();
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001646 mColorsChangedListeners = new SparseArray<>();
wilsonshih643bf132019-02-27 12:49:19 +08001647
1648 LocalServices.addService(WallpaperManagerInternal.class, new LocalService());
1649 }
1650
1651 private final class LocalService extends WallpaperManagerInternal {
1652 @Override
1653 public void onDisplayReady(int displayId) {
1654 onDisplayReadyInternal(displayId);
1655 }
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001656 }
1657
1658 void initialize() {
1659 mMonitor.register(mContext, null, UserHandle.ALL, true);
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001660 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
Christopher Tatef717b932017-09-11 15:52:54 -07001661
1662 // Initialize state from the persistent store, then guarantee that the
1663 // WallpaperData for the system imagery is instantiated & active, creating
1664 // it from defaults if necessary.
Christopher Tated7faf532016-02-25 12:43:38 -08001665 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatef717b932017-09-11 15:52:54 -07001666 getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001668
wilsonshih999ec102019-05-17 18:47:50 +08001669 File getWallpaperDir(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07001670 return Environment.getUserSystemDirectory(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001671 }
1672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 @Override
1674 protected void finalize() throws Throwable {
1675 super.finalize();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001676 for (int i = 0; i < mWallpaperMap.size(); i++) {
1677 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
1678 wallpaper.wallpaperObserver.stopWatching();
1679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 }
Amith Yamasani13593602012-03-22 16:16:17 -07001681
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001682 void systemReady() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001683 if (DEBUG) Slog.v(TAG, "systemReady");
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001684 initialize();
1685
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001686 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001687 // If we think we're going to be using the system image wallpaper imagery, make
1688 // sure we have something to render
1689 if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
1690 // No crop file? Make sure we've finished the processing sequence if necessary
1691 if (!wallpaper.cropExists()) {
1692 if (DEBUG) {
1693 Slog.i(TAG, "No crop; regenerating from source");
1694 }
1695 generateCrop(wallpaper);
1696 }
1697 // Still nothing? Fall back to default.
1698 if (!wallpaper.cropExists()) {
1699 if (DEBUG) {
1700 Slog.i(TAG, "Unable to regenerate crop; resetting");
1701 }
Christopher Tateedf7d042016-03-29 18:24:25 -07001702 clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001703 }
1704 } else {
1705 if (DEBUG) {
1706 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
1707 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001708 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001709
Amith Yamasani13593602012-03-22 16:16:17 -07001710 IntentFilter userFilter = new IntentFilter();
Amith Yamasani13593602012-03-22 16:16:17 -07001711 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1712 mContext.registerReceiver(new BroadcastReceiver() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001713 @Override
Amith Yamasani13593602012-03-22 16:16:17 -07001714 public void onReceive(Context context, Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001715 final String action = intent.getAction();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001716 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani756901d2012-10-12 12:30:07 -07001717 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1718 UserHandle.USER_NULL));
Amith Yamasani13593602012-03-22 16:16:17 -07001719 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001720 }
Amith Yamasani13593602012-03-22 16:16:17 -07001721 }, userFilter);
Amith Yamasani756901d2012-10-12 12:30:07 -07001722
Christopher Tate762dfd12016-10-10 17:44:48 -07001723 final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
1724 mContext.registerReceiver(new BroadcastReceiver() {
1725 @Override
1726 public void onReceive(Context context, Intent intent) {
1727 if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
1728 if (DEBUG) {
1729 Slog.i(TAG, "Shutting down");
1730 }
1731 synchronized (mLock) {
1732 mShuttingDown = true;
1733 }
1734 }
1735 }
1736 }, shutdownFilter);
1737
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001738 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001739 ActivityManager.getService().registerUserSwitchObserver(
Sudheer Shanka2c4522c2016-08-27 20:53:28 -07001740 new UserSwitchObserver() {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001741 @Override
1742 public void onUserSwitching(int newUserId, IRemoteCallback reply) {
1743 switchUser(newUserId, reply);
1744 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001745 }, TAG);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001746 } catch (RemoteException e) {
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001747 e.rethrowAsRuntimeException();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001748 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001749 }
1750
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08001751 /** Called by SystemBackupAgent */
1752 public String getName() {
1753 // Verify caller is the system
1754 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
1755 throw new RuntimeException("getName() can only be called from the system process");
1756 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001757 synchronized (mLock) {
1758 return mWallpaperMap.get(0).name;
1759 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001760 }
1761
Christopher Tatebe132e62016-02-10 12:59:49 -08001762 void stopObserver(WallpaperData wallpaper) {
1763 if (wallpaper != null) {
1764 if (wallpaper.wallpaperObserver != null) {
1765 wallpaper.wallpaperObserver.stopWatching();
1766 wallpaper.wallpaperObserver = null;
Amith Yamasani13593602012-03-22 16:16:17 -07001767 }
Amith Yamasani756901d2012-10-12 12:30:07 -07001768 }
1769 }
1770
Christopher Tatebe132e62016-02-10 12:59:49 -08001771 void stopObserversLocked(int userId) {
1772 stopObserver(mWallpaperMap.get(userId));
1773 stopObserver(mLockWallpaperMap.get(userId));
1774 mWallpaperMap.remove(userId);
1775 mLockWallpaperMap.remove(userId);
1776 }
1777
Daichi Hirono4bbf8522017-12-06 10:34:18 +09001778 @Override
1779 public void onBootPhase(int phase) {
1780 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1781 systemReady();
1782 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1783 switchUser(UserHandle.USER_SYSTEM, null);
1784 }
1785 }
1786
1787 @Override
1788 public void onUnlockUser(final int userId) {
Felipe Leme4e2cbb52019-12-02 16:46:49 -08001789 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
1790 t.traceBegin("on-unlock-user-" + userId);
1791 try {
1792 synchronized (mLock) {
1793 if (mCurrentUserId == userId) {
1794 if (mWaitingForUnlock) {
1795 // the desired wallpaper is not direct-boot aware, load it now
1796 final WallpaperData systemWallpaper =
1797 getWallpaperSafeLocked(userId, FLAG_SYSTEM);
1798 switchWallpaper(systemWallpaper, null);
1799 notifyCallbacksLocked(systemWallpaper);
1800 }
Christopher Tate190e8532016-07-11 11:35:34 -07001801
Felipe Leme4e2cbb52019-12-02 16:46:49 -08001802 // Make sure that the SELinux labeling of all the relevant files is correct.
1803 // This corrects for mislabeling bugs that might have arisen from move-to
1804 // operations involving the wallpaper files. This isn't timing-critical,
1805 // so we do it in the background to avoid holding up the user unlock operation.
1806 if (!mUserRestorecon.get(userId)) {
1807 mUserRestorecon.put(userId, true);
1808 Runnable relabeler = () -> {
Christopher Tate38a5dc32016-07-20 15:10:18 -07001809 final File wallpaperDir = getWallpaperDir(userId);
1810 for (String filename : sPerUserFiles) {
1811 File f = new File(wallpaperDir, filename);
1812 if (f.exists()) {
1813 SELinux.restorecon(f);
1814 }
Christopher Tate190e8532016-07-11 11:35:34 -07001815 }
Felipe Leme4e2cbb52019-12-02 16:46:49 -08001816 };
1817 BackgroundThread.getHandler().post(relabeler);
1818 }
Christopher Tate38a5dc32016-07-20 15:10:18 -07001819 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001820 }
Felipe Leme4e2cbb52019-12-02 16:46:49 -08001821 } finally {
1822 t.traceEnd();
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001823 }
1824 }
1825
Amith Yamasani756901d2012-10-12 12:30:07 -07001826 void onRemoveUser(int userId) {
1827 if (userId < 1) return;
Christopher Tatebe132e62016-02-10 12:59:49 -08001828
1829 final File wallpaperDir = getWallpaperDir(userId);
Amith Yamasani756901d2012-10-12 12:30:07 -07001830 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001831 stopObserversLocked(userId);
1832 for (String filename : sPerUserFiles) {
1833 new File(wallpaperDir, filename).delete();
1834 }
wilsonshiha282bf72018-11-30 12:48:05 +08001835 mUserRestorecon.delete(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001836 }
1837 }
1838
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001839 void switchUser(int userId, IRemoteCallback reply) {
Felipe Leme4e2cbb52019-12-02 16:46:49 -08001840 TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG);
1841 t.traceBegin("switch-user-" + userId);
1842 try {
1843 final WallpaperData systemWallpaper;
1844 final WallpaperData lockWallpaper;
1845 synchronized (mLock) {
1846 if (mCurrentUserId == userId) {
1847 return;
1848 }
1849 mCurrentUserId = userId;
1850 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
1851 final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
1852 lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
1853 // Not started watching yet, in case wallpaper data was loaded for other reasons.
1854 if (systemWallpaper.wallpaperObserver == null) {
1855 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
1856 systemWallpaper.wallpaperObserver.startWatching();
1857 }
1858 switchWallpaper(systemWallpaper, reply);
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001859 }
Lucas Dupin9272d452017-09-14 14:15:42 -07001860
Felipe Leme4e2cbb52019-12-02 16:46:49 -08001861 // Offload color extraction to another thread since switchUser will be called
1862 // from the main thread.
1863 FgThread.getHandler().post(() -> {
1864 notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
1865 notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
1866 notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
1867 });
1868 } finally {
1869 t.traceEnd();
1870 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001871 }
1872
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001873 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001874 synchronized (mLock) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001875 mWaitingForUnlock = false;
1876 final ComponentName cname = wallpaper.wallpaperComponent != null ?
1877 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
1878 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
1879 // We failed to bind the desired wallpaper, but that might
1880 // happen if the wallpaper isn't direct-boot aware
1881 ServiceInfo si = null;
1882 try {
1883 si = mIPackageManager.getServiceInfo(cname,
1884 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
1885 } catch (RemoteException ignored) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001886 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001887
1888 if (si == null) {
1889 Slog.w(TAG, "Failure starting previous wallpaper; clearing");
1890 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
1891 } else {
1892 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
1893 // We might end up persisting the current wallpaper data
1894 // while locked, so pretend like the component was actually
1895 // bound into place
1896 wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
wilsonshih999ec102019-05-17 18:47:50 +08001897 final WallpaperData fallback =
1898 new WallpaperData(wallpaper.userId, getWallpaperDir(wallpaper.userId),
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001899 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
wilsonshih81e10a72018-11-15 10:54:21 +08001900 ensureSaneWallpaperData(fallback, DEFAULT_DISPLAY);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001901 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
1902 mWaitingForUnlock = true;
1903 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001904 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001905 }
1906 }
1907
Christopher Tatebe132e62016-02-10 12:59:49 -08001908 @Override
1909 public void clearWallpaper(String callingPackage, int which, int userId) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001910 if (DEBUG) Slog.v(TAG, "clearWallpaper");
Benjamin Franzf3ece362015-02-11 10:51:10 +00001911 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tate98d609c2016-05-18 17:31:58 -07001912 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001913 return;
1914 }
Christopher Tatee409f0e2016-03-21 14:53:15 -07001915 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1916 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001917
Lucas Dupin41f69422017-05-03 15:26:22 -07001918 WallpaperData data = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001919 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001920 clearWallpaperLocked(false, which, userId, null);
Lucas Dupin41f69422017-05-03 15:26:22 -07001921
1922 if (which == FLAG_LOCK) {
1923 data = mLockWallpaperMap.get(userId);
1924 }
1925 if (which == FLAG_SYSTEM || data == null) {
1926 data = mWallpaperMap.get(userId);
1927 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001928 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001929
1930 // When clearing a wallpaper, broadcast new valid colors
Lucas Dupin41f69422017-05-03 15:26:22 -07001931 if (data != null) {
1932 notifyWallpaperColorsChanged(data, which);
wilsonshih36597d42018-12-05 18:56:39 +08001933 notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
Lucas Dupin41f69422017-05-03 15:26:22 -07001934 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001935 }
1936
Christopher Tatebe132e62016-02-10 12:59:49 -08001937 void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
Christopher Tateedf7d042016-03-29 18:24:25 -07001938 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tate105540d2018-03-21 13:03:09 -07001939 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
Christopher Tatebe132e62016-02-10 12:59:49 -08001940 }
1941
1942 WallpaperData wallpaper = null;
Christopher Tateedf7d042016-03-29 18:24:25 -07001943 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001944 wallpaper = mLockWallpaperMap.get(userId);
1945 if (wallpaper == null) {
1946 // It's already gone; we're done.
Christopher Tate79a24572016-03-02 14:42:44 -08001947 if (DEBUG) {
1948 Slog.i(TAG, "Lock wallpaper already cleared");
1949 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001950 return;
1951 }
1952 } else {
1953 wallpaper = mWallpaperMap.get(userId);
1954 if (wallpaper == null) {
1955 // Might need to bring it in the first time to establish our rewrite
Christopher Tated7faf532016-02-25 12:43:38 -08001956 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08001957 wallpaper = mWallpaperMap.get(userId);
1958 }
1959 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001960 if (wallpaper == null) {
1961 return;
1962 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001963
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001964 final long ident = Binder.clearCallingIdentity();
1965 try {
Christopher Tatebe132e62016-02-10 12:59:49 -08001966 if (wallpaper.wallpaperFile.exists()) {
1967 wallpaper.wallpaperFile.delete();
1968 wallpaper.cropFile.delete();
Christopher Tateedf7d042016-03-29 18:24:25 -07001969 if (which == FLAG_LOCK) {
Christopher Tate79a24572016-03-02 14:42:44 -08001970 mLockWallpaperMap.remove(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001971 final IWallpaperManagerCallback cb = mKeyguardListener;
1972 if (cb != null) {
Christopher Tate79a24572016-03-02 14:42:44 -08001973 if (DEBUG) {
1974 Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
1975 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001976 try {
1977 cb.onWallpaperChanged();
1978 } catch (RemoteException e) {
1979 // Oh well it went away; no big deal
1980 }
1981 }
Christopher Tate79a24572016-03-02 14:42:44 -08001982 saveSettingsLocked(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001983 return;
1984 }
1985 }
1986
Christopher Tateecd827a2014-09-05 17:42:34 -07001987 RuntimeException e = null;
1988 try {
Lucas Dupin75ec3792017-06-29 14:07:18 -07001989 wallpaper.primaryColors = null;
Christopher Tateecd827a2014-09-05 17:42:34 -07001990 wallpaper.imageWallpaperPending = false;
1991 if (userId != mCurrentUserId) return;
1992 if (bindWallpaperComponentLocked(defaultFailed
1993 ? mImageWallpaper
1994 : null, true, false, wallpaper, reply)) {
1995 return;
1996 }
1997 } catch (IllegalArgumentException e1) {
1998 e = e1;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001999 }
Christopher Tateecd827a2014-09-05 17:42:34 -07002000
2001 // This can happen if the default wallpaper component doesn't
2002 // exist. This should be a system configuration problem, but
2003 // let's not let it crash the system and just live with no
2004 // wallpaper.
2005 Slog.e(TAG, "Default wallpaper component not found!", e);
2006 clearWallpaperComponentLocked(wallpaper);
2007 if (reply != null) {
2008 try {
2009 reply.sendResult(null);
2010 } catch (RemoteException e1) {
2011 }
2012 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08002013 } finally {
2014 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002016 }
2017
2018 public boolean hasNamedWallpaper(String name) {
2019 synchronized (mLock) {
Amith Yamasani6474c4c2012-10-04 14:55:42 -07002020 List<UserInfo> users;
2021 long ident = Binder.clearCallingIdentity();
2022 try {
2023 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
2024 } finally {
2025 Binder.restoreCallingIdentity(ident);
2026 }
2027 for (UserInfo user: users) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00002028 // ignore managed profiles
2029 if (user.isManagedProfile()) {
2030 continue;
2031 }
Amith Yamasani6474c4c2012-10-04 14:55:42 -07002032 WallpaperData wd = mWallpaperMap.get(user.id);
2033 if (wd == null) {
2034 // User hasn't started yet, so load her settings to peek at the wallpaper
Christopher Tated7faf532016-02-25 12:43:38 -08002035 loadSettingsLocked(user.id, false);
Amith Yamasani6474c4c2012-10-04 14:55:42 -07002036 wd = mWallpaperMap.get(user.id);
2037 }
2038 if (wd != null && name.equals(wd.name)) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002039 return true;
2040 }
2041 }
2042 }
2043 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 }
2045
wilsonshih81e10a72018-11-15 10:54:21 +08002046 private boolean isValidDisplay(int displayId) {
2047 return mDisplayManager.getDisplay(displayId) != null;
2048 }
2049
2050 /**
2051 * Sets the dimension hint for the wallpaper. These hints indicate the desired
2052 * minimum width and height for the wallpaper in a particular display.
2053 */
2054 public void setDimensionHints(int width, int height, String callingPackage, int displayId)
Benjamin Franzf3ece362015-02-11 10:51:10 +00002055 throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00002057 if (!isWallpaperSupported(callingPackage)) {
2058 return;
2059 }
Ahan Wu32c6a7c2019-10-03 12:36:59 +08002060
2061 // Make sure both width and height are not larger than max texture size.
2062 width = Math.min(width, GLHelper.getMaxTextureSize());
2063 height = Math.min(height, GLHelper.getMaxTextureSize());
2064
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002065 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002066 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07002067 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002068 if (width <= 0 || height <= 0) {
2069 throw new IllegalArgumentException("width and height must be > 0");
2070 }
2071
wilsonshih81e10a72018-11-15 10:54:21 +08002072 if (!isValidDisplay(displayId)) {
2073 throw new IllegalArgumentException("Cannot find display with id=" + displayId);
2074 }
2075
wilsonshiha282bf72018-11-30 12:48:05 +08002076 final DisplayData wpdData = getDisplayDataOrCreate(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +08002077 if (width != wpdData.mWidth || height != wpdData.mHeight) {
2078 wpdData.mWidth = width;
2079 wpdData.mHeight = height;
2080 if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002081 if (mCurrentUserId != userId) return; // Don't change the properties now
2082 if (wallpaper.connection != null) {
wilsonshih81e10a72018-11-15 10:54:21 +08002083 final WallpaperConnection.DisplayConnector connector = wallpaper.connection
2084 .getDisplayConnectorOrCreate(displayId);
2085 final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
wilsonshihde93f492018-11-01 21:23:40 +08002086 if (engine != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -07002087 try {
wilsonshihde93f492018-11-01 21:23:40 +08002088 engine.setDesiredSize(width, height);
Dianne Hackborn284ac932009-08-28 10:34:25 -07002089 } catch (RemoteException e) {
2090 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002091 notifyCallbacksLocked(wallpaper);
wilsonshih81e10a72018-11-15 10:54:21 +08002092 } else if (wallpaper.connection.mService != null && connector != null) {
Michael Wright5203a8b2013-10-03 14:16:42 -07002093 // We've attached to the service but the engine hasn't attached back to us
2094 // yet. This means it will be created with the previous dimensions, so we
2095 // need to update it to the new dimensions once it attaches.
wilsonshih81e10a72018-11-15 10:54:21 +08002096 connector.mDimensionsChanged = true;
Dianne Hackborn284ac932009-08-28 10:34:25 -07002097 }
2098 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 }
2101 }
2102
wilsonshih81e10a72018-11-15 10:54:21 +08002103 /**
2104 * Returns the desired minimum width for the wallpaper in a particular display.
2105 */
2106 public int getWidthHint(int displayId) throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002107 synchronized (mLock) {
wilsonshih81e10a72018-11-15 10:54:21 +08002108 if (!isValidDisplay(displayId)) {
2109 throw new IllegalArgumentException("Cannot find display with id=" + displayId);
2110 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002111 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00002112 if (wallpaper != null) {
wilsonshiha282bf72018-11-30 12:48:05 +08002113 final DisplayData wpdData = getDisplayDataOrCreate(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +08002114 return wpdData.mWidth;
Benjamin Franzf3ece362015-02-11 10:51:10 +00002115 } else {
2116 return 0;
2117 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 }
2120
wilsonshih81e10a72018-11-15 10:54:21 +08002121 /**
2122 * Returns the desired minimum height for the wallpaper in a particular display.
2123 */
2124 public int getHeightHint(int displayId) throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002125 synchronized (mLock) {
wilsonshih81e10a72018-11-15 10:54:21 +08002126 if (!isValidDisplay(displayId)) {
2127 throw new IllegalArgumentException("Cannot find display with id=" + displayId);
2128 }
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002129 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00002130 if (wallpaper != null) {
wilsonshiha282bf72018-11-30 12:48:05 +08002131 final DisplayData wpdData = getDisplayDataOrCreate(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +08002132 return wpdData.mHeight;
Benjamin Franzf3ece362015-02-11 10:51:10 +00002133 } else {
2134 return 0;
2135 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 }
2138
wilsonshih81e10a72018-11-15 10:54:21 +08002139 /**
2140 * Sets extra padding that we would like the wallpaper to have outside of the display.
2141 */
2142 public void setDisplayPadding(Rect padding, String callingPackage, int displayId) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002143 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00002144 if (!isWallpaperSupported(callingPackage)) {
2145 return;
2146 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002147 synchronized (mLock) {
wilsonshih81e10a72018-11-15 10:54:21 +08002148 if (!isValidDisplay(displayId)) {
2149 throw new IllegalArgumentException("Cannot find display with id=" + displayId);
2150 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002151 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07002152 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002153 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
2154 throw new IllegalArgumentException("padding must be positive: " + padding);
2155 }
2156
wilsonshiha282bf72018-11-30 12:48:05 +08002157 final DisplayData wpdData = getDisplayDataOrCreate(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +08002158 if (!padding.equals(wpdData.mPadding)) {
2159 wpdData.mPadding.set(padding);
2160 if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002161 if (mCurrentUserId != userId) return; // Don't change the properties now
2162 if (wallpaper.connection != null) {
wilsonshih81e10a72018-11-15 10:54:21 +08002163 final WallpaperConnection.DisplayConnector connector = wallpaper.connection
2164 .getDisplayConnectorOrCreate(displayId);
2165 final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
wilsonshihde93f492018-11-01 21:23:40 +08002166 if (engine != null) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002167 try {
wilsonshihde93f492018-11-01 21:23:40 +08002168 engine.setDisplayPadding(padding);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002169 } catch (RemoteException e) {
2170 }
2171 notifyCallbacksLocked(wallpaper);
wilsonshih81e10a72018-11-15 10:54:21 +08002172 } else if (wallpaper.connection.mService != null && connector != null) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002173 // We've attached to the service but the engine hasn't attached back to us
2174 // yet. This means it will be created with the previous dimensions, so we
2175 // need to update it to the new dimensions once it attaches.
wilsonshih81e10a72018-11-15 10:54:21 +08002176 connector.mPaddingChanged = true;
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002177 }
2178 }
2179 }
2180 }
2181 }
2182
Santiago Etchebehere44a28312020-01-14 15:27:11 -08002183 /**
2184 * Called when the wallpaper needs to zoom out.
2185 *
2186 * @param zoom from 0 to 1 (inclusive) where 1 means fully zoomed out, 0 means fully zoomed in.
2187 * @param callingPackage package name calling this API.
2188 * @param displayId id of the display whose zoom is updating.
2189 */
2190 public void setWallpaperZoomOut(float zoom, String callingPackage, int displayId) {
2191 if (!isWallpaperSupported(callingPackage)) {
2192 return;
2193 }
2194 synchronized (mLock) {
2195 if (!isValidDisplay(displayId)) {
2196 throw new IllegalArgumentException("Cannot find display with id=" + displayId);
2197 }
2198 int userId = UserHandle.getCallingUserId();
2199 if (mCurrentUserId != userId) {
2200 return; // Don't change the properties now
2201 }
2202 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
2203 if (zoom < 0 || zoom > 1f) {
2204 throw new IllegalArgumentException("zoom must be between 0 and one: " + zoom);
2205 }
2206
2207 if (wallpaper.connection != null) {
2208 final WallpaperConnection.DisplayConnector connector = wallpaper.connection
2209 .getDisplayConnectorOrCreate(displayId);
2210 final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
2211 if (engine != null) {
2212 try {
2213 engine.setZoomOut(zoom);
2214 } catch (RemoteException e) {
2215 if (DEBUG) {
2216 Slog.w(TAG, "Couldn't set wallpaper zoom", e);
2217 }
2218 }
2219 }
2220 }
2221 }
2222 }
2223
Philip P. Moltmann41ff0f62019-11-15 10:55:52 -08002224 @Deprecated
Yorke Leedcd93cc2016-01-08 14:12:55 -08002225 @Override
Christopher Tate93252de2017-06-15 14:48:41 -07002226 public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
2227 final int which, Bundle outParams, int wallpaperUserId) {
Philip P. Moltmann41ff0f62019-11-15 10:55:52 -08002228 return getWallpaperWithFeature(callingPkg, null, cb, which, outParams, wallpaperUserId);
2229 }
2230
2231 @Override
2232 public ParcelFileDescriptor getWallpaperWithFeature(String callingPkg, String callingFeatureId,
2233 IWallpaperManagerCallback cb, final int which, Bundle outParams, int wallpaperUserId) {
Christopher Tate8a71c482017-08-14 16:45:03 -07002234 final int hasPrivilege = mContext.checkCallingOrSelfPermission(
2235 android.Manifest.permission.READ_WALLPAPER_INTERNAL);
2236 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
Jeff Sharkey859856d2019-03-25 11:44:11 -06002237 mContext.getSystemService(StorageManager.class).checkPermissionReadImages(true,
Philip P. Moltmann41ff0f62019-11-15 10:55:52 -08002238 Binder.getCallingPid(), Binder.getCallingUid(), callingPkg, callingFeatureId);
Christopher Tate8a71c482017-08-14 16:45:03 -07002239 }
Christopher Tate93252de2017-06-15 14:48:41 -07002240
Christopher Tatee409f0e2016-03-21 14:53:15 -07002241 wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2242 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08002243
Christopher Tateedf7d042016-03-29 18:24:25 -07002244 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002245 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
2246 }
2247
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002248 synchronized (mLock) {
Vadim Tryshev8cde0792016-02-19 17:02:15 -08002249 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07002250 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Vadim Tryshev8cde0792016-02-19 17:02:15 -08002251 WallpaperData wallpaper = whichSet.get(wallpaperUserId);
2252 if (wallpaper == null) {
Christopher Tatef717b932017-09-11 15:52:54 -07002253 // There is no established wallpaper imagery of this type (expected
2254 // only for lock wallpapers; a system WallpaperData is established at
2255 // user switch)
2256 return null;
Benjamin Franzf3ece362015-02-11 10:51:10 +00002257 }
wilsonshih81e10a72018-11-15 10:54:21 +08002258 // Only for default display.
wilsonshiha282bf72018-11-30 12:48:05 +08002259 final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002260 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -07002261 if (outParams != null) {
wilsonshih81e10a72018-11-15 10:54:21 +08002262 outParams.putInt("width", wpdData.mWidth);
2263 outParams.putInt("height", wpdData.mHeight);
Dianne Hackborn284ac932009-08-28 10:34:25 -07002264 }
Christopher Tateea6724a2016-02-18 18:39:19 -08002265 if (cb != null) {
2266 wallpaper.callbacks.register(cb);
2267 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002268 if (!wallpaper.cropFile.exists()) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002269 return null;
2270 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002271 return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002272 } catch (FileNotFoundException e) {
2273 /* Shouldn't happen as we check to see if the file exists */
Joe Onorato8a9b2202010-02-26 18:56:32 -08002274 Slog.w(TAG, "Error getting wallpaper", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002276 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 }
2279
Christopher Tatee409f0e2016-03-21 14:53:15 -07002280 @Override
Jorim Jaggie31f6b82016-07-01 16:15:09 -07002281 public WallpaperInfo getWallpaperInfo(int userId) {
2282 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Christopher Tatef717b932017-09-11 15:52:54 -07002283 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null);
Dianne Hackborneb034652009-09-07 00:49:58 -07002284 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002285 WallpaperData wallpaper = mWallpaperMap.get(userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00002286 if (wallpaper != null && wallpaper.connection != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002287 return wallpaper.connection.mInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -07002288 }
2289 return null;
2290 }
2291 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002292
Christopher Tatead3c2592016-01-20 18:13:17 -08002293 @Override
Christopher Tatee409f0e2016-03-21 14:53:15 -07002294 public int getWallpaperIdForUser(int which, int userId) {
2295 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2296 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
2297
Christopher Tateedf7d042016-03-29 18:24:25 -07002298 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07002299 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
2300 }
2301
2302 final SparseArray<WallpaperData> map =
Christopher Tateedf7d042016-03-29 18:24:25 -07002303 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatee409f0e2016-03-21 14:53:15 -07002304 synchronized (mLock) {
2305 WallpaperData wallpaper = map.get(userId);
2306 if (wallpaper != null) {
2307 return wallpaper.wallpaperId;
2308 }
2309 }
2310 return -1;
2311 }
2312
2313 @Override
wilsonshih36597d42018-12-05 18:56:39 +08002314 public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId,
2315 int displayId) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07002316 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
2317 userId, true, true, "registerWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002318 synchronized (mLock) {
wilsonshih36597d42018-12-05 18:56:39 +08002319 SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
2320 userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId);
2321 if (userDisplayColorsChangedListeners == null) {
2322 userDisplayColorsChangedListeners = new SparseArray<>();
2323 mColorsChangedListeners.put(userId, userDisplayColorsChangedListeners);
Lucas Dupin50ba9912017-07-14 11:55:05 -07002324 }
wilsonshih36597d42018-12-05 18:56:39 +08002325 RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners =
2326 userDisplayColorsChangedListeners.get(displayId);
2327 if (displayChangedListeners == null) {
2328 displayChangedListeners = new RemoteCallbackList<>();
2329 userDisplayColorsChangedListeners.put(displayId, displayChangedListeners);
2330 }
2331 displayChangedListeners.register(cb);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002332 }
2333 }
2334
2335 @Override
wilsonshih36597d42018-12-05 18:56:39 +08002336 public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId,
2337 int displayId) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07002338 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
2339 userId, true, true, "unregisterWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002340 synchronized (mLock) {
wilsonshih36597d42018-12-05 18:56:39 +08002341 SparseArray<RemoteCallbackList<IWallpaperManagerCallback>>
2342 userDisplayColorsChangedListeners = mColorsChangedListeners.get(userId);
2343 if (userDisplayColorsChangedListeners != null) {
2344 RemoteCallbackList<IWallpaperManagerCallback> displayChangedListeners =
2345 userDisplayColorsChangedListeners.get(displayId);
2346 if (displayChangedListeners != null) {
2347 displayChangedListeners.unregister(cb);
2348 }
Lucas Dupin50ba9912017-07-14 11:55:05 -07002349 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002350 }
2351 }
2352
Lucas Dupin4c8c3272018-11-06 17:47:48 -08002353 /**
wilsonshih36597d42018-12-05 18:56:39 +08002354 * TODO(multi-display) Extends this method with specific display.
Lucas Dupin4c8c3272018-11-06 17:47:48 -08002355 * Propagate ambient state to wallpaper engine.
2356 *
2357 * @param inAmbientMode {@code true} when in ambient mode, {@code false} otherwise.
2358 * @param animationDuration Duration of the animation, or 0 when immediate.
2359 */
2360 public void setInAmbientMode(boolean inAmbientMode, long animationDuration) {
Lucas Dupin7517b5d2017-08-22 12:51:25 -07002361 final IWallpaperEngine engine;
2362 synchronized (mLock) {
Lucas Dupin4c8c3272018-11-06 17:47:48 -08002363 mInAmbientMode = inAmbientMode;
Lucas Dupin7517b5d2017-08-22 12:51:25 -07002364 final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
Ahan Wu723a80e2018-11-07 20:39:32 +08002365 // The wallpaper info is null for image wallpaper, also use the engine in this case.
Ahan Wu67e7f102019-01-14 20:38:14 +08002366 if (data != null && data.connection != null && (data.connection.mInfo == null
2367 || data.connection.mInfo.supportsAmbientMode())) {
wilsonshih36597d42018-12-05 18:56:39 +08002368 // TODO(multi-display) Extends this method with specific display.
wilsonshihde93f492018-11-01 21:23:40 +08002369 engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
Lucas Dupin7517b5d2017-08-22 12:51:25 -07002370 } else {
2371 engine = null;
2372 }
2373 }
2374
2375 if (engine != null) {
2376 try {
Lucas Dupin4c8c3272018-11-06 17:47:48 -08002377 engine.setInAmbientMode(inAmbientMode, animationDuration);
Lucas Dupin7517b5d2017-08-22 12:51:25 -07002378 } catch (RemoteException e) {
2379 // Cannot talk to wallpaper engine.
2380 }
2381 }
2382 }
2383
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002384 @Override
Christopher Tatebe132e62016-02-10 12:59:49 -08002385 public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
2386 checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
2387 synchronized (mLock) {
2388 mKeyguardListener = cb;
2389 }
2390 return true;
2391 }
2392
2393 @Override
wilsonshih36597d42018-12-05 18:56:39 +08002394 public WallpaperColors getWallpaperColors(int which, int userId, int displayId)
2395 throws RemoteException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002396 if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
2397 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
2398 }
Lucas Dupin50ba9912017-07-14 11:55:05 -07002399 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
2400 userId, false, true, "getWallpaperColors", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002401
2402 WallpaperData wallpaperData = null;
2403 boolean shouldExtract;
2404
2405 synchronized (mLock) {
2406 if (which == FLAG_LOCK) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07002407 wallpaperData = mLockWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002408 }
2409
2410 // Try to get the system wallpaper anyway since it might
2411 // also be the lock screen wallpaper
2412 if (wallpaperData == null) {
wilsonshih36597d42018-12-05 18:56:39 +08002413 wallpaperData = findWallpaperAtDisplay(userId, displayId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002414 }
2415
2416 if (wallpaperData == null) {
2417 return null;
2418 }
2419 shouldExtract = wallpaperData.primaryColors == null;
2420 }
2421
2422 if (shouldExtract) {
2423 extractColors(wallpaperData);
2424 }
2425
2426 synchronized (mLock) {
Lucas Dupin4b4c5302018-06-24 18:22:10 -07002427 return wallpaperData.primaryColors;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002428 }
2429 }
2430
wilsonshih36597d42018-12-05 18:56:39 +08002431 private WallpaperData findWallpaperAtDisplay(int userId, int displayId) {
2432 if (mFallbackWallpaper != null && mFallbackWallpaper.connection != null
2433 && mFallbackWallpaper.connection.containsDisplay(displayId)) {
2434 return mFallbackWallpaper;
2435 } else {
2436 return mWallpaperMap.get(userId);
2437 }
2438 }
2439
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002440 @Override
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002441 public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Christopher Tated7faf532016-02-25 12:43:38 -08002442 Rect cropHint, boolean allowBackup, Bundle extras, int which,
Jorim Jaggi6c902d02016-08-18 10:44:54 -07002443 IWallpaperManagerCallback completion, int userId) {
2444 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
2445 false /* all */, true /* full */, "changing wallpaper", null /* pkg */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002446 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tatead3c2592016-01-20 18:13:17 -08002447
Christopher Tateedf7d042016-03-29 18:24:25 -07002448 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07002449 final String msg = "Must specify a valid wallpaper category to set";
2450 Slog.e(TAG, msg);
2451 throw new IllegalArgumentException(msg);
Christopher Tatead3c2592016-01-20 18:13:17 -08002452 }
2453
Christopher Tate98d609c2016-05-18 17:31:58 -07002454 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00002455 return null;
2456 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002457
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002458 // "null" means the no-op crop, preserving the full input image
2459 if (cropHint == null) {
2460 cropHint = new Rect(0, 0, 0, 0);
2461 } else {
2462 if (cropHint.isEmpty()
2463 || cropHint.left < 0
2464 || cropHint.top < 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07002465 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002466 }
2467 }
2468
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002469 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002470 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
2471 WallpaperData wallpaper;
2472
Christopher Tate8347b632016-04-29 18:59:18 -07002473 /* If we're setting system but not lock, and lock is currently sharing the system
2474 * wallpaper, we need to migrate that image over to being lock-only before
2475 * the caller here writes new bitmap data.
2476 */
2477 if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
2478 if (DEBUG) {
2479 Slog.i(TAG, "Migrating system->lock to preserve");
2480 }
2481 migrateSystemToLockWallpaperLocked(userId);
2482 }
2483
Christopher Tatebe132e62016-02-10 12:59:49 -08002484 wallpaper = getWallpaperSafeLocked(userId, which);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07002485 final long ident = Binder.clearCallingIdentity();
2486 try {
Christopher Tatead3c2592016-01-20 18:13:17 -08002487 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07002488 if (pfd != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002489 wallpaper.imageWallpaperPending = true;
Christopher Tatebe132e62016-02-10 12:59:49 -08002490 wallpaper.whichPending = which;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002491 wallpaper.setComplete = completion;
2492 wallpaper.cropHint.set(cropHint);
Christopher Tatec613c632016-08-12 14:13:02 -07002493 wallpaper.allowBackup = allowBackup;
Dianne Hackborn0cd48872009-08-13 18:51:59 -07002494 }
2495 return pfd;
2496 } finally {
2497 Binder.restoreCallingIdentity(ident);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002499 }
2500 }
2501
Christopher Tate8347b632016-04-29 18:59:18 -07002502 private void migrateSystemToLockWallpaperLocked(int userId) {
2503 WallpaperData sysWP = mWallpaperMap.get(userId);
2504 if (sysWP == null) {
2505 if (DEBUG) {
2506 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
2507 }
2508 return;
2509 }
2510
2511 // We know a-priori that there is no lock-only wallpaper currently
wilsonshih999ec102019-05-17 18:47:50 +08002512 WallpaperData lockWP = new WallpaperData(userId, getWallpaperDir(userId),
Christopher Tate8347b632016-04-29 18:59:18 -07002513 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2514 lockWP.wallpaperId = sysWP.wallpaperId;
2515 lockWP.cropHint.set(sysWP.cropHint);
Christopher Tateedd8dc82016-10-12 15:17:58 -07002516 lockWP.allowBackup = sysWP.allowBackup;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002517 lockWP.primaryColors = sysWP.primaryColors;
Christopher Tate8347b632016-04-29 18:59:18 -07002518
2519 // Migrate the bitmap files outright; no need to copy
2520 try {
2521 Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
2522 Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
2523 } catch (ErrnoException e) {
2524 Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
2525 lockWP.wallpaperFile.delete();
2526 lockWP.cropFile.delete();
2527 return;
2528 }
2529
2530 mLockWallpaperMap.put(userId, lockWP);
2531 }
2532
Christopher Tatead3c2592016-01-20 18:13:17 -08002533 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
2534 Bundle extras) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002535 if (name == null) name = "";
2536 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002537 File dir = getWallpaperDir(wallpaper.userId);
2538 if (!dir.exists()) {
2539 dir.mkdir();
Dianne Hackbornebac48c2011-11-29 18:01:50 -08002540 FileUtils.setPermissions(
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002541 dir.getPath(),
Dianne Hackbornebac48c2011-11-29 18:01:50 -08002542 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
2543 -1, -1);
2544 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002545 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
Christopher Tate90f86ba2014-09-11 12:37:19 -07002546 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
Christopher Tatebe132e62016-02-10 12:59:49 -08002547 if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
rpcraig554cb0c2012-07-05 06:41:43 -04002548 return null;
2549 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002550 wallpaper.name = name;
Christopher Tatead3c2592016-01-20 18:13:17 -08002551 wallpaper.wallpaperId = makeWallpaperIdLocked();
2552 if (extras != null) {
2553 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
2554 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002555 // Nullify field to require new computation
2556 wallpaper.primaryColors = null;
Christopher Tatead3c2592016-01-20 18:13:17 -08002557 if (DEBUG) {
2558 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
Christopher Tatebe132e62016-02-10 12:59:49 -08002559 + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
Christopher Tatead3c2592016-01-20 18:13:17 -08002560 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002561 return fd;
2562 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002563 Slog.w(TAG, "Error setting wallpaper", e);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002564 }
2565 return null;
2566 }
2567
Christopher Tated57d17c2016-03-25 13:41:46 -07002568 @Override
Adrian Roos40ea0832016-07-14 14:19:55 -07002569 public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
2570 int userId) {
2571
Christopher Tate98d609c2016-05-18 17:31:58 -07002572 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
Adrian Roos40ea0832016-07-14 14:19:55 -07002573 setWallpaperComponent(name, userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00002574 }
2575 }
2576
2577 // ToDo: Remove this version of the function
Christopher Tated57d17c2016-03-25 13:41:46 -07002578 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002579 public void setWallpaperComponent(ComponentName name) {
Adrian Roos40ea0832016-07-14 14:19:55 -07002580 setWallpaperComponent(name, UserHandle.getCallingUserId());
2581 }
2582
2583 private void setWallpaperComponent(ComponentName name, int userId) {
2584 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
2585 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002586 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
Adrian Roos40ea0832016-07-14 14:19:55 -07002587
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002588 int which = FLAG_SYSTEM;
2589 boolean shouldNotifyColors = false;
2590 WallpaperData wallpaper;
2591
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002592 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002593 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002594 wallpaper = mWallpaperMap.get(userId);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002595 if (wallpaper == null) {
2596 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
2597 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002598 final long ident = Binder.clearCallingIdentity();
Christopher Tate7cd00102016-12-19 14:38:44 -08002599
2600 // Live wallpapers can't be specified for keyguard. If we're using a static
2601 // system+lock image currently, migrate the system wallpaper to be a lock-only
2602 // image as part of making a different live component active as the system
2603 // wallpaper.
2604 if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
2605 if (mLockWallpaperMap.get(userId) == null) {
2606 // We're using the static imagery and there is no lock-specific image in place,
2607 // therefore it's a shared system+lock image that we need to migrate.
2608 migrateSystemToLockWallpaperLocked(userId);
2609 }
2610 }
2611
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002612 // New live wallpaper is also a lock wallpaper if nothing is set
2613 if (mLockWallpaperMap.get(userId) == null) {
2614 which |= FLAG_LOCK;
2615 }
2616
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002617 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002618 wallpaper.imageWallpaperPending = false;
Lucas Dupin50ba9912017-07-14 11:55:05 -07002619 boolean same = changingToSame(name, wallpaper);
Christopher Tated57d17c2016-03-25 13:41:46 -07002620 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07002621 if (!same) {
2622 wallpaper.primaryColors = null;
2623 }
Christopher Tated57d17c2016-03-25 13:41:46 -07002624 wallpaper.wallpaperId = makeWallpaperIdLocked();
Sunny Goyal0572e182016-03-31 11:05:51 -07002625 notifyCallbacksLocked(wallpaper);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002626 shouldNotifyColors = true;
Christopher Tated57d17c2016-03-25 13:41:46 -07002627 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002628 } finally {
2629 Binder.restoreCallingIdentity(ident);
2630 }
2631 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002632
2633 if (shouldNotifyColors) {
2634 notifyWallpaperColorsChanged(wallpaper, which);
wilsonshih36597d42018-12-05 18:56:39 +08002635 notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002636 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002637 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002638
Lucas Dupin50ba9912017-07-14 11:55:05 -07002639 private boolean changingToSame(ComponentName componentName, WallpaperData wallpaper) {
2640 if (wallpaper.connection != null) {
2641 if (wallpaper.wallpaperComponent == null) {
2642 if (componentName == null) {
2643 if (DEBUG) Slog.v(TAG, "changingToSame: still using default");
2644 // Still using default wallpaper.
2645 return true;
2646 }
2647 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
2648 // Changing to same wallpaper.
2649 if (DEBUG) Slog.v(TAG, "same wallpaper");
2650 return true;
2651 }
2652 }
2653 return false;
2654 }
2655
wilsonshiha282bf72018-11-30 12:48:05 +08002656 private boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002657 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002658 if (DEBUG_LIVE) {
2659 Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
2660 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002661 // Has the component changed?
Lucas Dupin50ba9912017-07-14 11:55:05 -07002662 if (!force && changingToSame(componentName, wallpaper)) {
2663 return true;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002664 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002665
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002666 try {
Mike Clerona428b2c2009-11-15 22:53:08 -08002667 if (componentName == null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002668 componentName = mDefaultWallpaperComponent;
Mike Clerona428b2c2009-11-15 22:53:08 -08002669 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -08002670 // Fall back to static image wallpaper
Justin Koh29c30162014-09-05 17:10:10 -07002671 componentName = mImageWallpaper;
Mike Cleron322b6ee2009-11-12 07:45:47 -08002672 //clearWallpaperComponentLocked();
2673 //return;
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002674 if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper");
Mike Cleron322b6ee2009-11-12 07:45:47 -08002675 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002676 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002677 int serviceUserId = wallpaper.userId;
2678 ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
2679 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
Christopher Tate90952202013-09-08 13:01:28 -07002680 if (si == null) {
2681 // The wallpaper component we're trying to use doesn't exist
2682 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
2683 return false;
2684 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002685 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
Lucas Dupin4c8c3272018-11-06 17:47:48 -08002686 String msg = "Selected service does not have "
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002687 + android.Manifest.permission.BIND_WALLPAPER
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002688 + ": " + componentName;
2689 if (fromUser) {
2690 throw new SecurityException(msg);
2691 }
2692 Slog.w(TAG, msg);
2693 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002694 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002695
Dianne Hackborneb034652009-09-07 00:49:58 -07002696 WallpaperInfo wi = null;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002697
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002698 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
Justin Koh29c30162014-09-05 17:10:10 -07002699 if (componentName != null && !componentName.equals(mImageWallpaper)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002700 // Make sure the selected service is actually a wallpaper service.
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002701 List<ResolveInfo> ris =
2702 mIPackageManager.queryIntentServices(intent,
2703 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
Jeff Sharkeyd5896632016-03-04 16:16:00 -07002704 PackageManager.GET_META_DATA, serviceUserId).getList();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002705 for (int i=0; i<ris.size(); i++) {
2706 ServiceInfo rsi = ris.get(i).serviceInfo;
2707 if (rsi.name.equals(si.name) &&
2708 rsi.packageName.equals(si.packageName)) {
Dianne Hackborneb034652009-09-07 00:49:58 -07002709 try {
2710 wi = new WallpaperInfo(mContext, ris.get(i));
2711 } catch (XmlPullParserException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002712 if (fromUser) {
2713 throw new IllegalArgumentException(e);
2714 }
2715 Slog.w(TAG, e);
2716 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002717 } catch (IOException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002718 if (fromUser) {
2719 throw new IllegalArgumentException(e);
2720 }
2721 Slog.w(TAG, e);
2722 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002723 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002724 break;
2725 }
2726 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002727 if (wi == null) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002728 String msg = "Selected service is not a wallpaper: "
2729 + componentName;
2730 if (fromUser) {
2731 throw new SecurityException(msg);
2732 }
2733 Slog.w(TAG, msg);
2734 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002735 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002736 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002737
Lucas Dupin4c8c3272018-11-06 17:47:48 -08002738 if (wi != null && wi.supportsAmbientMode()) {
2739 final int hasPrivilege = mIPackageManager.checkPermission(
2740 android.Manifest.permission.AMBIENT_WALLPAPER, wi.getPackageName(),
2741 serviceUserId);
2742 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
2743 String msg = "Selected service does not have "
2744 + android.Manifest.permission.AMBIENT_WALLPAPER
2745 + ": " + componentName;
2746 if (fromUser) {
2747 throw new SecurityException(msg);
2748 }
2749 Slog.w(TAG, msg);
2750 return false;
2751 }
2752 }
2753
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002754 // Bind the service!
Joe Onorato8a9b2202010-02-26 18:56:32 -08002755 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
wilsonshihde93f492018-11-01 21:23:40 +08002756 final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(),
2757 MATCH_DIRECT_BOOT_AUTO, wallpaper.userId);
2758 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid);
Mike Clerona428b2c2009-11-15 22:53:08 -08002759 intent.setComponent(componentName);
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002760 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2761 com.android.internal.R.string.wallpaper_binding_label);
Dianne Hackborn41203752012-08-31 14:05:51 -07002762 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
Dianne Hackborneb034652009-09-07 00:49:58 -07002763 mContext, 0,
2764 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
2765 mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
Dianne Hackborn41203752012-08-31 14:05:51 -07002766 0, null, new UserHandle(serviceUserId)));
Dianne Hackbornc8230512013-07-13 21:32:12 -07002767 if (!mContext.bindServiceAsUser(intent, newConn,
Dianne Hackbornd69e4c12015-04-24 09:54:54 -07002768 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
Amith Yamasanic45a9902019-04-05 16:29:30 -07002769 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
2770 | Context.BIND_INCLUDE_CAPABILITIES,
Amith Yamasani27b89e62013-01-16 12:30:11 -08002771 new UserHandle(serviceUserId))) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002772 String msg = "Unable to bind service: "
2773 + componentName;
2774 if (fromUser) {
2775 throw new IllegalArgumentException(msg);
2776 }
2777 Slog.w(TAG, msg);
2778 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002779 }
wilsonshiha282bf72018-11-30 12:48:05 +08002780 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null
2781 && !wallpaper.equals(mFallbackWallpaper)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002782 detachWallpaperLocked(mLastWallpaper);
2783 }
2784 wallpaper.wallpaperComponent = componentName;
2785 wallpaper.connection = newConn;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002786 newConn.mReply = reply;
wilsonshiha282bf72018-11-30 12:48:05 +08002787 if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(mFallbackWallpaper)) {
wilsonshihde93f492018-11-01 21:23:40 +08002788 mLastWallpaper = wallpaper;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002789 }
wilsonshiha282bf72018-11-30 12:48:05 +08002790 updateFallbackConnection();
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002791 } catch (RemoteException e) {
2792 String msg = "Remote exception for " + componentName + "\n" + e;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002793 if (fromUser) {
2794 throw new IllegalArgumentException(msg);
2795 }
2796 Slog.w(TAG, msg);
2797 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002798 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002799 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002800 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002801
wilsonshiha282bf72018-11-30 12:48:05 +08002802 private void detachWallpaperLocked(WallpaperData wallpaper) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002803 if (wallpaper.connection != null) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002804 if (wallpaper.connection.mReply != null) {
2805 try {
2806 wallpaper.connection.mReply.sendResult(null);
2807 } catch (RemoteException e) {
2808 }
2809 wallpaper.connection.mReply = null;
2810 }
wilsonshihb72ff9c2019-03-21 17:27:02 +08002811 try {
Keun young Parke3d2fea2019-03-29 17:42:32 -07002812 // It can be null if user switching happens before service connection.
2813 if (wallpaper.connection.mService != null) {
2814 wallpaper.connection.mService.detach();
2815 }
wilsonshihb72ff9c2019-03-21 17:27:02 +08002816 } catch (RemoteException e) {
2817 Slog.w(TAG, "Failed detaching wallpaper service ", e);
2818 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002819 mContext.unbindService(wallpaper.connection);
wilsonshiha282bf72018-11-30 12:48:05 +08002820 wallpaper.connection.forEachDisplayConnector(
2821 WallpaperConnection.DisplayConnector::disconnectLocked);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002822 wallpaper.connection.mService = null;
wilsonshihde93f492018-11-01 21:23:40 +08002823 wallpaper.connection.mDisplayConnector.clear();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002824 wallpaper.connection = null;
wilsonshihde93f492018-11-01 21:23:40 +08002825 if (wallpaper == mLastWallpaper) mLastWallpaper = null;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002826 }
2827 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002828
wilsonshiha282bf72018-11-30 12:48:05 +08002829 private void clearWallpaperComponentLocked(WallpaperData wallpaper) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002830 wallpaper.wallpaperComponent = null;
2831 detachWallpaperLocked(wallpaper);
2832 }
2833
wilsonshiha282bf72018-11-30 12:48:05 +08002834 private void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
wilsonshihde93f492018-11-01 21:23:40 +08002835 conn.forEachDisplayConnector(connector-> connector.connectLocked(conn, wallpaper));
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002836 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002837
2838 private void notifyCallbacksLocked(WallpaperData wallpaper) {
2839 final int n = wallpaper.callbacks.beginBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 for (int i = 0; i < n; i++) {
2841 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002842 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 } catch (RemoteException e) {
2844
2845 // The RemoteCallbackList will take care of removing
2846 // the dead object for us.
2847 }
2848 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002849 wallpaper.callbacks.finishBroadcast();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002851 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002852 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002853 }
2854
2855 private void checkPermission(String permission) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002856 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
2858 + ", must have permission " + permission);
2859 }
2860 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002861
Benjamin Franzf3ece362015-02-11 10:51:10 +00002862 /**
2863 * Certain user types do not support wallpapers (e.g. managed profiles). The check is
2864 * implemented through through the OP_WRITE_WALLPAPER AppOp.
2865 */
2866 public boolean isWallpaperSupported(String callingPackage) {
2867 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
2868 callingPackage) == AppOpsManager.MODE_ALLOWED;
2869 }
2870
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002871 @Override
Christopher Tate98d609c2016-05-18 17:31:58 -07002872 public boolean isSetWallpaperAllowed(String callingPackage) {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002873 final PackageManager pm = mContext.getPackageManager();
2874 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
2875 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
2876 if (!uidMatchPackage) {
2877 return false; // callingPackage was faked.
2878 }
2879
Bookatzcfc5d192019-11-05 17:25:53 -08002880 // TODO(b/144048540): DPM needs to take into account the userId, not just the package.
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002881 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
2882 if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
2883 return true;
2884 }
Bookatzcfc5d192019-11-05 17:25:53 -08002885 final int callingUserId = UserHandle.getCallingUserId();
2886 final long ident = Binder.clearCallingIdentity();
2887 try {
2888 UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
2889 return !umi.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER, callingUserId);
2890 } finally {
2891 Binder.restoreCallingIdentity(ident);
2892 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002893 }
2894
Christopher Tated7faf532016-02-25 12:43:38 -08002895 @Override
Christopher Tate61722662016-08-10 16:13:14 -07002896 public boolean isWallpaperBackupEligible(int which, int userId) {
Christopher Tated7faf532016-02-25 12:43:38 -08002897 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
2898 throw new SecurityException("Only the system may call isWallpaperBackupEligible");
2899 }
2900
Christopher Tate61722662016-08-10 16:13:14 -07002901 WallpaperData wallpaper = (which == FLAG_LOCK)
Christopher Tatef7d1b5d2016-08-19 11:21:07 -07002902 ? mLockWallpaperMap.get(userId)
2903 : mWallpaperMap.get(userId);
Christopher Tated7faf532016-02-25 12:43:38 -08002904 return (wallpaper != null) ? wallpaper.allowBackup : false;
2905 }
2906
wilsonshih643bf132019-02-27 12:49:19 +08002907 private void onDisplayReadyInternal(int displayId) {
2908 synchronized (mLock) {
2909 if (mLastWallpaper == null) {
2910 return;
2911 }
2912 if (supportsMultiDisplay(mLastWallpaper.connection)) {
2913 final WallpaperConnection.DisplayConnector connector =
2914 mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId);
2915 if (connector == null) return;
2916 connector.connectLocked(mLastWallpaper.connection, mLastWallpaper);
2917 return;
2918 }
2919 // System wallpaper does not support multiple displays, attach this display to
2920 // the fallback wallpaper.
2921 if (mFallbackWallpaper != null) {
2922 final WallpaperConnection.DisplayConnector connector = mFallbackWallpaper
2923 .connection.getDisplayConnectorOrCreate(displayId);
2924 if (connector == null) return;
2925 connector.connectLocked(mFallbackWallpaper.connection, mFallbackWallpaper);
2926 } else {
2927 Slog.w(TAG, "No wallpaper can be added to the new display");
2928 }
2929 }
2930 }
2931
wilsonshih999ec102019-05-17 18:47:50 +08002932 private JournaledFile makeJournaledFile(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07002933 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002934 return new JournaledFile(new File(base), new File(base + ".tmp"));
2935 }
2936
Christopher Tatedb27b842016-02-25 14:39:17 -08002937 private void saveSettingsLocked(int userId) {
2938 JournaledFile journal = makeJournaledFile(userId);
2939 FileOutputStream fstream = null;
2940 BufferedOutputStream stream = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002941 try {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002942 XmlSerializer out = new FastXmlSerializer();
Christopher Tatedb27b842016-02-25 14:39:17 -08002943 fstream = new FileOutputStream(journal.chooseForWrite(), false);
2944 stream = new BufferedOutputStream(fstream);
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002945 out.setOutput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002946 out.startDocument(null, true);
2947
Christopher Tatedb27b842016-02-25 14:39:17 -08002948 WallpaperData wallpaper;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002949
Christopher Tatedb27b842016-02-25 14:39:17 -08002950 wallpaper = mWallpaperMap.get(userId);
2951 if (wallpaper != null) {
2952 writeWallpaperAttributes(out, "wp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002953 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002954 wallpaper = mLockWallpaperMap.get(userId);
2955 if (wallpaper != null) {
2956 writeWallpaperAttributes(out, "kwp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002957 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002958
2959 out.endDocument();
Christopher Tatedb27b842016-02-25 14:39:17 -08002960
2961 stream.flush(); // also flushes fstream
2962 FileUtils.sync(fstream);
2963 stream.close(); // also closes fstream
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002964 journal.commit();
2965 } catch (IOException e) {
Christopher Tatead3c2592016-01-20 18:13:17 -08002966 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002967 journal.rollback();
2968 }
2969 }
2970
Christopher Tatedb27b842016-02-25 14:39:17 -08002971 private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
2972 throws IllegalArgumentException, IllegalStateException, IOException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002973 if (DEBUG) {
Christopher Tatef717b932017-09-11 15:52:54 -07002974 Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002975 }
wilsonshiha282bf72018-11-30 12:48:05 +08002976 final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
Christopher Tatedb27b842016-02-25 14:39:17 -08002977 out.startTag(null, tag);
2978 out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
wilsonshih81e10a72018-11-15 10:54:21 +08002979 out.attribute(null, "width", Integer.toString(wpdData.mWidth));
2980 out.attribute(null, "height", Integer.toString(wpdData.mHeight));
Christopher Tatedb27b842016-02-25 14:39:17 -08002981
2982 out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
2983 out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
2984 out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
2985 out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
2986
wilsonshih81e10a72018-11-15 10:54:21 +08002987 if (wpdData.mPadding.left != 0) {
2988 out.attribute(null, "paddingLeft", Integer.toString(wpdData.mPadding.left));
Christopher Tatedb27b842016-02-25 14:39:17 -08002989 }
wilsonshih81e10a72018-11-15 10:54:21 +08002990 if (wpdData.mPadding.top != 0) {
2991 out.attribute(null, "paddingTop", Integer.toString(wpdData.mPadding.top));
Christopher Tatedb27b842016-02-25 14:39:17 -08002992 }
wilsonshih81e10a72018-11-15 10:54:21 +08002993 if (wpdData.mPadding.right != 0) {
2994 out.attribute(null, "paddingRight", Integer.toString(wpdData.mPadding.right));
Christopher Tatedb27b842016-02-25 14:39:17 -08002995 }
wilsonshih81e10a72018-11-15 10:54:21 +08002996 if (wpdData.mPadding.bottom != 0) {
2997 out.attribute(null, "paddingBottom", Integer.toString(wpdData.mPadding.bottom));
Christopher Tatedb27b842016-02-25 14:39:17 -08002998 }
2999
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003000 if (wallpaper.primaryColors != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07003001 int colorsCount = wallpaper.primaryColors.getMainColors().size();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003002 out.attribute(null, "colorsCount", Integer.toString(colorsCount));
3003 if (colorsCount > 0) {
3004 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07003005 final Color wc = wallpaper.primaryColors.getMainColors().get(i);
3006 out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003007 }
3008 }
Lucas Dupin75ec3792017-06-29 14:07:18 -07003009 out.attribute(null, "colorHints",
Lucas Dupin84b89d92017-05-09 12:16:19 -07003010 Integer.toString(wallpaper.primaryColors.getColorHints()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003011 }
3012
Christopher Tatedb27b842016-02-25 14:39:17 -08003013 out.attribute(null, "name", wallpaper.name);
3014 if (wallpaper.wallpaperComponent != null
3015 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
3016 out.attribute(null, "component",
3017 wallpaper.wallpaperComponent.flattenToShortString());
3018 }
Christopher Tated7faf532016-02-25 12:43:38 -08003019
3020 if (wallpaper.allowBackup) {
3021 out.attribute(null, "backup", "true");
3022 }
3023
Christopher Tatedb27b842016-02-25 14:39:17 -08003024 out.endTag(null, tag);
3025 }
3026
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003027 private void migrateFromOld() {
Christopher Tate9f224432017-08-01 16:32:49 -07003028 // Pre-N, what existed is the one we're now using as the display crop
3029 File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP);
3030 // In the very-long-ago, imagery lived with the settings app
3031 File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
3032 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
3033
3034 // Migrations from earlier wallpaper image storage schemas
3035 if (preNWallpaper.exists()) {
3036 if (!newWallpaper.exists()) {
3037 // we've got the 'wallpaper' crop file but not the nominal source image,
3038 // so do the simple "just take everything" straight copy of legacy data
3039 if (DEBUG) {
3040 Slog.i(TAG, "Migrating wallpaper schema");
3041 }
3042 FileUtils.copyFile(preNWallpaper, newWallpaper);
3043 } // else we're in the usual modern case: both source & crop exist
3044 } else if (originalWallpaper.exists()) {
3045 // VERY old schema; make sure things exist and are in the right place
3046 if (DEBUG) {
3047 Slog.i(TAG, "Migrating antique wallpaper schema");
3048 }
3049 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
3050 if (oldInfo.exists()) {
3051 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
3052 oldInfo.renameTo(newInfo);
3053 }
3054
3055 FileUtils.copyFile(originalWallpaper, preNWallpaper);
3056 originalWallpaper.renameTo(newWallpaper);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003057 }
3058 }
3059
Dianne Hackborn067e5f62014-09-07 23:14:30 -07003060 private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
3061 String value = parser.getAttributeValue(null, name);
3062 if (value == null) {
3063 return defValue;
3064 }
3065 return Integer.parseInt(value);
3066 }
3067
Xiaohui Chenac531942015-05-13 13:20:52 -07003068 /**
3069 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could
3070 * happen during user switch. The async user switch observer may not have received
3071 * the event yet. We use this safe method when we don't care about this ordering and just
3072 * want to update the data. The data is going to be applied when the user switch observer
3073 * is eventually executed.
Christopher Tatef717b932017-09-11 15:52:54 -07003074 *
3075 * Important: this method loads settings to initialize the given user's wallpaper data if
3076 * there is no current in-memory state.
Xiaohui Chenac531942015-05-13 13:20:52 -07003077 */
Christopher Tatebe132e62016-02-10 12:59:49 -08003078 private WallpaperData getWallpaperSafeLocked(int userId, int which) {
3079 // We're setting either just system (work with the system wallpaper),
3080 // both (also work with the system wallpaper), or just the lock
3081 // wallpaper (update against the existing lock wallpaper if any).
3082 // Combined or just-system operations use the 'system' WallpaperData
3083 // for this use; lock-only operations use the dedicated one.
3084 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07003085 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatebe132e62016-02-10 12:59:49 -08003086 WallpaperData wallpaper = whichSet.get(userId);
Xiaohui Chenac531942015-05-13 13:20:52 -07003087 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08003088 // common case, this is the first lookup post-boot of the system or
3089 // unified lock, so we bring up the saved state lazily now and recheck.
Christopher Tated7faf532016-02-25 12:43:38 -08003090 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08003091 wallpaper = whichSet.get(userId);
3092 // if it's still null here, this is a lock-only operation and there is not
3093 // yet a lock-only wallpaper set for this user, so we need to establish
3094 // it now.
3095 if (wallpaper == null) {
Christopher Tateedf7d042016-03-29 18:24:25 -07003096 if (which == FLAG_LOCK) {
wilsonshih999ec102019-05-17 18:47:50 +08003097 wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
Christopher Tatebe132e62016-02-10 12:59:49 -08003098 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
3099 mLockWallpaperMap.put(userId, wallpaper);
wilsonshih81e10a72018-11-15 10:54:21 +08003100 ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
Christopher Tatebe132e62016-02-10 12:59:49 -08003101 } else {
3102 // sanity fallback: we're in bad shape, but establishing a known
3103 // valid system+lock WallpaperData will keep us from dying.
3104 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
wilsonshih999ec102019-05-17 18:47:50 +08003105 wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
3106 WALLPAPER, WALLPAPER_CROP);
Christopher Tatebe132e62016-02-10 12:59:49 -08003107 mWallpaperMap.put(userId, wallpaper);
wilsonshih81e10a72018-11-15 10:54:21 +08003108 ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
Christopher Tatebe132e62016-02-10 12:59:49 -08003109 }
3110 }
Xiaohui Chenac531942015-05-13 13:20:52 -07003111 }
3112 return wallpaper;
3113 }
3114
Christopher Tated7faf532016-02-25 12:43:38 -08003115 private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003116 JournaledFile journal = makeJournaledFile(userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003117 FileInputStream stream = null;
3118 File file = journal.chooseForRead();
Christopher Tate9f224432017-08-01 16:32:49 -07003119
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003120 WallpaperData wallpaper = mWallpaperMap.get(userId);
3121 if (wallpaper == null) {
Christopher Tate9f224432017-08-01 16:32:49 -07003122 // Do this once per boot
3123 migrateFromOld();
3124
wilsonshih999ec102019-05-17 18:47:50 +08003125 wallpaper = new WallpaperData(userId, getWallpaperDir(userId),
3126 WALLPAPER, WALLPAPER_CROP);
Christopher Tated7faf532016-02-25 12:43:38 -08003127 wallpaper.allowBackup = true;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003128 mWallpaperMap.put(userId, wallpaper);
Christopher Tate41297ff2016-03-10 16:46:15 -08003129 if (!wallpaper.cropExists()) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07003130 if (wallpaper.sourceExists()) {
3131 generateCrop(wallpaper);
3132 } else {
3133 Slog.i(TAG, "No static wallpaper imagery; defaults will be shown");
3134 }
Christopher Tate41297ff2016-03-10 16:46:15 -08003135 }
wilsonshiha282bf72018-11-30 12:48:05 +08003136 initializeFallbackWallpaper();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003137 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003138 boolean success = false;
wilsonshiha282bf72018-11-30 12:48:05 +08003139 final DisplayData wpdData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003140 try {
3141 stream = new FileInputStream(file);
3142 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01003143 parser.setInput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003144
3145 int type;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003146 do {
3147 type = parser.next();
3148 if (type == XmlPullParser.START_TAG) {
3149 String tag = parser.getName();
3150 if ("wp".equals(tag)) {
Christopher Tatebe132e62016-02-10 12:59:49 -08003151 // Common to system + lock wallpapers
Christopher Tated7faf532016-02-25 12:43:38 -08003152 parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
Christopher Tatead3c2592016-01-20 18:13:17 -08003153
Christopher Tatebe132e62016-02-10 12:59:49 -08003154 // A system wallpaper might also be a live wallpaper
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07003155 String comp = parser.getAttributeValue(null, "component");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003156 wallpaper.nextWallpaperComponent = comp != null
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07003157 ? ComponentName.unflattenFromString(comp)
3158 : null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003159 if (wallpaper.nextWallpaperComponent == null
3160 || "android".equals(wallpaper.nextWallpaperComponent
3161 .getPackageName())) {
Justin Koh29c30162014-09-05 17:10:10 -07003162 wallpaper.nextWallpaperComponent = mImageWallpaper;
Dianne Hackborn9ea31632011-08-05 14:43:50 -07003163 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01003164
Mike Clerona428b2c2009-11-15 22:53:08 -08003165 if (DEBUG) {
wilsonshih81e10a72018-11-15 10:54:21 +08003166 Slog.v(TAG, "mWidth:" + wpdData.mWidth);
3167 Slog.v(TAG, "mHeight:" + wpdData.mHeight);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003168 Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003169 Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003170 Slog.v(TAG, "mName:" + wallpaper.name);
3171 Slog.v(TAG, "mNextWallpaperComponent:"
3172 + wallpaper.nextWallpaperComponent);
Mike Clerona428b2c2009-11-15 22:53:08 -08003173 }
Christopher Tatebe132e62016-02-10 12:59:49 -08003174 } else if ("kwp".equals(tag)) {
3175 // keyguard-specific wallpaper for this user
3176 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
3177 if (lockWallpaper == null) {
wilsonshih999ec102019-05-17 18:47:50 +08003178 lockWallpaper = new WallpaperData(userId, getWallpaperDir(userId),
Christopher Tatebe132e62016-02-10 12:59:49 -08003179 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
3180 mLockWallpaperMap.put(userId, lockWallpaper);
3181 }
Christopher Tated7faf532016-02-25 12:43:38 -08003182 parseWallpaperAttributes(parser, lockWallpaper, false);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003183 }
3184 }
3185 } while (type != XmlPullParser.END_DOCUMENT);
3186 success = true;
Dianne Hackborn13579ed2012-11-28 18:05:36 -08003187 } catch (FileNotFoundException e) {
3188 Slog.w(TAG, "no current wallpaper -- first boot?");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003189 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003190 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003191 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003192 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003193 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003194 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003195 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003196 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003197 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003198 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003199 }
Christopher Tatead3c2592016-01-20 18:13:17 -08003200 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003201
3202 if (!success) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003203 wallpaper.cropHint.set(0, 0, 0, 0);
wilsonshih81e10a72018-11-15 10:54:21 +08003204 wpdData.mPadding.set(0, 0, 0, 0);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003205 wallpaper.name = "";
Adrian Roosc28e3a92016-04-14 10:47:52 -07003206
3207 mLockWallpaperMap.remove(userId);
Christopher Tatead3c2592016-01-20 18:13:17 -08003208 } else {
3209 if (wallpaper.wallpaperId <= 0) {
3210 wallpaper.wallpaperId = makeWallpaperIdLocked();
3211 if (DEBUG) {
3212 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
3213 + "); now " + wallpaper.wallpaperId);
3214 }
3215 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003216 }
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07003217
wilsonshihd9173df2018-11-29 11:52:15 +08003218 ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY);
wilsonshih81e10a72018-11-15 10:54:21 +08003219 ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
Adrian Roosc28e3a92016-04-14 10:47:52 -07003220 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
3221 if (lockWallpaper != null) {
wilsonshih81e10a72018-11-15 10:54:21 +08003222 ensureSaneWallpaperData(lockWallpaper, DEFAULT_DISPLAY);
Adrian Roosc28e3a92016-04-14 10:47:52 -07003223 }
3224 }
3225
wilsonshiha282bf72018-11-30 12:48:05 +08003226 private void initializeFallbackWallpaper() {
3227 if (mFallbackWallpaper == null) {
3228 if (DEBUG) Slog.d(TAG, "Initialize fallback wallpaper");
wilsonshih999ec102019-05-17 18:47:50 +08003229 final int systemUserId = UserHandle.USER_SYSTEM;
3230 mFallbackWallpaper = new WallpaperData(systemUserId, getWallpaperDir(systemUserId),
3231 WALLPAPER, WALLPAPER_CROP);
wilsonshiha282bf72018-11-30 12:48:05 +08003232 mFallbackWallpaper.allowBackup = false;
3233 mFallbackWallpaper.wallpaperId = makeWallpaperIdLocked();
3234 bindWallpaperComponentLocked(mImageWallpaper, true, false, mFallbackWallpaper, null);
3235 }
3236 }
3237
wilsonshih81e10a72018-11-15 10:54:21 +08003238 private void ensureSaneWallpaperData(WallpaperData wallpaper, int displayId) {
wilsonshiha282bf72018-11-30 12:48:05 +08003239 final DisplayData size = getDisplayDataOrCreate(displayId);
wilsonshih81e10a72018-11-15 10:54:21 +08003240
3241 if (displayId == DEFAULT_DISPLAY) {
3242 // crop, if not previously specified
3243 if (wallpaper.cropHint.width() <= 0
3244 || wallpaper.cropHint.height() <= 0) {
3245 wallpaper.cropHint.set(0, 0, size.mWidth, size.mHeight);
3246 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003247 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003248 }
3249
Christopher Tated7faf532016-02-25 12:43:38 -08003250 private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
3251 boolean keepDimensionHints) {
Christopher Tatebe132e62016-02-10 12:59:49 -08003252 final String idString = parser.getAttributeValue(null, "id");
3253 if (idString != null) {
3254 final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
3255 if (id > mWallpaperId) {
3256 mWallpaperId = id;
3257 }
3258 } else {
3259 wallpaper.wallpaperId = makeWallpaperIdLocked();
3260 }
3261
wilsonshiha282bf72018-11-30 12:48:05 +08003262 final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY);
wilsonshih81e10a72018-11-15 10:54:21 +08003263
Christopher Tated7faf532016-02-25 12:43:38 -08003264 if (!keepDimensionHints) {
wilsonshih81e10a72018-11-15 10:54:21 +08003265 wpData.mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
3266 wpData.mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
Christopher Tated7faf532016-02-25 12:43:38 -08003267 }
Christopher Tatebe132e62016-02-10 12:59:49 -08003268 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
3269 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
3270 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
3271 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
wilsonshih81e10a72018-11-15 10:54:21 +08003272 wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0);
3273 wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0);
3274 wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0);
3275 wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003276 int colorsCount = getAttributeInt(parser, "colorsCount", 0);
3277 if (colorsCount > 0) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07003278 Color primary = null, secondary = null, tertiary = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003279 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07003280 Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
3281 if (i == 0) {
3282 primary = color;
3283 } else if (i == 1) {
3284 secondary = color;
3285 } else if (i == 2) {
3286 tertiary = color;
3287 } else {
3288 break;
3289 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003290 }
Lucas Dupin84b89d92017-05-09 12:16:19 -07003291 int colorHints = getAttributeInt(parser, "colorHints", 0);
3292 wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07003293 }
Christopher Tatebe132e62016-02-10 12:59:49 -08003294 wallpaper.name = parser.getAttributeValue(null, "name");
Christopher Tated7faf532016-02-25 12:43:38 -08003295 wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
Christopher Tatebe132e62016-02-10 12:59:49 -08003296 }
3297
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07003298 // Called by SystemBackupAgent after files are restored to disk.
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08003299 public void settingsRestored() {
3300 // Verify caller is the system
3301 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
3302 throw new RuntimeException("settingsRestored() can only be called from the system process");
3303 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003304 // TODO: If necessary, make it work for secondary users as well. This currently assumes
3305 // restores only to the primary user
Joe Onorato8a9b2202010-02-26 18:56:32 -08003306 if (DEBUG) Slog.v(TAG, "settingsRestored");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003307 WallpaperData wallpaper = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003308 boolean success = false;
3309 synchronized (mLock) {
Christopher Tated7faf532016-02-25 12:43:38 -08003310 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatedb27b842016-02-25 14:39:17 -08003311 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tatead3c2592016-01-20 18:13:17 -08003312 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
Christopher Tated7faf532016-02-25 12:43:38 -08003313 wallpaper.allowBackup = true; // by definition if it was restored
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003314 if (wallpaper.nextWallpaperComponent != null
Justin Koh29c30162014-09-05 17:10:10 -07003315 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003316 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07003317 wallpaper, null)) {
Christopher Tatee3ab4d02009-12-16 14:03:31 -08003318 // No such live wallpaper or other failure; fall back to the default
3319 // live wallpaper (since the profile being restored indicated that the
3320 // user had selected a live rather than static one).
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07003321 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Christopher Tatee3ab4d02009-12-16 14:03:31 -08003322 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003323 success = true;
3324 } else {
Mike Clerona428b2c2009-11-15 22:53:08 -08003325 // If there's a wallpaper name, we use that. If that can't be loaded, then we
3326 // use the default.
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003327 if ("".equals(wallpaper.name)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003328 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
Mike Clerona428b2c2009-11-15 22:53:08 -08003329 success = true;
3330 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003331 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003332 success = restoreNamedResourceLocked(wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08003333 }
Christopher Tatead3c2592016-01-20 18:13:17 -08003334 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
3335 + " id=" + wallpaper.wallpaperId);
Mike Clerona428b2c2009-11-15 22:53:08 -08003336 if (success) {
wilsonshih81e10a72018-11-15 10:54:21 +08003337 generateCrop(wallpaper); // based on the new image + metadata
Christopher Tate41297ff2016-03-10 16:46:15 -08003338 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07003339 wallpaper, null);
Mike Clerona428b2c2009-11-15 22:53:08 -08003340 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003341 }
3342 }
3343
3344 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003345 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
3346 wallpaper.name = "";
Christopher Tatedb27b842016-02-25 14:39:17 -08003347 getWallpaperDir(UserHandle.USER_SYSTEM).delete();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003348 }
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07003349
3350 synchronized (mLock) {
Christopher Tatedb27b842016-02-25 14:39:17 -08003351 saveSettingsLocked(UserHandle.USER_SYSTEM);
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07003352 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003353 }
3354
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003355 // Restore the named resource bitmap to both source + crop files
wilsonshiha282bf72018-11-30 12:48:05 +08003356 private boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003357 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
3358 String resName = wallpaper.name.substring(4);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003359
3360 String pkg = null;
3361 int colon = resName.indexOf(':');
3362 if (colon > 0) {
3363 pkg = resName.substring(0, colon);
3364 }
3365
3366 String ident = null;
3367 int slash = resName.lastIndexOf('/');
3368 if (slash > 0) {
3369 ident = resName.substring(slash+1);
3370 }
3371
3372 String type = null;
3373 if (colon > 0 && slash > 0 && (slash-colon) > 1) {
3374 type = resName.substring(colon+1, slash);
3375 }
3376
3377 if (pkg != null && ident != null && type != null) {
3378 int resId = -1;
3379 InputStream res = null;
3380 FileOutputStream fos = null;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003381 FileOutputStream cos = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003382 try {
3383 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
3384 Resources r = c.getResources();
3385 resId = r.getIdentifier(resName, null, null);
3386 if (resId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003387 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003388 + " ident=" + ident);
3389 return false;
3390 }
3391
3392 res = r.openRawResource(resId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003393 if (wallpaper.wallpaperFile.exists()) {
3394 wallpaper.wallpaperFile.delete();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003395 wallpaper.cropFile.delete();
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07003396 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003397 fos = new FileOutputStream(wallpaper.wallpaperFile);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003398 cos = new FileOutputStream(wallpaper.cropFile);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003399
3400 byte[] buffer = new byte[32768];
3401 int amt;
3402 while ((amt=res.read(buffer)) > 0) {
3403 fos.write(buffer, 0, amt);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003404 cos.write(buffer, 0, amt);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003405 }
3406 // mWallpaperObserver will notice the close and send the change broadcast
3407
Joe Onorato8a9b2202010-02-26 18:56:32 -08003408 Slog.v(TAG, "Restored wallpaper: " + resName);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003409 return true;
3410 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003411 Slog.e(TAG, "Package name " + pkg + " not found");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003412 } catch (Resources.NotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003413 Slog.e(TAG, "Resource not found: " + resId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003414 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08003415 Slog.e(TAG, "IOException while restoring wallpaper ", e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003416 } finally {
Christopher Tatead3c2592016-01-20 18:13:17 -08003417 IoUtils.closeQuietly(res);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003418 if (fos != null) {
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07003419 FileUtils.sync(fos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003420 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003421 if (cos != null) {
3422 FileUtils.sync(cos);
3423 }
3424 IoUtils.closeQuietly(fos);
3425 IoUtils.closeQuietly(cos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07003426 }
3427 }
3428 }
3429 return false;
3430 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003431
Dianne Hackborneb034652009-09-07 00:49:58 -07003432 @Override
3433 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003434 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Dianne Hackborneb034652009-09-07 00:49:58 -07003435
Felipe Leme9584cb6c2020-01-17 13:30:36 -08003436 pw.print("mDefaultWallpaperComponent="); pw.println(mDefaultWallpaperComponent);
3437 pw.print("mImageWallpaper="); pw.println(mImageWallpaper);
3438
Dianne Hackborneb034652009-09-07 00:49:58 -07003439 synchronized (mLock) {
Adrian Roosc28e3a92016-04-14 10:47:52 -07003440 pw.println("System wallpaper state:");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003441 for (int i = 0; i < mWallpaperMap.size(); i++) {
3442 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
Christopher Tatead3c2592016-01-20 18:13:17 -08003443 pw.print(" User "); pw.print(wallpaper.userId);
wilsonshiha282bf72018-11-30 12:48:05 +08003444 pw.print(": id="); pw.println(wallpaper.wallpaperId);
3445 pw.println(" Display state:");
3446 forEachDisplayData(wpSize -> {
wilsonshih81e10a72018-11-15 10:54:21 +08003447 pw.print(" displayId=");
3448 pw.println(wpSize.mDisplayId);
3449 pw.print(" mWidth=");
3450 pw.print(wpSize.mWidth);
3451 pw.print(" mHeight=");
3452 pw.println(wpSize.mHeight);
3453 pw.print(" mPadding="); pw.println(wpSize.mPadding);
3454 });
Christopher Tate1e1e2e02016-01-25 15:34:36 -08003455 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07003456 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01003457 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07003458 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003459 if (wallpaper.connection != null) {
3460 WallpaperConnection conn = wallpaper.connection;
3461 pw.print(" Wallpaper connection ");
3462 pw.print(conn);
3463 pw.println(":");
3464 if (conn.mInfo != null) {
3465 pw.print(" mInfo.component=");
3466 pw.println(conn.mInfo.getComponent());
3467 }
wilsonshihde93f492018-11-01 21:23:40 +08003468 conn.forEachDisplayConnector(connector -> {
wilsonshiha282bf72018-11-30 12:48:05 +08003469 pw.print(" mDisplayId=");
wilsonshihde93f492018-11-01 21:23:40 +08003470 pw.println(connector.mDisplayId);
wilsonshiha282bf72018-11-30 12:48:05 +08003471 pw.print(" mToken=");
wilsonshihde93f492018-11-01 21:23:40 +08003472 pw.println(connector.mToken);
wilsonshiha282bf72018-11-30 12:48:05 +08003473 pw.print(" mEngine=");
wilsonshihde93f492018-11-01 21:23:40 +08003474 pw.println(connector.mEngine);
3475 });
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003476 pw.print(" mService=");
3477 pw.println(conn.mService);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08003478 pw.print(" mLastDiedTime=");
3479 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
3480 }
Dianne Hackborneb034652009-09-07 00:49:58 -07003481 }
Adrian Roosc28e3a92016-04-14 10:47:52 -07003482 pw.println("Lock wallpaper state:");
3483 for (int i = 0; i < mLockWallpaperMap.size(); i++) {
3484 WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
3485 pw.print(" User "); pw.print(wallpaper.userId);
wilsonshih81e10a72018-11-15 10:54:21 +08003486 pw.print(": id="); pw.println(wallpaper.wallpaperId);
Adrian Roosc28e3a92016-04-14 10:47:52 -07003487 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
Adrian Roosc28e3a92016-04-14 10:47:52 -07003488 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01003489 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Adrian Roosc28e3a92016-04-14 10:47:52 -07003490 }
wilsonshiha282bf72018-11-30 12:48:05 +08003491 pw.println("Fallback wallpaper state:");
3492 pw.print(" User "); pw.print(mFallbackWallpaper.userId);
3493 pw.print(": id="); pw.println(mFallbackWallpaper.wallpaperId);
3494 pw.print(" mCropHint="); pw.println(mFallbackWallpaper.cropHint);
3495 pw.print(" mName="); pw.println(mFallbackWallpaper.name);
3496 pw.print(" mAllowBackup="); pw.println(mFallbackWallpaper.allowBackup);
3497 if (mFallbackWallpaper.connection != null) {
3498 WallpaperConnection conn = mFallbackWallpaper.connection;
3499 pw.print(" Fallback Wallpaper connection ");
3500 pw.print(conn);
3501 pw.println(":");
3502 if (conn.mInfo != null) {
3503 pw.print(" mInfo.component=");
3504 pw.println(conn.mInfo.getComponent());
3505 }
3506 conn.forEachDisplayConnector(connector -> {
3507 pw.print(" mDisplayId=");
3508 pw.println(connector.mDisplayId);
3509 pw.print(" mToken=");
3510 pw.println(connector.mToken);
3511 pw.print(" mEngine=");
3512 pw.println(connector.mEngine);
3513 });
3514 pw.print(" mService=");
3515 pw.println(conn.mService);
3516 pw.print(" mLastDiedTime=");
3517 pw.println(mFallbackWallpaper.lastDiedTime - SystemClock.uptimeMillis());
3518 }
Dianne Hackborneb034652009-09-07 00:49:58 -07003519 }
3520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521}