blob: 547ab0ed443dba6363d4baf72135cd65c7bf0b78 [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;
21import static android.os.ParcelFileDescriptor.MODE_CREATE;
22import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
23import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
24import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070025import static android.view.Display.DEFAULT_DISPLAY;
26import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
Christopher Tate111bd4a2009-06-24 17:29:38 -070027
Lucas Dupin50ba9912017-07-14 11:55:05 -070028import android.annotation.NonNull;
Christopher Tatee409f0e2016-03-21 14:53:15 -070029import android.app.ActivityManager;
Amith Yamasani4e2820c2012-08-28 22:17:23 -070030import android.app.AppGlobals;
Benjamin Franzf3ece362015-02-11 10:51:10 +000031import android.app.AppOpsManager;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070032import android.app.IWallpaperManager;
33import android.app.IWallpaperManagerCallback;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070034import android.app.PendingIntent;
Sudheer Shanka2c4522c2016-08-27 20:53:28 -070035import android.app.UserSwitchObserver;
Lucas Dupin75ec3792017-06-29 14:07:18 -070036import android.app.WallpaperColors;
Dianne Hackborneb034652009-09-07 00:49:58 -070037import android.app.WallpaperInfo;
Jeff Sharkey28f08772014-04-16 09:41:58 -070038import android.app.WallpaperManager;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +010039import android.app.admin.DevicePolicyManager;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080040import android.app.backup.WallpaperBackupHelper;
Amith Yamasani13593602012-03-22 16:16:17 -070041import android.content.BroadcastReceiver;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070042import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.content.Context;
44import android.content.Intent;
Amith Yamasani13593602012-03-22 16:16:17 -070045import android.content.IntentFilter;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070046import android.content.ServiceConnection;
Amith Yamasani4e2820c2012-08-28 22:17:23 -070047import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.pm.PackageManager;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060049import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070050import android.content.pm.ResolveInfo;
51import android.content.pm.ServiceInfo;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070052import android.content.pm.UserInfo;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070053import android.content.res.Resources;
Tony Huangf0800fa2018-05-02 10:53:52 +080054import android.database.ContentObserver;
Christopher Tate1e1e2e02016-01-25 15:34:36 -080055import android.graphics.Bitmap;
56import android.graphics.BitmapFactory;
57import android.graphics.BitmapRegionDecoder;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -070058import android.graphics.Color;
John Spurlock41f64642013-11-04 13:48:38 -050059import android.graphics.Point;
Dianne Hackborn067e5f62014-09-07 23:14:30 -070060import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.os.Binder;
Dianne Hackborn284ac932009-08-28 10:34:25 -070062import android.os.Bundle;
Amith Yamasani13593602012-03-22 16:16:17 -070063import android.os.Environment;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060064import android.os.FileObserver;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070065import android.os.FileUtils;
Christopher Tatec349e59f2017-05-05 17:37:43 -070066import android.os.Handler;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070067import android.os.IBinder;
Lucas Dupin50ba9912017-07-14 11:55:05 -070068import android.os.IInterface;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -070069import android.os.IRemoteCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.ParcelFileDescriptor;
Lucas Dupin75ec3792017-06-29 14:07:18 -070071import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.RemoteCallbackList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060073import android.os.RemoteException;
rpcraig554cb0c2012-07-05 06:41:43 -040074import android.os.SELinux;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070075import android.os.ServiceManager;
Dianne Hackborn0cd48872009-08-13 18:51:59 -070076import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070077import android.os.UserHandle;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070078import android.os.UserManager;
Tony Huangf0800fa2018-05-02 10:53:52 +080079import android.provider.Settings;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070080import android.service.wallpaper.IWallpaperConnection;
81import android.service.wallpaper.IWallpaperEngine;
82import android.service.wallpaper.IWallpaperService;
83import android.service.wallpaper.WallpaperService;
Christopher Tate8347b632016-04-29 18:59:18 -070084import android.system.ErrnoException;
85import android.system.Os;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -070086import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080087import android.util.Slog;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080088import android.util.SparseArray;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070089import android.util.Xml;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -070090import android.view.Display;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070091import android.view.IWindowManager;
92import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060094import com.android.internal.R;
95import com.android.internal.content.PackageMonitor;
Christopher Tate190e8532016-07-11 11:35:34 -070096import com.android.internal.os.BackgroundThread;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060097import com.android.internal.util.DumpUtils;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060098import com.android.internal.util.FastXmlSerializer;
99import com.android.internal.util.JournaledFile;
100import com.android.server.EventLogTags;
Adrian Roosc3f915e2016-09-06 11:40:53 -0700101import com.android.server.FgThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600102import com.android.server.SystemService;
103
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900104import java.lang.reflect.InvocationTargetException;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600105import libcore.io.IoUtils;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700106
107import org.xmlpull.v1.XmlPullParser;
108import org.xmlpull.v1.XmlPullParserException;
109import org.xmlpull.v1.XmlSerializer;
110
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600111import java.io.BufferedOutputStream;
112import java.io.File;
113import java.io.FileDescriptor;
114import java.io.FileInputStream;
115import java.io.FileNotFoundException;
116import java.io.FileOutputStream;
117import java.io.IOException;
118import java.io.InputStream;
119import java.io.PrintWriter;
120import java.nio.charset.StandardCharsets;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400121import java.util.ArrayList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600122import java.util.Arrays;
123import java.util.List;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700124import java.util.Objects;
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900125import com.android.internal.R;
Christopher Tatead3c2592016-01-20 18:13:17 -0800126
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900127public class WallpaperManagerService extends IWallpaperManager.Stub
128 implements IWallpaperManagerService {
Amith Yamasani09e9cdc2013-11-06 14:54:50 -0800129 static final String TAG = "WallpaperManagerService";
Joe Onorato7e1693a2016-02-01 17:45:03 -0800130 static final boolean DEBUG = false;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700131 static final boolean DEBUG_LIVE = DEBUG || true;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700132
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600133 public static class Lifecycle extends SystemService {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900134 private IWallpaperManagerService mService;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600135
136 public Lifecycle(Context context) {
137 super(context);
138 }
139
140 @Override
141 public void onStart() {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900142 try {
143 final Class<? extends IWallpaperManagerService> klass =
144 (Class<? extends IWallpaperManagerService>)Class.forName(
145 getContext().getResources().getString(
146 R.string.config_wallpaperManagerServiceName));
147 mService = klass.getConstructor(Context.class).newInstance(getContext());
148 publishBinderService(Context.WALLPAPER_SERVICE, mService);
149 } catch (Exception exp) {
150 Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp);
151 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600152 }
153
154 @Override
155 public void onBootPhase(int phase) {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900156 if (mService != null) {
157 mService.onBootPhase(phase);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600158 }
159 }
160
161 @Override
162 public void onUnlockUser(int userHandle) {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900163 if (mService != null) {
164 mService.onUnlockUser(userHandle);
165 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600166 }
167 }
168
Christopher Tatebe132e62016-02-10 12:59:49 -0800169 final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700171 /**
172 * Minimum time between crashes of a wallpaper service for us to consider
173 * restarting it vs. just reverting to the static wallpaper.
174 */
175 static final long MIN_WALLPAPER_CRASH_TIME = 10000;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700176 static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800177 static final String WALLPAPER = "wallpaper_orig";
178 static final String WALLPAPER_CROP = "wallpaper";
Christopher Tatebe132e62016-02-10 12:59:49 -0800179 static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
180 static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800181 static final String WALLPAPER_INFO = "wallpaper_info.xml";
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700182
Christopher Tatebe132e62016-02-10 12:59:49 -0800183 // All the various per-user state files we need to be aware of
184 static final String[] sPerUserFiles = new String[] {
185 WALLPAPER, WALLPAPER_CROP,
186 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
187 WALLPAPER_INFO
188 };
189
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700190 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
192 * that the wallpaper has changed. The CREATE is triggered when there is no
193 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
Christopher Tate190e8532016-07-11 11:35:34 -0700194 * every time the wallpaper is changed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 */
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800196 private class WallpaperObserver extends FileObserver {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700197
Christopher Tatebe132e62016-02-10 12:59:49 -0800198 final int mUserId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800199 final WallpaperData mWallpaper;
200 final File mWallpaperDir;
201 final File mWallpaperFile;
Christopher Tatebe132e62016-02-10 12:59:49 -0800202 final File mWallpaperLockFile;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800203
204 public WallpaperObserver(WallpaperData wallpaper) {
205 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
Christopher Tateda058e22014-10-08 14:51:09 -0700206 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
Christopher Tatebe132e62016-02-10 12:59:49 -0800207 mUserId = wallpaper.userId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800208 mWallpaperDir = getWallpaperDir(wallpaper.userId);
209 mWallpaper = wallpaper;
210 mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
Christopher Tatebe132e62016-02-10 12:59:49 -0800211 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800212 }
213
Christopher Tatebe132e62016-02-10 12:59:49 -0800214 private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
215 WallpaperData wallpaper = null;
216 synchronized (mLock) {
217 if (lockChanged) {
218 wallpaper = mLockWallpaperMap.get(mUserId);
219 }
220 if (wallpaper == null) {
221 // no lock-specific wallpaper exists, or sys case, handled together
222 wallpaper = mWallpaperMap.get(mUserId);
223 }
224 }
225 return (wallpaper != null) ? wallpaper : mWallpaper;
226 }
227
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800228 @Override
229 public void onEvent(int event, String path) {
230 if (path == null) {
231 return;
232 }
Christopher Tated7faf532016-02-25 12:43:38 -0800233 final boolean moved = (event == MOVED_TO);
234 final boolean written = (event == CLOSE_WRITE || moved);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800235 final File changedFile = new File(mWallpaperDir, path);
236
Christopher Tatebe132e62016-02-10 12:59:49 -0800237 // System and system+lock changes happen on the system wallpaper input file;
238 // lock-only changes happen on the dedicated lock wallpaper input file
239 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
240 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700241 int notifyColorsWhich = 0;
Christopher Tatebe132e62016-02-10 12:59:49 -0800242 WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
243
244 if (DEBUG) {
245 Slog.v(TAG, "Wallpaper file change: evt=" + event
246 + " path=" + path
247 + " sys=" + sysWallpaperChanged
248 + " lock=" + lockWallpaperChanged
249 + " imagePending=" + wallpaper.imageWallpaperPending
250 + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
251 + " written=" + written);
252 }
Christopher Tate8347b632016-04-29 18:59:18 -0700253
254 if (moved && lockWallpaperChanged) {
255 // We just migrated sys -> lock to preserve imagery for an impending
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700256 // new system-only wallpaper. Tell keyguard about it and make sure it
257 // has the right SELinux label.
Christopher Tate8347b632016-04-29 18:59:18 -0700258 if (DEBUG) {
259 Slog.i(TAG, "Sys -> lock MOVED_TO");
260 }
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700261 SELinux.restorecon(changedFile);
Christopher Tate8347b632016-04-29 18:59:18 -0700262 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700263 notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK);
Christopher Tate8347b632016-04-29 18:59:18 -0700264 return;
265 }
266
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800267 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800268 if (sysWallpaperChanged || lockWallpaperChanged) {
269 notifyCallbacksLocked(wallpaper);
270 if (wallpaper.wallpaperComponent == null
Christopher Tateda058e22014-10-08 14:51:09 -0700271 || event != CLOSE_WRITE // includes the MOVED_TO case
Christopher Tatebe132e62016-02-10 12:59:49 -0800272 || wallpaper.imageWallpaperPending) {
Christopher Tateda058e22014-10-08 14:51:09 -0700273 if (written) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800274 // The image source has finished writing the source image,
275 // so we now produce the crop rect (in the background), and
276 // only publish the new displayable (sub)image as a result
277 // of that work.
Christopher Tatebe132e62016-02-10 12:59:49 -0800278 if (DEBUG) {
279 Slog.v(TAG, "Wallpaper written; generating crop");
280 }
Christopher Tateebadfb12016-07-25 14:50:08 -0700281 SELinux.restorecon(changedFile);
Christopher Tated7faf532016-02-25 12:43:38 -0800282 if (moved) {
283 // This is a restore, so generate the crop using any just-restored new
284 // crop guidelines, making sure to preserve our local dimension hints.
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700285 // We also make sure to reapply the correct SELinux label.
Christopher Tated7faf532016-02-25 12:43:38 -0800286 if (DEBUG) {
287 Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
288 }
289 loadSettingsLocked(wallpaper.userId, true);
290 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800291 generateCrop(wallpaper);
292 if (DEBUG) {
293 Slog.v(TAG, "Crop done; invoking completion callback");
294 }
295 wallpaper.imageWallpaperPending = false;
Christopher Tatebe132e62016-02-10 12:59:49 -0800296 if (sysWallpaperChanged) {
297 // If this was the system wallpaper, rebind...
298 bindWallpaperComponentLocked(mImageWallpaper, true,
299 false, wallpaper, null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700300 notifyColorsWhich |= FLAG_SYSTEM;
Christopher Tatebe132e62016-02-10 12:59:49 -0800301 }
302 if (lockWallpaperChanged
Christopher Tateedf7d042016-03-29 18:24:25 -0700303 || (wallpaper.whichPending & FLAG_LOCK) != 0) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800304 if (DEBUG) {
Christopher Tatedb27b842016-02-25 14:39:17 -0800305 Slog.i(TAG, "Lock-relevant wallpaper changed");
Christopher Tatebe132e62016-02-10 12:59:49 -0800306 }
Christopher Tatedb27b842016-02-25 14:39:17 -0800307 // either a lock-only wallpaper commit or a system+lock event.
308 // if it's system-plus-lock we need to wipe the lock bookkeeping;
309 // we're falling back to displaying the system wallpaper there.
310 if (!lockWallpaperChanged) {
311 mLockWallpaperMap.remove(wallpaper.userId);
312 }
313 // and in any case, tell keyguard about it
Christopher Tate8347b632016-04-29 18:59:18 -0700314 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700315 notifyColorsWhich |= FLAG_LOCK;
Christopher Tatebe132e62016-02-10 12:59:49 -0800316 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700317
Christopher Tatedb27b842016-02-25 14:39:17 -0800318 saveSettingsLocked(wallpaper.userId);
Christopher Tate8efbe0d2017-08-29 16:50:13 -0700319
320 // Publish completion *after* we've persisted the changes
321 if (wallpaper.setComplete != null) {
322 try {
323 wallpaper.setComplete.onWallpaperChanged();
324 } catch (RemoteException e) {
325 // if this fails we don't really care; the setting app may just
326 // have crashed and that sort of thing is a fact of life.
327 }
328 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 }
331 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800332 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700333
334 // Outside of the lock since it will synchronize itself
335 if (notifyColorsWhich != 0) {
336 notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
337 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800338 }
339 }
340
Tony Huangf0800fa2018-05-02 10:53:52 +0800341 /**
342 * Observes changes of theme settings. It will check whether to call
343 * notifyWallpaperColorsChanged by the current theme and updated theme.
344 * The light theme and dark theme are controlled by the hint values in Wallpaper colors,
345 * threrfore, if light theme mode is chosen, HINT_SUPPORTS_DARK_THEME in hint will be
346 * removed and then notify listeners.
347 */
348 private class ThemeSettingsObserver extends ContentObserver {
349
350 public ThemeSettingsObserver(Handler handler) {
351 super(handler);
352 }
353
354 public void startObserving(Context context) {
355 context.getContentResolver().registerContentObserver(
356 Settings.Secure.getUriFor(Settings.Secure.THEME_MODE),
357 false,
358 this);
359 }
360
361 public void stopObserving(Context context) {
362 context.getContentResolver().unregisterContentObserver(this);
363 }
364
365 @Override
366 public void onChange(boolean selfChange) {
367 onThemeSettingsChanged();
368 }
369 }
370
371 /**
372 * Check whether to call notifyWallpaperColorsChanged. Assumed that the theme mode
373 * was wallpaper theme mode and dark wallpaper was set, therefoe, the theme was dark.
374 * Then theme mode changing to dark theme mode, however, theme should not update since
375 * theme was dark already.
376 */
377 private boolean needUpdateLocked(WallpaperColors colors, int themeMode) {
378 if (colors == null) {
379 return false;
380 }
381
382 if (themeMode == mThemeMode) {
383 return false;
384 }
385
386 boolean result = true;
387 boolean supportDarkTheme =
388 (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
389 switch (themeMode) {
390 case Settings.Secure.THEME_MODE_WALLPAPER:
391 if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) {
392 result = supportDarkTheme;
393 } else {
394 result = !supportDarkTheme;
395 }
396 break;
397 case Settings.Secure.THEME_MODE_LIGHT:
398 if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) {
399 result = supportDarkTheme;
400 }
401 break;
402 case Settings.Secure.THEME_MODE_DARK:
403 if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) {
404 result = !supportDarkTheme;
405 }
406 break;
407 default:
408 Slog.w(TAG, "unkonwn theme mode " + themeMode);
409 return false;
410 }
411 mThemeMode = themeMode;
412 return result;
413 }
414
415 void onThemeSettingsChanged() {
416 WallpaperData wallpaper;
417 synchronized (mLock) {
418 wallpaper = mWallpaperMap.get(mCurrentUserId);
419 int updatedThemeMode = Settings.Secure.getInt(
420 mContext.getContentResolver(), Settings.Secure.THEME_MODE,
421 Settings.Secure.THEME_MODE_WALLPAPER);
422
423 if (DEBUG) {
424 Slog.v(TAG, "onThemeSettingsChanged, mode = " + updatedThemeMode);
425 }
426
427 if (!needUpdateLocked(wallpaper.primaryColors, updatedThemeMode)) {
428 return;
429 }
430 }
431
432 if (wallpaper != null) {
433 notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM);
434 }
435 }
436
Christopher Tate8347b632016-04-29 18:59:18 -0700437 void notifyLockWallpaperChanged() {
438 final IWallpaperManagerCallback cb = mKeyguardListener;
439 if (cb != null) {
440 try {
441 cb.onWallpaperChanged();
442 } catch (RemoteException e) {
443 // Oh well it went away; no big deal
444 }
445 }
446 }
447
Lucas Dupin50ba9912017-07-14 11:55:05 -0700448 private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700449 boolean needsExtraction;
450 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700451 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
452 mColorsChangedListeners.get(wallpaper.userId);
453 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
454 mColorsChangedListeners.get(UserHandle.USER_ALL);
455 // No-op until someone is listening to it.
456 if (emptyCallbackList(currentUserColorListeners) &&
457 emptyCallbackList(userAllColorListeners)) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700458 return;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700459 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700460
461 if (DEBUG) {
462 Slog.v(TAG, "notifyWallpaperColorsChanged " + which);
463 }
464
465 needsExtraction = wallpaper.primaryColors == null;
466 }
467
Lucas Dupin75ec3792017-06-29 14:07:18 -0700468 // Let's notify the current values, it's fine if it's null, it just means
469 // that we don't know yet.
Lucas Dupin50ba9912017-07-14 11:55:05 -0700470 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700471
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700472 if (needsExtraction) {
473 extractColors(wallpaper);
Lucas Dupin50ba9912017-07-14 11:55:05 -0700474 synchronized (mLock) {
475 // Don't need to notify if nothing changed.
476 if (wallpaper.primaryColors == null) {
477 return;
478 }
479 }
480 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700481 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700482 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700483
Lucas Dupin50ba9912017-07-14 11:55:05 -0700484 private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
485 return (list == null || list.getRegisteredCallbackCount() == 0);
486 }
487
488 private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
489 int userId) {
Lucas Dupin75ec3792017-06-29 14:07:18 -0700490 final IWallpaperManagerCallback keyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400491 final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700492 synchronized (mLock) {
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400493 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
494 mColorsChangedListeners.get(userId);
495 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
496 mColorsChangedListeners.get(UserHandle.USER_ALL);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700497 keyguardListener = mKeyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400498
499 if (currentUserColorListeners != null) {
500 final int count = currentUserColorListeners.beginBroadcast();
501 for (int i = 0; i < count; i++) {
502 colorListeners.add(currentUserColorListeners.getBroadcastItem(i));
503 }
504 currentUserColorListeners.finishBroadcast();
505 }
506
507 if (userAllColorListeners != null) {
508 final int count = userAllColorListeners.beginBroadcast();
509 for (int i = 0; i < count; i++) {
510 colorListeners.add(userAllColorListeners.getBroadcastItem(i));
511 }
512 userAllColorListeners.finishBroadcast();
513 }
Tony Huangf0800fa2018-05-02 10:53:52 +0800514 wallpaperColors = getThemeColorsLocked(wallpaperColors);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700515 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700516
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400517 final int count = colorListeners.size();
518 for (int i = 0; i < count; i++) {
519 try {
520 colorListeners.get(i).onWallpaperColorsChanged(wallpaperColors, which, userId);
521 } catch (RemoteException e) {
522 // Callback is gone, it's not necessary to unregister it since
523 // RemoteCallbackList#getBroadcastItem will take care of it.
Lucas Dupin75ec3792017-06-29 14:07:18 -0700524 }
525 }
526
527 if (keyguardListener != null) {
528 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700529 keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700530 } catch (RemoteException e) {
531 // Oh well it went away; no big deal
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700532 }
533 }
534 }
535
Lucas Dupinbcae5852017-05-03 12:42:58 -0700536 /**
537 * We can easily extract colors from an ImageWallpaper since it's only a bitmap.
Lucas Dupin284836b2017-06-23 15:28:41 -0700538 * In this case, using the crop is more than enough. Live wallpapers are just ignored.
Lucas Dupinbcae5852017-05-03 12:42:58 -0700539 *
540 * @param wallpaper a wallpaper representation
541 */
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700542 private void extractColors(WallpaperData wallpaper) {
543 String cropFile = null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700544 int wallpaperId;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700545
Lucas Dupinbcae5852017-05-03 12:42:58 -0700546 synchronized (mLock) {
Lucas Dupin284836b2017-06-23 15:28:41 -0700547 // Not having a wallpaperComponent means it's a lock screen wallpaper.
548 final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
Lucas Dupinbcae5852017-05-03 12:42:58 -0700549 || wallpaper.wallpaperComponent == null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700550 if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
551 cropFile = wallpaper.cropFile.getAbsolutePath();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700552 }
553 wallpaperId = wallpaper.wallpaperId;
554 }
555
Lucas Dupin84b89d92017-05-09 12:16:19 -0700556 WallpaperColors colors = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700557 if (cropFile != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700558 Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
Lucas Dupin284836b2017-06-23 15:28:41 -0700559 if (bitmap != null) {
Lucas Dupinb5e50532018-05-24 16:33:14 +0000560 colors = WallpaperColors.fromBitmap(bitmap);
Lucas Dupin284836b2017-06-23 15:28:41 -0700561 bitmap.recycle();
562 }
Lucas Dupinbcae5852017-05-03 12:42:58 -0700563 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700564
Lucas Dupin84b89d92017-05-09 12:16:19 -0700565 if (colors == null) {
Lucas Dupinbcae5852017-05-03 12:42:58 -0700566 Slog.w(TAG, "Cannot extract colors because wallpaper could not be read.");
567 return;
568 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700569
Lucas Dupinbcae5852017-05-03 12:42:58 -0700570 synchronized (mLock) {
571 if (wallpaper.wallpaperId == wallpaperId) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700572 wallpaper.primaryColors = colors;
Lucas Dupin75ec3792017-06-29 14:07:18 -0700573 // Now that we have the colors, let's save them into the xml
574 // to avoid having to run this again.
575 saveSettingsLocked(wallpaper.userId);
Lucas Dupinbcae5852017-05-03 12:42:58 -0700576 } else {
577 Slog.w(TAG, "Not setting primary colors since wallpaper changed");
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700578 }
579 }
580 }
581
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800582 /**
Tony Huangf0800fa2018-05-02 10:53:52 +0800583 * We can easily change theme by modified colors hint. This function will check
584 * current theme mode and return the WallpaperColors fit current theme mode.
585 * If color need modified, it will return a copied WallpaperColors which
586 * its ColorsHint is modified to fit current theme mode.
587 *
588 * @param colors a wallpaper primary colors representation
589 */
590 private WallpaperColors getThemeColorsLocked(WallpaperColors colors) {
591 if (colors == null) {
592 Slog.w(TAG, "Cannot get theme colors because WallpaperColors is null.");
593 return null;
594 }
595
596 int colorHints = colors.getColorHints();
597 boolean supportDarkTheme = (colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
598 if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER ||
599 (mThemeMode == Settings.Secure.THEME_MODE_LIGHT && !supportDarkTheme) ||
600 (mThemeMode == Settings.Secure.THEME_MODE_DARK && supportDarkTheme)) {
601 return colors;
602 }
603
604 WallpaperColors themeColors = new WallpaperColors(colors.getPrimaryColor(),
605 colors.getSecondaryColor(), colors.getTertiaryColor());
606
607 if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) {
608 colorHints &= ~WallpaperColors.HINT_SUPPORTS_DARK_THEME;
609 } else if (mThemeMode == Settings.Secure.THEME_MODE_DARK) {
610 colorHints |= WallpaperColors.HINT_SUPPORTS_DARK_THEME;
611 }
612 themeColors.setColorHints(colorHints);
613 return themeColors;
614 }
615
616 /**
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800617 * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
618 * for display.
619 */
620 private void generateCrop(WallpaperData wallpaper) {
621 boolean success = false;
Christopher Tate1a96b632016-03-22 15:25:42 -0700622
623 Rect cropHint = new Rect(wallpaper.cropHint);
Christopher Tatebe132e62016-02-10 12:59:49 -0800624
625 if (DEBUG) {
626 Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
627 + Integer.toHexString(wallpaper.whichPending)
Christopher Tate1a96b632016-03-22 15:25:42 -0700628 + " to " + wallpaper.cropFile.getName()
629 + " crop=(" + cropHint.width() + 'x' + cropHint.height()
630 + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
Christopher Tatebe132e62016-02-10 12:59:49 -0800631 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800632
633 // Analyse the source; needed in multiple cases
634 BitmapFactory.Options options = new BitmapFactory.Options();
635 options.inJustDecodeBounds = true;
636 BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
Christopher Tate1a96b632016-03-22 15:25:42 -0700637 if (options.outWidth <= 0 || options.outHeight <= 0) {
Joe LaPennac298b162016-05-02 15:25:50 -0700638 Slog.w(TAG, "Invalid wallpaper data");
Christopher Tate1a96b632016-03-22 15:25:42 -0700639 success = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800640 } else {
Christopher Tate1a96b632016-03-22 15:25:42 -0700641 boolean needCrop = false;
642 boolean needScale = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800643
Christopher Tate1a96b632016-03-22 15:25:42 -0700644 // Empty crop means use the full image
645 if (cropHint.isEmpty()) {
646 cropHint.left = cropHint.top = 0;
647 cropHint.right = options.outWidth;
648 cropHint.bottom = options.outHeight;
649 } else {
650 // force the crop rect to lie within the measured bounds
651 cropHint.offset(
652 (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
653 (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
654
Adrian Roos5c97ff22016-08-31 10:25:38 -0700655 // If the crop hint was larger than the image we just overshot. Patch things up.
656 if (cropHint.left < 0) {
657 cropHint.left = 0;
658 }
659 if (cropHint.top < 0) {
660 cropHint.top = 0;
661 }
662
Christopher Tate1a96b632016-03-22 15:25:42 -0700663 // Don't bother cropping if what we're left with is identity
Christopher Tateebadfb12016-07-25 14:50:08 -0700664 needCrop = (options.outHeight > cropHint.height()
Adrian Roos5c97ff22016-08-31 10:25:38 -0700665 || options.outWidth > cropHint.width());
Christopher Tate1a96b632016-03-22 15:25:42 -0700666 }
667
668 // scale if the crop height winds up not matching the recommended metrics
669 needScale = (wallpaper.height != cropHint.height());
670
671 if (DEBUG) {
672 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
673 Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
674 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
675 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
676 }
677
678 if (!needCrop && !needScale) {
679 // Simple case: the nominal crop fits what we want, so we take
680 // the whole thing and just copy the image file directly.
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800681 if (DEBUG) {
Christopher Tate1a96b632016-03-22 15:25:42 -0700682 Slog.v(TAG, "Null crop of new wallpaper; copying");
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800683 }
Christopher Tate1a96b632016-03-22 15:25:42 -0700684 success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
685 if (!success) {
686 wallpaper.cropFile.delete();
687 // TODO: fall back to default wallpaper in this case
688 }
689 } else {
690 // Fancy case: crop and scale. First, we decode and scale down if appropriate.
691 FileOutputStream f = null;
692 BufferedOutputStream bos = null;
693 try {
694 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
695 wallpaper.wallpaperFile.getAbsolutePath(), false);
696
697 // This actually downsamples only by powers of two, but that's okay; we do
698 // a proper scaling blit later. This is to minimize transient RAM use.
699 // We calculate the largest power-of-two under the actual ratio rather than
700 // just let the decode take care of it because we also want to remap where the
701 // cropHint rectangle lies in the decoded [super]rect.
702 final BitmapFactory.Options scaler;
703 final int actualScale = cropHint.height() / wallpaper.height;
704 int scale = 1;
705 while (2*scale < actualScale) {
706 scale *= 2;
707 }
708 if (scale > 1) {
709 scaler = new BitmapFactory.Options();
710 scaler.inSampleSize = scale;
711 if (DEBUG) {
712 Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
713 }
714 } else {
715 scaler = null;
716 }
717 Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
718 decoder.recycle();
719
720 if (cropped == null) {
721 Slog.e(TAG, "Could not decode new wallpaper");
722 } else {
723 // We've got the extracted crop; now we want to scale it properly to
724 // the desired rectangle. That's a height-biased operation: make it
725 // fit the hinted height, and accept whatever width we end up with.
726 cropHint.offsetTo(0, 0);
727 cropHint.right /= scale; // adjust by downsampling factor
728 cropHint.bottom /= scale;
729 final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
730 if (DEBUG) {
731 Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
732 }
733 final int destWidth = (int)(cropHint.width() * heightR);
734 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
735 destWidth, wallpaper.height, true);
736 if (DEBUG) {
737 Slog.v(TAG, "Final extract:");
738 Slog.v(TAG, " dims: w=" + wallpaper.width
739 + " h=" + wallpaper.height);
740 Slog.v(TAG, " out: w=" + finalCrop.getWidth()
741 + " h=" + finalCrop.getHeight());
742 }
743
744 f = new FileOutputStream(wallpaper.cropFile);
745 bos = new BufferedOutputStream(f, 32*1024);
Christopher Tatec484f542016-05-11 14:31:34 -0700746 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
Christopher Tate1a96b632016-03-22 15:25:42 -0700747 bos.flush(); // don't rely on the implicit flush-at-close when noting success
748 success = true;
749 }
750 } catch (Exception e) {
751 if (DEBUG) {
752 Slog.e(TAG, "Error decoding crop", e);
753 }
754 } finally {
755 IoUtils.closeQuietly(bos);
756 IoUtils.closeQuietly(f);
757 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800758 }
759 }
760
761 if (!success) {
762 Slog.e(TAG, "Unable to apply new wallpaper");
763 wallpaper.cropFile.delete();
764 }
765
766 if (wallpaper.cropFile.exists()) {
767 boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
768 if (DEBUG) {
769 Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
770 }
771 }
772 }
773
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700774 final Context mContext;
775 final IWindowManager mIWindowManager;
Amith Yamasani4e2820c2012-08-28 22:17:23 -0700776 final IPackageManager mIPackageManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800777 final MyPackageMonitor mMonitor;
Benjamin Franzf3ece362015-02-11 10:51:10 +0000778 final AppOpsManager mAppOpsManager;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700779 /**
780 * Map of color listeners per user id.
781 * The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
782 */
783 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> mColorsChangedListeners;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800784 WallpaperData mLastWallpaper;
Christopher Tatebe132e62016-02-10 12:59:49 -0800785 IWallpaperManagerCallback mKeyguardListener;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600786 boolean mWaitingForUnlock;
Christopher Tate762dfd12016-10-10 17:44:48 -0700787 boolean mShuttingDown;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788
Justin Koh29c30162014-09-05 17:10:10 -0700789 /**
Christopher Tatead3c2592016-01-20 18:13:17 -0800790 * ID of the current wallpaper, changed every time anything sets a wallpaper.
791 * This is used for external detection of wallpaper update activity.
792 */
793 int mWallpaperId;
794
795 /**
Justin Koh29c30162014-09-05 17:10:10 -0700796 * Name of the component used to display bitmap wallpapers from either the gallery or
797 * built-in wallpapers.
798 */
799 final ComponentName mImageWallpaper;
800
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700801 /**
802 * Name of the default wallpaper component; might be different from mImageWallpaper
803 */
804 final ComponentName mDefaultWallpaperComponent;
805
Christopher Tatebe132e62016-02-10 12:59:49 -0800806 final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
807 final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
Dianne Hackborn07213e62011-08-24 20:05:39 -0700808
Christopher Tate38a5dc32016-07-20 15:10:18 -0700809 final SparseArray<Boolean> mUserRestorecon = new SparseArray<Boolean>();
Jaekyun Seokad7d90f2018-04-04 01:57:18 +0900810 int mCurrentUserId = UserHandle.USER_NULL;
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700811 boolean mInAmbientMode;
Tony Huangf0800fa2018-05-02 10:53:52 +0800812 int mThemeMode;
Dianne Hackborn07213e62011-08-24 20:05:39 -0700813
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800814 static class WallpaperData {
815
816 int userId;
817
Christopher Tatebe132e62016-02-10 12:59:49 -0800818 final File wallpaperFile; // source image
819 final File cropFile; // eventual destination
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800820
821 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800822 * True while the client is writing a new wallpaper
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800823 */
824 boolean imageWallpaperPending;
825
826 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800827 * Which new wallpapers are being written; mirrors the 'which'
828 * selector bit field to setWallpaper().
829 */
830 int whichPending;
831
832 /**
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800833 * Callback once the set + crop is finished
834 */
835 IWallpaperManagerCallback setComplete;
836
837 /**
Christopher Tated7faf532016-02-25 12:43:38 -0800838 * Is the OS allowed to back up this wallpaper imagery?
839 */
840 boolean allowBackup;
841
842 /**
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800843 * Resource name if using a picture from the wallpaper gallery
844 */
845 String name = "";
846
847 /**
848 * The component name of the currently set live wallpaper.
849 */
850 ComponentName wallpaperComponent;
851
852 /**
853 * The component name of the wallpaper that should be set next.
854 */
855 ComponentName nextWallpaperComponent;
856
Christopher Tatead3c2592016-01-20 18:13:17 -0800857 /**
858 * The ID of this wallpaper
859 */
860 int wallpaperId;
861
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700862 /**
863 * Primary colors histogram
864 */
865 WallpaperColors primaryColors;
866
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800867 WallpaperConnection connection;
868 long lastDiedTime;
869 boolean wallpaperUpdating;
870 WallpaperObserver wallpaperObserver;
Tony Huangf0800fa2018-05-02 10:53:52 +0800871 ThemeSettingsObserver themeSettingsObserver;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800872
873 /**
874 * List of callbacks registered they should each be notified when the wallpaper is changed.
875 */
876 private RemoteCallbackList<IWallpaperManagerCallback> callbacks
877 = new RemoteCallbackList<IWallpaperManagerCallback>();
878
879 int width = -1;
880 int height = -1;
881
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800882 /**
883 * The crop hint supplied for displaying a subset of the source image
884 */
885 final Rect cropHint = new Rect(0, 0, 0, 0);
886
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700887 final Rect padding = new Rect(0, 0, 0, 0);
888
Christopher Tatebe132e62016-02-10 12:59:49 -0800889 WallpaperData(int userId, String inputFileName, String cropFileName) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800890 this.userId = userId;
Christopher Tatebe132e62016-02-10 12:59:49 -0800891 final File wallpaperDir = getWallpaperDir(userId);
892 wallpaperFile = new File(wallpaperDir, inputFileName);
893 cropFile = new File(wallpaperDir, cropFileName);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800894 }
895
Christopher Tatebe132e62016-02-10 12:59:49 -0800896 // Called during initialization of a given user's wallpaper bookkeeping
Christopher Tate41297ff2016-03-10 16:46:15 -0800897 boolean cropExists() {
898 return cropFile.exists();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800899 }
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700900
901 boolean sourceExists() {
902 return wallpaperFile.exists();
903 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800904 }
905
Christopher Tatead3c2592016-01-20 18:13:17 -0800906 int makeWallpaperIdLocked() {
907 do {
908 ++mWallpaperId;
909 } while (mWallpaperId == 0);
910 return mWallpaperId;
911 }
912
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700913 class WallpaperConnection extends IWallpaperConnection.Stub
914 implements ServiceConnection {
Adrian Roosc3f915e2016-09-06 11:40:53 -0700915
916 /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
917 * middle of an update). If exceeded, the wallpaper gets reset to the system default. */
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700918 private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000;
Adrian Roosc3f915e2016-09-06 11:40:53 -0700919
Dianne Hackborneb034652009-09-07 00:49:58 -0700920 final WallpaperInfo mInfo;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700921 final Binder mToken = new Binder();
922 IWallpaperService mService;
923 IWallpaperEngine mEngine;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800924 WallpaperData mWallpaper;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700925 IRemoteCallback mReply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926
Michael Wright5203a8b2013-10-03 14:16:42 -0700927 boolean mDimensionsChanged = false;
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700928 boolean mPaddingChanged = false;
Michael Wright5203a8b2013-10-03 14:16:42 -0700929
Adrian Roosc3f915e2016-09-06 11:40:53 -0700930 private Runnable mResetRunnable = () -> {
931 synchronized (mLock) {
Christopher Tate762dfd12016-10-10 17:44:48 -0700932 if (mShuttingDown) {
933 // Don't expect wallpaper services to relaunch during shutdown
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700934 if (DEBUG_LIVE) {
Christopher Tate762dfd12016-10-10 17:44:48 -0700935 Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
936 }
937 return;
938 }
939
Adrian Roosc3f915e2016-09-06 11:40:53 -0700940 if (!mWallpaper.wallpaperUpdating
941 && mWallpaper.userId == mCurrentUserId) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700942 Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
943 + ", reverting to built-in wallpaper!");
Adrian Roosc3f915e2016-09-06 11:40:53 -0700944 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
945 null);
946 }
947 }
948 };
949
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800950 public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700951 mInfo = info;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800952 mWallpaper = wallpaper;
Dianne Hackborneb034652009-09-07 00:49:58 -0700953 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700954
955 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700956 public void onServiceConnected(ComponentName name, IBinder service) {
957 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800958 if (mWallpaper.connection == this) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700959 mService = IWallpaperService.Stub.asInterface(service);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800960 attachServiceLocked(this, mWallpaper);
Dianne Hackborneb034652009-09-07 00:49:58 -0700961 // XXX should probably do saveSettingsLocked() later
962 // when we have an engine, but I'm not sure about
963 // locking there and anyway we always need to be able to
964 // recover if there is something wrong.
Christopher Tatedb27b842016-02-25 14:39:17 -0800965 saveSettingsLocked(mWallpaper.userId);
Adrian Roosc3f915e2016-09-06 11:40:53 -0700966 FgThread.getHandler().removeCallbacks(mResetRunnable);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700967 }
968 }
969 }
970
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700971 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700972 public void onServiceDisconnected(ComponentName name) {
973 synchronized (mLock) {
Christopher Tatec349e59f2017-05-05 17:37:43 -0700974 Slog.w(TAG, "Wallpaper service gone: " + name);
975 if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
976 Slog.e(TAG, "Does not match expected wallpaper component "
977 + mWallpaper.wallpaperComponent);
978 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700979 mService = null;
980 mEngine = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800981 if (mWallpaper.connection == this) {
Christopher Tatec349e59f2017-05-05 17:37:43 -0700982 // There is an inherent ordering race between this callback and the
983 // package monitor that receives notice that a package is being updated,
984 // so we cannot quite trust at this moment that we know for sure that
985 // this is not an update. If we think this is a genuine non-update
986 // wallpaper outage, we do our "wait for reset" work as a continuation,
987 // a short time in the future, specifically to allow any pending package
988 // update message on this same looper thread to be processed.
989 if (!mWallpaper.wallpaperUpdating) {
990 mContext.getMainThreadHandler().postDelayed(() -> processDisconnect(this),
991 1000);
992 }
993 }
994 }
995 }
996
Tetsutoki Shiozawa06919212018-02-02 14:18:43 +0900997 public void scheduleTimeoutLocked() {
998 // If we didn't reset it right away, do so after we couldn't connect to
999 // it for an extended amount of time to avoid having a black wallpaper.
1000 final Handler fgHandler = FgThread.getHandler();
1001 fgHandler.removeCallbacks(mResetRunnable);
1002 fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
1003 if (DEBUG_LIVE) {
1004 Slog.i(TAG, "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
1005 }
1006 }
1007
Christopher Tatec349e59f2017-05-05 17:37:43 -07001008 private void processDisconnect(final ServiceConnection connection) {
1009 synchronized (mLock) {
1010 // The wallpaper disappeared. If this isn't a system-default one, track
1011 // crashes and fall back to default if it continues to misbehave.
1012 if (connection == mWallpaper.connection) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001013 final ComponentName wpService = mWallpaper.wallpaperComponent;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001014 if (!mWallpaper.wallpaperUpdating
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001015 && mWallpaper.userId == mCurrentUserId
1016 && !Objects.equals(mDefaultWallpaperComponent, wpService)
1017 && !Objects.equals(mImageWallpaper, wpService)) {
Selim Cinekebebadb2014-03-05 22:17:26 +01001018 // There is a race condition which causes
1019 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is
1020 // currently updating since the broadcast notifying us is async.
1021 // This race is overcome by the general rule that we only reset the
1022 // wallpaper if its service was shut down twice
1023 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
1024 if (mWallpaper.lastDiedTime != 0
1025 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
Christopher Tatec349e59f2017-05-05 17:37:43 -07001026 > SystemClock.uptimeMillis()) {
Selim Cinekebebadb2014-03-05 22:17:26 +01001027 Slog.w(TAG, "Reverting to built-in wallpaper!");
Christopher Tateedf7d042016-03-29 18:24:25 -07001028 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Selim Cinekebebadb2014-03-05 22:17:26 +01001029 } else {
1030 mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
Adrian Roosc3f915e2016-09-06 11:40:53 -07001031
Tetsutoki Shiozawa06919212018-02-02 14:18:43 +09001032 clearWallpaperComponentLocked(mWallpaper);
1033 if (bindWallpaperComponentLocked(
1034 wpService, false, false, mWallpaper, null)) {
1035 mWallpaper.connection.scheduleTimeoutLocked();
1036 } else {
1037 Slog.w(TAG, "Reverting to built-in wallpaper!");
1038 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001039 }
Selim Cinekebebadb2014-03-05 22:17:26 +01001040 }
Christopher Tatec349e59f2017-05-05 17:37:43 -07001041 final String flattened = wpService.flattenToString();
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -07001042 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
Filip Gruszczynski5a589432014-10-14 12:06:06 -07001043 flattened.substring(0, Math.min(flattened.length(),
1044 MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001045 }
Christopher Tatec349e59f2017-05-05 17:37:43 -07001046 } else {
1047 if (DEBUG_LIVE) {
1048 Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring");
1049 }
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001050 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001051 }
1052 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001053
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001054 /**
1055 * Called by a live wallpaper if its colors have changed.
1056 * @param primaryColors representation of wallpaper primary colors
1057 */
1058 @Override
1059 public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
1060 int which;
1061 synchronized (mLock) {
1062 // Do not broadcast changes on ImageWallpaper since it's handled
1063 // internally by this class.
1064 if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
1065 return;
1066 }
1067
1068 mWallpaper.primaryColors = primaryColors;
1069
1070 // Live wallpapers always are system wallpapers.
1071 which = FLAG_SYSTEM;
1072 // It's also the lock screen wallpaper when we don't have a bitmap in there
Lucas Dupin50ba9912017-07-14 11:55:05 -07001073 WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001074 if (lockedWallpaper == null) {
1075 which |= FLAG_LOCK;
1076 }
1077 }
1078 if (which != 0) {
1079 notifyWallpaperColorsChanged(mWallpaper, which);
1080 }
1081 }
1082
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001083 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001084 public void attachEngine(IWallpaperEngine engine) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001085 synchronized (mLock) {
1086 mEngine = engine;
Michael Wright5203a8b2013-10-03 14:16:42 -07001087 if (mDimensionsChanged) {
1088 try {
1089 mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
1090 } catch (RemoteException e) {
1091 Slog.w(TAG, "Failed to set wallpaper dimensions", e);
1092 }
1093 mDimensionsChanged = false;
1094 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001095 if (mPaddingChanged) {
1096 try {
1097 mEngine.setDisplayPadding(mWallpaper.padding);
1098 } catch (RemoteException e) {
1099 Slog.w(TAG, "Failed to set wallpaper padding", e);
1100 }
1101 mPaddingChanged = false;
1102 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001103 if (mInfo != null && mInfo.getSupportsAmbientMode()) {
1104 try {
Lucas Dupin660d5732017-12-19 10:05:19 -08001105 mEngine.setInAmbientMode(mInAmbientMode, false /* animated */);
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001106 } catch (RemoteException e) {
1107 Slog.w(TAG, "Failed to set ambient mode state", e);
1108 }
1109 }
Lucas Dupin50ba9912017-07-14 11:55:05 -07001110 try {
1111 // This will trigger onComputeColors in the wallpaper engine.
1112 // It's fine to be locked in here since the binder is oneway.
1113 mEngine.requestWallpaperColors();
1114 } catch (RemoteException e) {
1115 Slog.w(TAG, "Failed to request wallpaper colors", e);
1116 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001117 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001118 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001119
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001120 @Override
1121 public void engineShown(IWallpaperEngine engine) {
1122 synchronized (mLock) {
1123 if (mReply != null) {
1124 long ident = Binder.clearCallingIdentity();
1125 try {
1126 mReply.sendResult(null);
1127 } catch (RemoteException e) {
1128 Binder.restoreCallingIdentity(ident);
1129 }
1130 mReply = null;
1131 }
1132 }
1133 }
1134
1135 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001136 public ParcelFileDescriptor setWallpaper(String name) {
1137 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001138 if (mWallpaper.connection == this) {
Christopher Tatead3c2592016-01-20 18:13:17 -08001139 return updateWallpaperBitmapLocked(name, mWallpaper, null);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001140 }
1141 return null;
1142 }
1143 }
1144 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001145
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001146 class MyPackageMonitor extends PackageMonitor {
1147 @Override
1148 public void onPackageUpdateFinished(String packageName, int uid) {
1149 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001150 if (mCurrentUserId != getChangingUserId()) {
1151 return;
1152 }
1153 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1154 if (wallpaper != null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001155 final ComponentName wpService = wallpaper.wallpaperComponent;
1156 if (wpService != null && wpService.getPackageName().equals(packageName)) {
1157 if (DEBUG_LIVE) {
1158 Slog.i(TAG, "Wallpaper " + wpService + " update has finished");
1159 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001160 wallpaper.wallpaperUpdating = false;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001161 clearWallpaperComponentLocked(wallpaper);
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001162 if (!bindWallpaperComponentLocked(wpService, false, false,
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001163 wallpaper, null)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001164 Slog.w(TAG, "Wallpaper " + wpService
1165 + " no longer available; reverting to default");
Christopher Tateedf7d042016-03-29 18:24:25 -07001166 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001167 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001168 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001169 }
1170 }
1171 }
1172
1173 @Override
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001174 public void onPackageModified(String packageName) {
1175 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001176 if (mCurrentUserId != getChangingUserId()) {
1177 return;
1178 }
1179 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1180 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001181 if (wallpaper.wallpaperComponent == null
1182 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001183 return;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001184 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001185 doPackagesChangedLocked(true, wallpaper);
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001186 }
1187 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001188 }
1189
1190 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001191 public void onPackageUpdateStarted(String packageName, int uid) {
1192 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001193 if (mCurrentUserId != getChangingUserId()) {
1194 return;
1195 }
1196 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1197 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001198 if (wallpaper.wallpaperComponent != null
1199 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001200 if (DEBUG_LIVE) {
1201 Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent
1202 + " is updating");
1203 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001204 wallpaper.wallpaperUpdating = true;
Adrian Roosc3f915e2016-09-06 11:40:53 -07001205 if (wallpaper.connection != null) {
1206 FgThread.getHandler().removeCallbacks(
1207 wallpaper.connection.mResetRunnable);
1208 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001209 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001210 }
1211 }
1212 }
1213
1214 @Override
1215 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001216 synchronized (mLock) {
1217 boolean changed = false;
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001218 if (mCurrentUserId != getChangingUserId()) {
1219 return false;
1220 }
1221 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1222 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001223 boolean res = doPackagesChangedLocked(doit, wallpaper);
1224 changed |= res;
1225 }
1226 return changed;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001227 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001228 }
1229
1230 @Override
1231 public void onSomePackagesChanged() {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001232 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001233 if (mCurrentUserId != getChangingUserId()) {
1234 return;
1235 }
1236 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1237 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001238 doPackagesChangedLocked(true, wallpaper);
1239 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001240 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001241 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001242
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001243 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001244 boolean changed = false;
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001245 if (wallpaper.wallpaperComponent != null) {
1246 int change = isPackageDisappearing(wallpaper.wallpaperComponent
1247 .getPackageName());
1248 if (change == PACKAGE_PERMANENT_CHANGE
1249 || change == PACKAGE_TEMPORARY_CHANGE) {
1250 changed = true;
1251 if (doit) {
1252 Slog.w(TAG, "Wallpaper uninstalled, removing: "
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001253 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001254 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001255 }
1256 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001257 }
1258 if (wallpaper.nextWallpaperComponent != null) {
1259 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
1260 .getPackageName());
1261 if (change == PACKAGE_PERMANENT_CHANGE
1262 || change == PACKAGE_TEMPORARY_CHANGE) {
1263 wallpaper.nextWallpaperComponent = null;
1264 }
1265 }
1266 if (wallpaper.wallpaperComponent != null
1267 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
1268 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001269 mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
1270 PackageManager.MATCH_DIRECT_BOOT_AWARE
1271 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001272 } catch (NameNotFoundException e) {
1273 Slog.w(TAG, "Wallpaper component gone, removing: "
1274 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001275 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001276 }
1277 }
1278 if (wallpaper.nextWallpaperComponent != null
1279 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
1280 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001281 mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
1282 PackageManager.MATCH_DIRECT_BOOT_AWARE
1283 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001284 } catch (NameNotFoundException e) {
1285 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001286 }
1287 }
1288 return changed;
1289 }
1290 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001291
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001292 public WallpaperManagerService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001293 if (DEBUG) Slog.v(TAG, "WallpaperService startup");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 mContext = context;
Christopher Tate762dfd12016-10-10 17:44:48 -07001295 mShuttingDown = false;
Justin Koh29c30162014-09-05 17:10:10 -07001296 mImageWallpaper = ComponentName.unflattenFromString(
1297 context.getResources().getString(R.string.image_wallpaper_component));
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001298 mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001299 mIWindowManager = IWindowManager.Stub.asInterface(
1300 ServiceManager.getService(Context.WINDOW_SERVICE));
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001301 mIPackageManager = AppGlobals.getPackageManager();
Benjamin Franzf3ece362015-02-11 10:51:10 +00001302 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001303 mMonitor = new MyPackageMonitor();
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001304 mColorsChangedListeners = new SparseArray<>();
1305 }
1306
1307 void initialize() {
1308 mMonitor.register(mContext, null, UserHandle.ALL, true);
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001309 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
Christopher Tatef717b932017-09-11 15:52:54 -07001310
1311 // Initialize state from the persistent store, then guarantee that the
1312 // WallpaperData for the system imagery is instantiated & active, creating
1313 // it from defaults if necessary.
Christopher Tated7faf532016-02-25 12:43:38 -08001314 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatef717b932017-09-11 15:52:54 -07001315 getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001317
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001318 private static File getWallpaperDir(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07001319 return Environment.getUserSystemDirectory(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001320 }
1321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 @Override
1323 protected void finalize() throws Throwable {
1324 super.finalize();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001325 for (int i = 0; i < mWallpaperMap.size(); i++) {
1326 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
1327 wallpaper.wallpaperObserver.stopWatching();
1328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 }
Amith Yamasani13593602012-03-22 16:16:17 -07001330
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001331 void systemReady() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001332 if (DEBUG) Slog.v(TAG, "systemReady");
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001333 initialize();
1334
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001335 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001336 // If we think we're going to be using the system image wallpaper imagery, make
1337 // sure we have something to render
1338 if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
1339 // No crop file? Make sure we've finished the processing sequence if necessary
1340 if (!wallpaper.cropExists()) {
1341 if (DEBUG) {
1342 Slog.i(TAG, "No crop; regenerating from source");
1343 }
1344 generateCrop(wallpaper);
1345 }
1346 // Still nothing? Fall back to default.
1347 if (!wallpaper.cropExists()) {
1348 if (DEBUG) {
1349 Slog.i(TAG, "Unable to regenerate crop; resetting");
1350 }
Christopher Tateedf7d042016-03-29 18:24:25 -07001351 clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001352 }
1353 } else {
1354 if (DEBUG) {
1355 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
1356 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001357 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001358
Amith Yamasani13593602012-03-22 16:16:17 -07001359 IntentFilter userFilter = new IntentFilter();
Amith Yamasani13593602012-03-22 16:16:17 -07001360 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1361 mContext.registerReceiver(new BroadcastReceiver() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001362 @Override
Amith Yamasani13593602012-03-22 16:16:17 -07001363 public void onReceive(Context context, Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001364 final String action = intent.getAction();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001365 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani756901d2012-10-12 12:30:07 -07001366 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1367 UserHandle.USER_NULL));
Amith Yamasani13593602012-03-22 16:16:17 -07001368 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001369 }
Amith Yamasani13593602012-03-22 16:16:17 -07001370 }, userFilter);
Amith Yamasani756901d2012-10-12 12:30:07 -07001371
Christopher Tate762dfd12016-10-10 17:44:48 -07001372 final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
1373 mContext.registerReceiver(new BroadcastReceiver() {
1374 @Override
1375 public void onReceive(Context context, Intent intent) {
1376 if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
1377 if (DEBUG) {
1378 Slog.i(TAG, "Shutting down");
1379 }
1380 synchronized (mLock) {
1381 mShuttingDown = true;
1382 }
1383 }
1384 }
1385 }, shutdownFilter);
1386
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001387 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001388 ActivityManager.getService().registerUserSwitchObserver(
Sudheer Shanka2c4522c2016-08-27 20:53:28 -07001389 new UserSwitchObserver() {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001390 @Override
1391 public void onUserSwitching(int newUserId, IRemoteCallback reply) {
1392 switchUser(newUserId, reply);
1393 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001394 }, TAG);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001395 } catch (RemoteException e) {
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001396 e.rethrowAsRuntimeException();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001397 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001398 }
1399
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08001400 /** Called by SystemBackupAgent */
1401 public String getName() {
1402 // Verify caller is the system
1403 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
1404 throw new RuntimeException("getName() can only be called from the system process");
1405 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001406 synchronized (mLock) {
1407 return mWallpaperMap.get(0).name;
1408 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001409 }
1410
Christopher Tatebe132e62016-02-10 12:59:49 -08001411 void stopObserver(WallpaperData wallpaper) {
1412 if (wallpaper != null) {
1413 if (wallpaper.wallpaperObserver != null) {
1414 wallpaper.wallpaperObserver.stopWatching();
1415 wallpaper.wallpaperObserver = null;
Amith Yamasani13593602012-03-22 16:16:17 -07001416 }
Tony Huangf0800fa2018-05-02 10:53:52 +08001417 if (wallpaper.themeSettingsObserver != null) {
1418 wallpaper.themeSettingsObserver.stopObserving(mContext);
1419 wallpaper.themeSettingsObserver = null;
1420 }
Amith Yamasani756901d2012-10-12 12:30:07 -07001421 }
1422 }
1423
Christopher Tatebe132e62016-02-10 12:59:49 -08001424 void stopObserversLocked(int userId) {
1425 stopObserver(mWallpaperMap.get(userId));
1426 stopObserver(mLockWallpaperMap.get(userId));
1427 mWallpaperMap.remove(userId);
1428 mLockWallpaperMap.remove(userId);
1429 }
1430
Daichi Hirono4bbf8522017-12-06 10:34:18 +09001431 @Override
1432 public void onBootPhase(int phase) {
1433 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1434 systemReady();
1435 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1436 switchUser(UserHandle.USER_SYSTEM, null);
1437 }
1438 }
1439
1440 @Override
1441 public void onUnlockUser(final int userId) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001442 synchronized (mLock) {
Christopher Tate38a5dc32016-07-20 15:10:18 -07001443 if (mCurrentUserId == userId) {
1444 if (mWaitingForUnlock) {
wilsonshiha47fcc92018-04-26 14:27:38 +08001445 // the desired wallpaper is not direct-boot aware, load it now
1446 final WallpaperData systemWallpaper =
1447 getWallpaperSafeLocked(userId, FLAG_SYSTEM);
1448 switchWallpaper(systemWallpaper, null);
Christopher Tate38a5dc32016-07-20 15:10:18 -07001449 }
Christopher Tate190e8532016-07-11 11:35:34 -07001450
1451 // Make sure that the SELinux labeling of all the relevant files is correct.
1452 // This corrects for mislabeling bugs that might have arisen from move-to
1453 // operations involving the wallpaper files. This isn't timing-critical,
1454 // so we do it in the background to avoid holding up the user unlock operation.
Christopher Tate38a5dc32016-07-20 15:10:18 -07001455 if (mUserRestorecon.get(userId) != Boolean.TRUE) {
1456 mUserRestorecon.put(userId, Boolean.TRUE);
1457 Runnable relabeler = new Runnable() {
1458 @Override
1459 public void run() {
1460 final File wallpaperDir = getWallpaperDir(userId);
1461 for (String filename : sPerUserFiles) {
1462 File f = new File(wallpaperDir, filename);
1463 if (f.exists()) {
1464 SELinux.restorecon(f);
1465 }
Christopher Tate190e8532016-07-11 11:35:34 -07001466 }
1467 }
Christopher Tate38a5dc32016-07-20 15:10:18 -07001468 };
1469 BackgroundThread.getHandler().post(relabeler);
1470 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001471 }
1472 }
1473 }
1474
Amith Yamasani756901d2012-10-12 12:30:07 -07001475 void onRemoveUser(int userId) {
1476 if (userId < 1) return;
Christopher Tatebe132e62016-02-10 12:59:49 -08001477
1478 final File wallpaperDir = getWallpaperDir(userId);
Amith Yamasani756901d2012-10-12 12:30:07 -07001479 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001480 stopObserversLocked(userId);
1481 for (String filename : sPerUserFiles) {
1482 new File(wallpaperDir, filename).delete();
1483 }
Sudheer Shanka69f0cb52016-10-06 17:33:20 -07001484 mUserRestorecon.remove(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001485 }
1486 }
1487
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001488 void switchUser(int userId, IRemoteCallback reply) {
Lucas Dupin9272d452017-09-14 14:15:42 -07001489 final WallpaperData systemWallpaper;
1490 final WallpaperData lockWallpaper;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001491 synchronized (mLock) {
Jaekyun Seokad7d90f2018-04-04 01:57:18 +09001492 if (mCurrentUserId == userId) {
1493 return;
1494 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001495 mCurrentUserId = userId;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001496 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Lucas Dupin9272d452017-09-14 14:15:42 -07001497 final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
1498 lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001499 // Not started watching yet, in case wallpaper data was loaded for other reasons.
1500 if (systemWallpaper.wallpaperObserver == null) {
1501 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
1502 systemWallpaper.wallpaperObserver.startWatching();
1503 }
Tony Huangf0800fa2018-05-02 10:53:52 +08001504 if (systemWallpaper.themeSettingsObserver == null) {
1505 systemWallpaper.themeSettingsObserver = new ThemeSettingsObserver(null);
1506 systemWallpaper.themeSettingsObserver.startObserving(mContext);
1507 }
1508 mThemeMode = Settings.Secure.getInt(
1509 mContext.getContentResolver(), Settings.Secure.THEME_MODE,
1510 Settings.Secure.THEME_MODE_WALLPAPER);
Lucas Dupin50ba9912017-07-14 11:55:05 -07001511 switchWallpaper(systemWallpaper, reply);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001512 }
Lucas Dupin9272d452017-09-14 14:15:42 -07001513
1514 // Offload color extraction to another thread since switchUser will be called
1515 // from the main thread.
1516 FgThread.getHandler().post(() -> {
1517 notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
1518 notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
1519 });
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001520 }
1521
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001522 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001523 synchronized (mLock) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001524 mWaitingForUnlock = false;
1525 final ComponentName cname = wallpaper.wallpaperComponent != null ?
1526 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
1527 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
1528 // We failed to bind the desired wallpaper, but that might
1529 // happen if the wallpaper isn't direct-boot aware
1530 ServiceInfo si = null;
1531 try {
1532 si = mIPackageManager.getServiceInfo(cname,
1533 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
1534 } catch (RemoteException ignored) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001535 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001536
1537 if (si == null) {
1538 Slog.w(TAG, "Failure starting previous wallpaper; clearing");
1539 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
1540 } else {
1541 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
1542 // We might end up persisting the current wallpaper data
1543 // while locked, so pretend like the component was actually
1544 // bound into place
1545 wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
1546 final WallpaperData fallback = new WallpaperData(wallpaper.userId,
1547 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
Adrian Roosc28e3a92016-04-14 10:47:52 -07001548 ensureSaneWallpaperData(fallback);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001549 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
1550 mWaitingForUnlock = true;
1551 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001552 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001553 }
1554 }
1555
Christopher Tatebe132e62016-02-10 12:59:49 -08001556 @Override
1557 public void clearWallpaper(String callingPackage, int which, int userId) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001558 if (DEBUG) Slog.v(TAG, "clearWallpaper");
Benjamin Franzf3ece362015-02-11 10:51:10 +00001559 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tate98d609c2016-05-18 17:31:58 -07001560 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001561 return;
1562 }
Christopher Tatee409f0e2016-03-21 14:53:15 -07001563 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1564 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001565
Lucas Dupin41f69422017-05-03 15:26:22 -07001566 WallpaperData data = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001567 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001568 clearWallpaperLocked(false, which, userId, null);
Lucas Dupin41f69422017-05-03 15:26:22 -07001569
1570 if (which == FLAG_LOCK) {
1571 data = mLockWallpaperMap.get(userId);
1572 }
1573 if (which == FLAG_SYSTEM || data == null) {
1574 data = mWallpaperMap.get(userId);
1575 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001576 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001577
1578 // When clearing a wallpaper, broadcast new valid colors
Lucas Dupin41f69422017-05-03 15:26:22 -07001579 if (data != null) {
1580 notifyWallpaperColorsChanged(data, which);
1581 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001582 }
1583
Christopher Tatebe132e62016-02-10 12:59:49 -08001584 void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
Christopher Tateedf7d042016-03-29 18:24:25 -07001585 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tate105540d2018-03-21 13:03:09 -07001586 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
Christopher Tatebe132e62016-02-10 12:59:49 -08001587 }
1588
1589 WallpaperData wallpaper = null;
Christopher Tateedf7d042016-03-29 18:24:25 -07001590 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001591 wallpaper = mLockWallpaperMap.get(userId);
1592 if (wallpaper == null) {
1593 // It's already gone; we're done.
Christopher Tate79a24572016-03-02 14:42:44 -08001594 if (DEBUG) {
1595 Slog.i(TAG, "Lock wallpaper already cleared");
1596 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001597 return;
1598 }
1599 } else {
1600 wallpaper = mWallpaperMap.get(userId);
1601 if (wallpaper == null) {
1602 // Might need to bring it in the first time to establish our rewrite
Christopher Tated7faf532016-02-25 12:43:38 -08001603 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08001604 wallpaper = mWallpaperMap.get(userId);
1605 }
1606 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001607 if (wallpaper == null) {
1608 return;
1609 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001610
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001611 final long ident = Binder.clearCallingIdentity();
1612 try {
Christopher Tatebe132e62016-02-10 12:59:49 -08001613 if (wallpaper.wallpaperFile.exists()) {
1614 wallpaper.wallpaperFile.delete();
1615 wallpaper.cropFile.delete();
Christopher Tateedf7d042016-03-29 18:24:25 -07001616 if (which == FLAG_LOCK) {
Christopher Tate79a24572016-03-02 14:42:44 -08001617 mLockWallpaperMap.remove(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001618 final IWallpaperManagerCallback cb = mKeyguardListener;
1619 if (cb != null) {
Christopher Tate79a24572016-03-02 14:42:44 -08001620 if (DEBUG) {
1621 Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
1622 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001623 try {
1624 cb.onWallpaperChanged();
1625 } catch (RemoteException e) {
1626 // Oh well it went away; no big deal
1627 }
1628 }
Christopher Tate79a24572016-03-02 14:42:44 -08001629 saveSettingsLocked(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001630 return;
1631 }
1632 }
1633
Christopher Tateecd827a2014-09-05 17:42:34 -07001634 RuntimeException e = null;
1635 try {
Lucas Dupin75ec3792017-06-29 14:07:18 -07001636 wallpaper.primaryColors = null;
Christopher Tateecd827a2014-09-05 17:42:34 -07001637 wallpaper.imageWallpaperPending = false;
1638 if (userId != mCurrentUserId) return;
1639 if (bindWallpaperComponentLocked(defaultFailed
1640 ? mImageWallpaper
1641 : null, true, false, wallpaper, reply)) {
1642 return;
1643 }
1644 } catch (IllegalArgumentException e1) {
1645 e = e1;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001646 }
Christopher Tateecd827a2014-09-05 17:42:34 -07001647
1648 // This can happen if the default wallpaper component doesn't
1649 // exist. This should be a system configuration problem, but
1650 // let's not let it crash the system and just live with no
1651 // wallpaper.
1652 Slog.e(TAG, "Default wallpaper component not found!", e);
1653 clearWallpaperComponentLocked(wallpaper);
1654 if (reply != null) {
1655 try {
1656 reply.sendResult(null);
1657 } catch (RemoteException e1) {
1658 }
1659 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001660 } finally {
1661 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001663 }
1664
1665 public boolean hasNamedWallpaper(String name) {
1666 synchronized (mLock) {
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001667 List<UserInfo> users;
1668 long ident = Binder.clearCallingIdentity();
1669 try {
1670 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
1671 } finally {
1672 Binder.restoreCallingIdentity(ident);
1673 }
1674 for (UserInfo user: users) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001675 // ignore managed profiles
1676 if (user.isManagedProfile()) {
1677 continue;
1678 }
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001679 WallpaperData wd = mWallpaperMap.get(user.id);
1680 if (wd == null) {
1681 // User hasn't started yet, so load her settings to peek at the wallpaper
Christopher Tated7faf532016-02-25 12:43:38 -08001682 loadSettingsLocked(user.id, false);
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001683 wd = mWallpaperMap.get(user.id);
1684 }
1685 if (wd != null && name.equals(wd.name)) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001686 return true;
1687 }
1688 }
1689 }
1690 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 }
1692
John Spurlock41f64642013-11-04 13:48:38 -05001693 private Point getDefaultDisplaySize() {
1694 Point p = new Point();
John Spurlockd6e836c2013-11-18 14:14:49 -05001695 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1696 Display d = wm.getDefaultDisplay();
1697 d.getRealSize(p);
John Spurlock41f64642013-11-04 13:48:38 -05001698 return p;
1699 }
1700
Benjamin Franzf3ece362015-02-11 10:51:10 +00001701 public void setDimensionHints(int width, int height, String callingPackage)
1702 throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001704 if (!isWallpaperSupported(callingPackage)) {
1705 return;
1706 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001707 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001708 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001709 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001710 if (width <= 0 || height <= 0) {
1711 throw new IllegalArgumentException("width and height must be > 0");
1712 }
John Spurlock41f64642013-11-04 13:48:38 -05001713 // Make sure it is at least as large as the display.
1714 Point displaySize = getDefaultDisplaySize();
1715 width = Math.max(width, displaySize.x);
1716 height = Math.max(height, displaySize.y);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001717
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001718 if (width != wallpaper.width || height != wallpaper.height) {
1719 wallpaper.width = width;
1720 wallpaper.height = height;
Christopher Tatedb27b842016-02-25 14:39:17 -08001721 saveSettingsLocked(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001722 if (mCurrentUserId != userId) return; // Don't change the properties now
1723 if (wallpaper.connection != null) {
1724 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001725 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001726 wallpaper.connection.mEngine.setDesiredSize(
Dianne Hackborn284ac932009-08-28 10:34:25 -07001727 width, height);
1728 } catch (RemoteException e) {
1729 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001730 notifyCallbacksLocked(wallpaper);
Michael Wright5203a8b2013-10-03 14:16:42 -07001731 } else if (wallpaper.connection.mService != null) {
1732 // We've attached to the service but the engine hasn't attached back to us
1733 // yet. This means it will be created with the previous dimensions, so we
1734 // need to update it to the new dimensions once it attaches.
1735 wallpaper.connection.mDimensionsChanged = true;
Dianne Hackborn284ac932009-08-28 10:34:25 -07001736 }
1737 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001738 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
1740 }
1741
1742 public int getWidthHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001743 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001744 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001745 if (wallpaper != null) {
1746 return wallpaper.width;
1747 } else {
1748 return 0;
1749 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 }
1752
1753 public int getHeightHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001754 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001755 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001756 if (wallpaper != null) {
1757 return wallpaper.height;
1758 } else {
1759 return 0;
1760 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001761 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 }
1763
Benjamin Franzf3ece362015-02-11 10:51:10 +00001764 public void setDisplayPadding(Rect padding, String callingPackage) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001765 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001766 if (!isWallpaperSupported(callingPackage)) {
1767 return;
1768 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001769 synchronized (mLock) {
1770 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001771 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001772 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
1773 throw new IllegalArgumentException("padding must be positive: " + padding);
1774 }
1775
1776 if (!padding.equals(wallpaper.padding)) {
1777 wallpaper.padding.set(padding);
Christopher Tatedb27b842016-02-25 14:39:17 -08001778 saveSettingsLocked(userId);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001779 if (mCurrentUserId != userId) return; // Don't change the properties now
1780 if (wallpaper.connection != null) {
1781 if (wallpaper.connection.mEngine != null) {
1782 try {
1783 wallpaper.connection.mEngine.setDisplayPadding(padding);
1784 } catch (RemoteException e) {
1785 }
1786 notifyCallbacksLocked(wallpaper);
1787 } else if (wallpaper.connection.mService != null) {
1788 // We've attached to the service but the engine hasn't attached back to us
1789 // yet. This means it will be created with the previous dimensions, so we
1790 // need to update it to the new dimensions once it attaches.
1791 wallpaper.connection.mPaddingChanged = true;
1792 }
1793 }
1794 }
1795 }
1796 }
1797
Christopher Tate93252de2017-06-15 14:48:41 -07001798 private void enforceCallingOrSelfPermissionAndAppOp(String permission, final String callingPkg,
1799 final int callingUid, String message) {
1800 mContext.enforceCallingOrSelfPermission(permission, message);
1801
1802 final String opName = AppOpsManager.permissionToOp(permission);
1803 if (opName != null) {
1804 final int appOpMode = mAppOpsManager.noteOp(opName, callingUid, callingPkg);
1805 if (appOpMode != AppOpsManager.MODE_ALLOWED) {
1806 throw new SecurityException(
1807 message + ": " + callingPkg + " is not allowed to " + permission);
1808 }
1809 }
1810 }
1811
Yorke Leedcd93cc2016-01-08 14:12:55 -08001812 @Override
Christopher Tate93252de2017-06-15 14:48:41 -07001813 public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
1814 final int which, Bundle outParams, int wallpaperUserId) {
Christopher Tate8a71c482017-08-14 16:45:03 -07001815 final int hasPrivilege = mContext.checkCallingOrSelfPermission(
1816 android.Manifest.permission.READ_WALLPAPER_INTERNAL);
1817 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
1818 enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
1819 callingPkg, Binder.getCallingUid(), "read wallpaper");
1820 }
Christopher Tate93252de2017-06-15 14:48:41 -07001821
Christopher Tatee409f0e2016-03-21 14:53:15 -07001822 wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1823 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001824
Christopher Tateedf7d042016-03-29 18:24:25 -07001825 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001826 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1827 }
1828
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001829 synchronized (mLock) {
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001830 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07001831 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001832 WallpaperData wallpaper = whichSet.get(wallpaperUserId);
1833 if (wallpaper == null) {
Christopher Tatef717b932017-09-11 15:52:54 -07001834 // There is no established wallpaper imagery of this type (expected
1835 // only for lock wallpapers; a system WallpaperData is established at
1836 // user switch)
1837 return null;
Benjamin Franzf3ece362015-02-11 10:51:10 +00001838 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001839 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001840 if (outParams != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001841 outParams.putInt("width", wallpaper.width);
1842 outParams.putInt("height", wallpaper.height);
Dianne Hackborn284ac932009-08-28 10:34:25 -07001843 }
Christopher Tateea6724a2016-02-18 18:39:19 -08001844 if (cb != null) {
1845 wallpaper.callbacks.register(cb);
1846 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001847 if (!wallpaper.cropFile.exists()) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001848 return null;
1849 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001850 return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001851 } catch (FileNotFoundException e) {
1852 /* Shouldn't happen as we check to see if the file exists */
Joe Onorato8a9b2202010-02-26 18:56:32 -08001853 Slog.w(TAG, "Error getting wallpaper", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001855 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 }
1858
Christopher Tatee409f0e2016-03-21 14:53:15 -07001859 @Override
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001860 public WallpaperInfo getWallpaperInfo(int userId) {
1861 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Christopher Tatef717b932017-09-11 15:52:54 -07001862 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null);
Dianne Hackborneb034652009-09-07 00:49:58 -07001863 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001864 WallpaperData wallpaper = mWallpaperMap.get(userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001865 if (wallpaper != null && wallpaper.connection != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001866 return wallpaper.connection.mInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -07001867 }
1868 return null;
1869 }
1870 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001871
Christopher Tatead3c2592016-01-20 18:13:17 -08001872 @Override
Christopher Tatee409f0e2016-03-21 14:53:15 -07001873 public int getWallpaperIdForUser(int which, int userId) {
1874 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1875 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
1876
Christopher Tateedf7d042016-03-29 18:24:25 -07001877 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001878 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
1879 }
1880
1881 final SparseArray<WallpaperData> map =
Christopher Tateedf7d042016-03-29 18:24:25 -07001882 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatee409f0e2016-03-21 14:53:15 -07001883 synchronized (mLock) {
1884 WallpaperData wallpaper = map.get(userId);
1885 if (wallpaper != null) {
1886 return wallpaper.wallpaperId;
1887 }
1888 }
1889 return -1;
1890 }
1891
1892 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001893 public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
1894 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1895 userId, true, true, "registerWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001896 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001897 RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
1898 mColorsChangedListeners.get(userId);
1899 if (userColorsChangedListeners == null) {
1900 userColorsChangedListeners = new RemoteCallbackList<>();
1901 mColorsChangedListeners.put(userId, userColorsChangedListeners);
1902 }
1903 userColorsChangedListeners.register(cb);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001904 }
1905 }
1906
1907 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001908 public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
1909 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1910 userId, true, true, "unregisterWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001911 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001912 final RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
1913 mColorsChangedListeners.get(userId);
1914 if (userColorsChangedListeners != null) {
1915 userColorsChangedListeners.unregister(cb);
1916 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001917 }
1918 }
1919
Lucas Dupin660d5732017-12-19 10:05:19 -08001920 public void setInAmbientMode(boolean inAmbienMode, boolean animated) {
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001921 final IWallpaperEngine engine;
1922 synchronized (mLock) {
1923 mInAmbientMode = inAmbienMode;
1924 final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
1925 if (data != null && data.connection != null && data.connection.mInfo != null
1926 && data.connection.mInfo.getSupportsAmbientMode()) {
1927 engine = data.connection.mEngine;
1928 } else {
1929 engine = null;
1930 }
1931 }
1932
1933 if (engine != null) {
1934 try {
Lucas Dupin660d5732017-12-19 10:05:19 -08001935 engine.setInAmbientMode(inAmbienMode, animated);
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001936 } catch (RemoteException e) {
1937 // Cannot talk to wallpaper engine.
1938 }
1939 }
1940 }
1941
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001942 @Override
Christopher Tatebe132e62016-02-10 12:59:49 -08001943 public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
1944 checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
1945 synchronized (mLock) {
1946 mKeyguardListener = cb;
1947 }
1948 return true;
1949 }
1950
1951 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001952 public WallpaperColors getWallpaperColors(int which, int userId) throws RemoteException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001953 if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
1954 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
1955 }
Lucas Dupin50ba9912017-07-14 11:55:05 -07001956 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1957 userId, false, true, "getWallpaperColors", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001958
1959 WallpaperData wallpaperData = null;
1960 boolean shouldExtract;
1961
1962 synchronized (mLock) {
1963 if (which == FLAG_LOCK) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001964 wallpaperData = mLockWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001965 }
1966
1967 // Try to get the system wallpaper anyway since it might
1968 // also be the lock screen wallpaper
1969 if (wallpaperData == null) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001970 wallpaperData = mWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001971 }
1972
1973 if (wallpaperData == null) {
1974 return null;
1975 }
1976 shouldExtract = wallpaperData.primaryColors == null;
1977 }
1978
1979 if (shouldExtract) {
1980 extractColors(wallpaperData);
1981 }
1982
1983 synchronized (mLock) {
Tony Huangf0800fa2018-05-02 10:53:52 +08001984 return getThemeColorsLocked(wallpaperData.primaryColors);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001985 }
1986 }
1987
1988 @Override
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001989 public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Christopher Tated7faf532016-02-25 12:43:38 -08001990 Rect cropHint, boolean allowBackup, Bundle extras, int which,
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001991 IWallpaperManagerCallback completion, int userId) {
1992 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
1993 false /* all */, true /* full */, "changing wallpaper", null /* pkg */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tatead3c2592016-01-20 18:13:17 -08001995
Christopher Tateedf7d042016-03-29 18:24:25 -07001996 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001997 final String msg = "Must specify a valid wallpaper category to set";
1998 Slog.e(TAG, msg);
1999 throw new IllegalArgumentException(msg);
Christopher Tatead3c2592016-01-20 18:13:17 -08002000 }
2001
Christopher Tate98d609c2016-05-18 17:31:58 -07002002 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00002003 return null;
2004 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002005
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002006 // "null" means the no-op crop, preserving the full input image
2007 if (cropHint == null) {
2008 cropHint = new Rect(0, 0, 0, 0);
2009 } else {
2010 if (cropHint.isEmpty()
2011 || cropHint.left < 0
2012 || cropHint.top < 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07002013 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002014 }
2015 }
2016
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002017 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002018 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
2019 WallpaperData wallpaper;
2020
Christopher Tate8347b632016-04-29 18:59:18 -07002021 /* If we're setting system but not lock, and lock is currently sharing the system
2022 * wallpaper, we need to migrate that image over to being lock-only before
2023 * the caller here writes new bitmap data.
2024 */
2025 if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
2026 if (DEBUG) {
2027 Slog.i(TAG, "Migrating system->lock to preserve");
2028 }
2029 migrateSystemToLockWallpaperLocked(userId);
2030 }
2031
Christopher Tatebe132e62016-02-10 12:59:49 -08002032 wallpaper = getWallpaperSafeLocked(userId, which);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07002033 final long ident = Binder.clearCallingIdentity();
2034 try {
Christopher Tatead3c2592016-01-20 18:13:17 -08002035 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07002036 if (pfd != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002037 wallpaper.imageWallpaperPending = true;
Christopher Tatebe132e62016-02-10 12:59:49 -08002038 wallpaper.whichPending = which;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002039 wallpaper.setComplete = completion;
2040 wallpaper.cropHint.set(cropHint);
Christopher Tatec613c632016-08-12 14:13:02 -07002041 wallpaper.allowBackup = allowBackup;
Dianne Hackborn0cd48872009-08-13 18:51:59 -07002042 }
2043 return pfd;
2044 } finally {
2045 Binder.restoreCallingIdentity(ident);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 }
2048 }
2049
Christopher Tate8347b632016-04-29 18:59:18 -07002050 private void migrateSystemToLockWallpaperLocked(int userId) {
2051 WallpaperData sysWP = mWallpaperMap.get(userId);
2052 if (sysWP == null) {
2053 if (DEBUG) {
2054 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
2055 }
2056 return;
2057 }
2058
2059 // We know a-priori that there is no lock-only wallpaper currently
2060 WallpaperData lockWP = new WallpaperData(userId,
2061 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2062 lockWP.wallpaperId = sysWP.wallpaperId;
2063 lockWP.cropHint.set(sysWP.cropHint);
2064 lockWP.width = sysWP.width;
2065 lockWP.height = sysWP.height;
Christopher Tateedd8dc82016-10-12 15:17:58 -07002066 lockWP.allowBackup = sysWP.allowBackup;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002067 lockWP.primaryColors = sysWP.primaryColors;
Christopher Tate8347b632016-04-29 18:59:18 -07002068
2069 // Migrate the bitmap files outright; no need to copy
2070 try {
2071 Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
2072 Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
2073 } catch (ErrnoException e) {
2074 Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
2075 lockWP.wallpaperFile.delete();
2076 lockWP.cropFile.delete();
2077 return;
2078 }
2079
2080 mLockWallpaperMap.put(userId, lockWP);
2081 }
2082
Christopher Tatead3c2592016-01-20 18:13:17 -08002083 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
2084 Bundle extras) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002085 if (name == null) name = "";
2086 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002087 File dir = getWallpaperDir(wallpaper.userId);
2088 if (!dir.exists()) {
2089 dir.mkdir();
Dianne Hackbornebac48c2011-11-29 18:01:50 -08002090 FileUtils.setPermissions(
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002091 dir.getPath(),
Dianne Hackbornebac48c2011-11-29 18:01:50 -08002092 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
2093 -1, -1);
2094 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002095 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
Christopher Tate90f86ba2014-09-11 12:37:19 -07002096 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
Christopher Tatebe132e62016-02-10 12:59:49 -08002097 if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
rpcraig554cb0c2012-07-05 06:41:43 -04002098 return null;
2099 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002100 wallpaper.name = name;
Christopher Tatead3c2592016-01-20 18:13:17 -08002101 wallpaper.wallpaperId = makeWallpaperIdLocked();
2102 if (extras != null) {
2103 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
2104 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002105 // Nullify field to require new computation
2106 wallpaper.primaryColors = null;
Christopher Tatead3c2592016-01-20 18:13:17 -08002107 if (DEBUG) {
2108 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
Christopher Tatebe132e62016-02-10 12:59:49 -08002109 + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
Christopher Tatead3c2592016-01-20 18:13:17 -08002110 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002111 return fd;
2112 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002113 Slog.w(TAG, "Error setting wallpaper", e);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002114 }
2115 return null;
2116 }
2117
Christopher Tated57d17c2016-03-25 13:41:46 -07002118 @Override
Adrian Roos40ea0832016-07-14 14:19:55 -07002119 public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
2120 int userId) {
2121
Christopher Tate98d609c2016-05-18 17:31:58 -07002122 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
Adrian Roos40ea0832016-07-14 14:19:55 -07002123 setWallpaperComponent(name, userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00002124 }
2125 }
2126
2127 // ToDo: Remove this version of the function
Christopher Tated57d17c2016-03-25 13:41:46 -07002128 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002129 public void setWallpaperComponent(ComponentName name) {
Adrian Roos40ea0832016-07-14 14:19:55 -07002130 setWallpaperComponent(name, UserHandle.getCallingUserId());
2131 }
2132
2133 private void setWallpaperComponent(ComponentName name, int userId) {
2134 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
2135 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002136 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
Adrian Roos40ea0832016-07-14 14:19:55 -07002137
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002138 int which = FLAG_SYSTEM;
2139 boolean shouldNotifyColors = false;
2140 WallpaperData wallpaper;
2141
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002142 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002143 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002144 wallpaper = mWallpaperMap.get(userId);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002145 if (wallpaper == null) {
2146 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
2147 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002148 final long ident = Binder.clearCallingIdentity();
Christopher Tate7cd00102016-12-19 14:38:44 -08002149
2150 // Live wallpapers can't be specified for keyguard. If we're using a static
2151 // system+lock image currently, migrate the system wallpaper to be a lock-only
2152 // image as part of making a different live component active as the system
2153 // wallpaper.
2154 if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
2155 if (mLockWallpaperMap.get(userId) == null) {
2156 // We're using the static imagery and there is no lock-specific image in place,
2157 // therefore it's a shared system+lock image that we need to migrate.
2158 migrateSystemToLockWallpaperLocked(userId);
2159 }
2160 }
2161
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002162 // New live wallpaper is also a lock wallpaper if nothing is set
2163 if (mLockWallpaperMap.get(userId) == null) {
2164 which |= FLAG_LOCK;
2165 }
2166
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002167 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002168 wallpaper.imageWallpaperPending = false;
Lucas Dupin50ba9912017-07-14 11:55:05 -07002169 boolean same = changingToSame(name, wallpaper);
Christopher Tated57d17c2016-03-25 13:41:46 -07002170 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07002171 if (!same) {
2172 wallpaper.primaryColors = null;
2173 }
Christopher Tated57d17c2016-03-25 13:41:46 -07002174 wallpaper.wallpaperId = makeWallpaperIdLocked();
Sunny Goyal0572e182016-03-31 11:05:51 -07002175 notifyCallbacksLocked(wallpaper);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002176 shouldNotifyColors = true;
Christopher Tated57d17c2016-03-25 13:41:46 -07002177 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002178 } finally {
2179 Binder.restoreCallingIdentity(ident);
2180 }
2181 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002182
2183 if (shouldNotifyColors) {
2184 notifyWallpaperColorsChanged(wallpaper, which);
2185 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002186 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002187
Lucas Dupin50ba9912017-07-14 11:55:05 -07002188 private boolean changingToSame(ComponentName componentName, WallpaperData wallpaper) {
2189 if (wallpaper.connection != null) {
2190 if (wallpaper.wallpaperComponent == null) {
2191 if (componentName == null) {
2192 if (DEBUG) Slog.v(TAG, "changingToSame: still using default");
2193 // Still using default wallpaper.
2194 return true;
2195 }
2196 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
2197 // Changing to same wallpaper.
2198 if (DEBUG) Slog.v(TAG, "same wallpaper");
2199 return true;
2200 }
2201 }
2202 return false;
2203 }
2204
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002205 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002206 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002207 if (DEBUG_LIVE) {
2208 Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
2209 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002210 // Has the component changed?
Lucas Dupin50ba9912017-07-14 11:55:05 -07002211 if (!force && changingToSame(componentName, wallpaper)) {
2212 return true;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002213 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002214
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002215 try {
Mike Clerona428b2c2009-11-15 22:53:08 -08002216 if (componentName == null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002217 componentName = mDefaultWallpaperComponent;
Mike Clerona428b2c2009-11-15 22:53:08 -08002218 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -08002219 // Fall back to static image wallpaper
Justin Koh29c30162014-09-05 17:10:10 -07002220 componentName = mImageWallpaper;
Mike Cleron322b6ee2009-11-12 07:45:47 -08002221 //clearWallpaperComponentLocked();
2222 //return;
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002223 if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper");
Mike Cleron322b6ee2009-11-12 07:45:47 -08002224 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002225 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002226 int serviceUserId = wallpaper.userId;
2227 ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
2228 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
Christopher Tate90952202013-09-08 13:01:28 -07002229 if (si == null) {
2230 // The wallpaper component we're trying to use doesn't exist
2231 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
2232 return false;
2233 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002234 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002235 String msg = "Selected service does not require "
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002236 + android.Manifest.permission.BIND_WALLPAPER
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002237 + ": " + componentName;
2238 if (fromUser) {
2239 throw new SecurityException(msg);
2240 }
2241 Slog.w(TAG, msg);
2242 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002243 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002244
Dianne Hackborneb034652009-09-07 00:49:58 -07002245 WallpaperInfo wi = null;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002246
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002247 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
Justin Koh29c30162014-09-05 17:10:10 -07002248 if (componentName != null && !componentName.equals(mImageWallpaper)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002249 // Make sure the selected service is actually a wallpaper service.
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002250 List<ResolveInfo> ris =
2251 mIPackageManager.queryIntentServices(intent,
2252 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
Jeff Sharkeyd5896632016-03-04 16:16:00 -07002253 PackageManager.GET_META_DATA, serviceUserId).getList();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002254 for (int i=0; i<ris.size(); i++) {
2255 ServiceInfo rsi = ris.get(i).serviceInfo;
2256 if (rsi.name.equals(si.name) &&
2257 rsi.packageName.equals(si.packageName)) {
Dianne Hackborneb034652009-09-07 00:49:58 -07002258 try {
2259 wi = new WallpaperInfo(mContext, ris.get(i));
2260 } catch (XmlPullParserException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002261 if (fromUser) {
2262 throw new IllegalArgumentException(e);
2263 }
2264 Slog.w(TAG, e);
2265 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002266 } catch (IOException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002267 if (fromUser) {
2268 throw new IllegalArgumentException(e);
2269 }
2270 Slog.w(TAG, e);
2271 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002272 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002273 break;
2274 }
2275 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002276 if (wi == null) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002277 String msg = "Selected service is not a wallpaper: "
2278 + componentName;
2279 if (fromUser) {
2280 throw new SecurityException(msg);
2281 }
2282 Slog.w(TAG, msg);
2283 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002284 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002285 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002286
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002287 // Bind the service!
Joe Onorato8a9b2202010-02-26 18:56:32 -08002288 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002289 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002290 intent.setComponent(componentName);
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002291 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2292 com.android.internal.R.string.wallpaper_binding_label);
Dianne Hackborn41203752012-08-31 14:05:51 -07002293 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
Dianne Hackborneb034652009-09-07 00:49:58 -07002294 mContext, 0,
2295 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
2296 mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
Dianne Hackborn41203752012-08-31 14:05:51 -07002297 0, null, new UserHandle(serviceUserId)));
Dianne Hackbornc8230512013-07-13 21:32:12 -07002298 if (!mContext.bindServiceAsUser(intent, newConn,
Dianne Hackbornd69e4c12015-04-24 09:54:54 -07002299 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
2300 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
Amith Yamasani27b89e62013-01-16 12:30:11 -08002301 new UserHandle(serviceUserId))) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002302 String msg = "Unable to bind service: "
2303 + componentName;
2304 if (fromUser) {
2305 throw new IllegalArgumentException(msg);
2306 }
2307 Slog.w(TAG, msg);
2308 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002309 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002310 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
2311 detachWallpaperLocked(mLastWallpaper);
2312 }
2313 wallpaper.wallpaperComponent = componentName;
2314 wallpaper.connection = newConn;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002315 newConn.mReply = reply;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002316 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002317 if (wallpaper.userId == mCurrentUserId) {
2318 if (DEBUG)
2319 Slog.v(TAG, "Adding window token: " + newConn.mToken);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002320 mIWindowManager.addWindowToken(newConn.mToken, TYPE_WALLPAPER, DEFAULT_DISPLAY);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002321 mLastWallpaper = wallpaper;
2322 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002323 } catch (RemoteException e) {
2324 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002325 } catch (RemoteException e) {
2326 String msg = "Remote exception for " + componentName + "\n" + e;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002327 if (fromUser) {
2328 throw new IllegalArgumentException(msg);
2329 }
2330 Slog.w(TAG, msg);
2331 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002332 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002333 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002334 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002335
2336 void detachWallpaperLocked(WallpaperData wallpaper) {
2337 if (wallpaper.connection != null) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002338 if (wallpaper.connection.mReply != null) {
2339 try {
2340 wallpaper.connection.mReply.sendResult(null);
2341 } catch (RemoteException e) {
2342 }
2343 wallpaper.connection.mReply = null;
2344 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002345 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002346 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002347 wallpaper.connection.mEngine.destroy();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002348 } catch (RemoteException e) {
2349 }
2350 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002351 mContext.unbindService(wallpaper.connection);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07002352 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002353 if (DEBUG)
2354 Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002355 mIWindowManager.removeWindowToken(wallpaper.connection.mToken, DEFAULT_DISPLAY);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07002356 } catch (RemoteException e) {
2357 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002358 wallpaper.connection.mService = null;
2359 wallpaper.connection.mEngine = null;
2360 wallpaper.connection = null;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002361 }
2362 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002363
2364 void clearWallpaperComponentLocked(WallpaperData wallpaper) {
2365 wallpaper.wallpaperComponent = null;
2366 detachWallpaperLocked(wallpaper);
2367 }
2368
2369 void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002370 try {
Dianne Hackborn3be63c02009-08-20 19:31:38 -07002371 conn.mService.attach(conn, conn.mToken,
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002372 TYPE_WALLPAPER, false,
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002373 wallpaper.width, wallpaper.height, wallpaper.padding);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002374 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002375 Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002376 if (!wallpaper.wallpaperUpdating) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002377 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08002378 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002379 }
2380 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002381
2382 private void notifyCallbacksLocked(WallpaperData wallpaper) {
2383 final int n = wallpaper.callbacks.beginBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002384 for (int i = 0; i < n; i++) {
2385 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002386 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002387 } catch (RemoteException e) {
2388
2389 // The RemoteCallbackList will take care of removing
2390 // the dead object for us.
2391 }
2392 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002393 wallpaper.callbacks.finishBroadcast();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002395 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002396 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 }
2398
2399 private void checkPermission(String permission) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002400 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002401 throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
2402 + ", must have permission " + permission);
2403 }
2404 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002405
Benjamin Franzf3ece362015-02-11 10:51:10 +00002406 /**
2407 * Certain user types do not support wallpapers (e.g. managed profiles). The check is
2408 * implemented through through the OP_WRITE_WALLPAPER AppOp.
2409 */
2410 public boolean isWallpaperSupported(String callingPackage) {
2411 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
2412 callingPackage) == AppOpsManager.MODE_ALLOWED;
2413 }
2414
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002415 @Override
Christopher Tate98d609c2016-05-18 17:31:58 -07002416 public boolean isSetWallpaperAllowed(String callingPackage) {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002417 final PackageManager pm = mContext.getPackageManager();
2418 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
2419 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
2420 if (!uidMatchPackage) {
2421 return false; // callingPackage was faked.
2422 }
2423
2424 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
2425 if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
2426 return true;
2427 }
2428 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
2429 return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
2430 }
2431
Christopher Tated7faf532016-02-25 12:43:38 -08002432 @Override
Christopher Tate61722662016-08-10 16:13:14 -07002433 public boolean isWallpaperBackupEligible(int which, int userId) {
Christopher Tated7faf532016-02-25 12:43:38 -08002434 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
2435 throw new SecurityException("Only the system may call isWallpaperBackupEligible");
2436 }
2437
Christopher Tate61722662016-08-10 16:13:14 -07002438 WallpaperData wallpaper = (which == FLAG_LOCK)
Christopher Tatef7d1b5d2016-08-19 11:21:07 -07002439 ? mLockWallpaperMap.get(userId)
2440 : mWallpaperMap.get(userId);
Christopher Tated7faf532016-02-25 12:43:38 -08002441 return (wallpaper != null) ? wallpaper.allowBackup : false;
2442 }
2443
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002444 private static JournaledFile makeJournaledFile(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07002445 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002446 return new JournaledFile(new File(base), new File(base + ".tmp"));
2447 }
2448
Christopher Tatedb27b842016-02-25 14:39:17 -08002449 private void saveSettingsLocked(int userId) {
2450 JournaledFile journal = makeJournaledFile(userId);
2451 FileOutputStream fstream = null;
2452 BufferedOutputStream stream = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002453 try {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002454 XmlSerializer out = new FastXmlSerializer();
Christopher Tatedb27b842016-02-25 14:39:17 -08002455 fstream = new FileOutputStream(journal.chooseForWrite(), false);
2456 stream = new BufferedOutputStream(fstream);
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002457 out.setOutput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002458 out.startDocument(null, true);
2459
Christopher Tatedb27b842016-02-25 14:39:17 -08002460 WallpaperData wallpaper;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002461
Christopher Tatedb27b842016-02-25 14:39:17 -08002462 wallpaper = mWallpaperMap.get(userId);
2463 if (wallpaper != null) {
2464 writeWallpaperAttributes(out, "wp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002465 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002466 wallpaper = mLockWallpaperMap.get(userId);
2467 if (wallpaper != null) {
2468 writeWallpaperAttributes(out, "kwp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002469 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002470
2471 out.endDocument();
Christopher Tatedb27b842016-02-25 14:39:17 -08002472
2473 stream.flush(); // also flushes fstream
2474 FileUtils.sync(fstream);
2475 stream.close(); // also closes fstream
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002476 journal.commit();
2477 } catch (IOException e) {
Christopher Tatead3c2592016-01-20 18:13:17 -08002478 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002479 journal.rollback();
2480 }
2481 }
2482
Christopher Tatedb27b842016-02-25 14:39:17 -08002483 private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
2484 throws IllegalArgumentException, IllegalStateException, IOException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002485 if (DEBUG) {
Christopher Tatef717b932017-09-11 15:52:54 -07002486 Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002487 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002488 out.startTag(null, tag);
2489 out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
2490 out.attribute(null, "width", Integer.toString(wallpaper.width));
2491 out.attribute(null, "height", Integer.toString(wallpaper.height));
2492
2493 out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
2494 out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
2495 out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
2496 out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
2497
2498 if (wallpaper.padding.left != 0) {
2499 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
2500 }
2501 if (wallpaper.padding.top != 0) {
2502 out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
2503 }
2504 if (wallpaper.padding.right != 0) {
2505 out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
2506 }
2507 if (wallpaper.padding.bottom != 0) {
2508 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
2509 }
2510
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002511 if (wallpaper.primaryColors != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002512 int colorsCount = wallpaper.primaryColors.getMainColors().size();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002513 out.attribute(null, "colorsCount", Integer.toString(colorsCount));
2514 if (colorsCount > 0) {
2515 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002516 final Color wc = wallpaper.primaryColors.getMainColors().get(i);
2517 out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002518 }
2519 }
Lucas Dupin75ec3792017-06-29 14:07:18 -07002520 out.attribute(null, "colorHints",
Lucas Dupin84b89d92017-05-09 12:16:19 -07002521 Integer.toString(wallpaper.primaryColors.getColorHints()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002522 }
2523
Christopher Tatedb27b842016-02-25 14:39:17 -08002524 out.attribute(null, "name", wallpaper.name);
2525 if (wallpaper.wallpaperComponent != null
2526 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
2527 out.attribute(null, "component",
2528 wallpaper.wallpaperComponent.flattenToShortString());
2529 }
Christopher Tated7faf532016-02-25 12:43:38 -08002530
2531 if (wallpaper.allowBackup) {
2532 out.attribute(null, "backup", "true");
2533 }
2534
Christopher Tatedb27b842016-02-25 14:39:17 -08002535 out.endTag(null, tag);
2536 }
2537
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002538 private void migrateFromOld() {
Christopher Tate9f224432017-08-01 16:32:49 -07002539 // Pre-N, what existed is the one we're now using as the display crop
2540 File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP);
2541 // In the very-long-ago, imagery lived with the settings app
2542 File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
2543 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
2544
2545 // Migrations from earlier wallpaper image storage schemas
2546 if (preNWallpaper.exists()) {
2547 if (!newWallpaper.exists()) {
2548 // we've got the 'wallpaper' crop file but not the nominal source image,
2549 // so do the simple "just take everything" straight copy of legacy data
2550 if (DEBUG) {
2551 Slog.i(TAG, "Migrating wallpaper schema");
2552 }
2553 FileUtils.copyFile(preNWallpaper, newWallpaper);
2554 } // else we're in the usual modern case: both source & crop exist
2555 } else if (originalWallpaper.exists()) {
2556 // VERY old schema; make sure things exist and are in the right place
2557 if (DEBUG) {
2558 Slog.i(TAG, "Migrating antique wallpaper schema");
2559 }
2560 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
2561 if (oldInfo.exists()) {
2562 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
2563 oldInfo.renameTo(newInfo);
2564 }
2565
2566 FileUtils.copyFile(originalWallpaper, preNWallpaper);
2567 originalWallpaper.renameTo(newWallpaper);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002568 }
2569 }
2570
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002571 private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
2572 String value = parser.getAttributeValue(null, name);
2573 if (value == null) {
2574 return defValue;
2575 }
2576 return Integer.parseInt(value);
2577 }
2578
Xiaohui Chenac531942015-05-13 13:20:52 -07002579 /**
2580 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could
2581 * happen during user switch. The async user switch observer may not have received
2582 * the event yet. We use this safe method when we don't care about this ordering and just
2583 * want to update the data. The data is going to be applied when the user switch observer
2584 * is eventually executed.
Christopher Tatef717b932017-09-11 15:52:54 -07002585 *
2586 * Important: this method loads settings to initialize the given user's wallpaper data if
2587 * there is no current in-memory state.
Xiaohui Chenac531942015-05-13 13:20:52 -07002588 */
Christopher Tatebe132e62016-02-10 12:59:49 -08002589 private WallpaperData getWallpaperSafeLocked(int userId, int which) {
2590 // We're setting either just system (work with the system wallpaper),
2591 // both (also work with the system wallpaper), or just the lock
2592 // wallpaper (update against the existing lock wallpaper if any).
2593 // Combined or just-system operations use the 'system' WallpaperData
2594 // for this use; lock-only operations use the dedicated one.
2595 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07002596 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatebe132e62016-02-10 12:59:49 -08002597 WallpaperData wallpaper = whichSet.get(userId);
Xiaohui Chenac531942015-05-13 13:20:52 -07002598 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002599 // common case, this is the first lookup post-boot of the system or
2600 // unified lock, so we bring up the saved state lazily now and recheck.
Christopher Tated7faf532016-02-25 12:43:38 -08002601 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08002602 wallpaper = whichSet.get(userId);
2603 // if it's still null here, this is a lock-only operation and there is not
2604 // yet a lock-only wallpaper set for this user, so we need to establish
2605 // it now.
2606 if (wallpaper == null) {
Christopher Tateedf7d042016-03-29 18:24:25 -07002607 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002608 wallpaper = new WallpaperData(userId,
2609 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2610 mLockWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002611 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08002612 } else {
2613 // sanity fallback: we're in bad shape, but establishing a known
2614 // valid system+lock WallpaperData will keep us from dying.
2615 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
2616 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
2617 mWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002618 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08002619 }
2620 }
Xiaohui Chenac531942015-05-13 13:20:52 -07002621 }
2622 return wallpaper;
2623 }
2624
Christopher Tated7faf532016-02-25 12:43:38 -08002625 private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002626 JournaledFile journal = makeJournaledFile(userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002627 FileInputStream stream = null;
2628 File file = journal.chooseForRead();
Christopher Tate9f224432017-08-01 16:32:49 -07002629
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002630 WallpaperData wallpaper = mWallpaperMap.get(userId);
2631 if (wallpaper == null) {
Christopher Tate9f224432017-08-01 16:32:49 -07002632 // Do this once per boot
2633 migrateFromOld();
2634
Christopher Tatebe132e62016-02-10 12:59:49 -08002635 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
Christopher Tated7faf532016-02-25 12:43:38 -08002636 wallpaper.allowBackup = true;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002637 mWallpaperMap.put(userId, wallpaper);
Christopher Tate41297ff2016-03-10 16:46:15 -08002638 if (!wallpaper.cropExists()) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002639 if (wallpaper.sourceExists()) {
2640 generateCrop(wallpaper);
2641 } else {
2642 Slog.i(TAG, "No static wallpaper imagery; defaults will be shown");
2643 }
Christopher Tate41297ff2016-03-10 16:46:15 -08002644 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002645 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002646 boolean success = false;
2647 try {
2648 stream = new FileInputStream(file);
2649 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002650 parser.setInput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002651
2652 int type;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002653 do {
2654 type = parser.next();
2655 if (type == XmlPullParser.START_TAG) {
2656 String tag = parser.getName();
2657 if ("wp".equals(tag)) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002658 // Common to system + lock wallpapers
Christopher Tated7faf532016-02-25 12:43:38 -08002659 parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
Christopher Tatead3c2592016-01-20 18:13:17 -08002660
Christopher Tatebe132e62016-02-10 12:59:49 -08002661 // A system wallpaper might also be a live wallpaper
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002662 String comp = parser.getAttributeValue(null, "component");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002663 wallpaper.nextWallpaperComponent = comp != null
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002664 ? ComponentName.unflattenFromString(comp)
2665 : null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002666 if (wallpaper.nextWallpaperComponent == null
2667 || "android".equals(wallpaper.nextWallpaperComponent
2668 .getPackageName())) {
Justin Koh29c30162014-09-05 17:10:10 -07002669 wallpaper.nextWallpaperComponent = mImageWallpaper;
Dianne Hackborn9ea31632011-08-05 14:43:50 -07002670 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002671
Mike Clerona428b2c2009-11-15 22:53:08 -08002672 if (DEBUG) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002673 Slog.v(TAG, "mWidth:" + wallpaper.width);
2674 Slog.v(TAG, "mHeight:" + wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002675 Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002676 Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002677 Slog.v(TAG, "mName:" + wallpaper.name);
2678 Slog.v(TAG, "mNextWallpaperComponent:"
2679 + wallpaper.nextWallpaperComponent);
Mike Clerona428b2c2009-11-15 22:53:08 -08002680 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002681 } else if ("kwp".equals(tag)) {
2682 // keyguard-specific wallpaper for this user
2683 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2684 if (lockWallpaper == null) {
2685 lockWallpaper = new WallpaperData(userId,
2686 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2687 mLockWallpaperMap.put(userId, lockWallpaper);
2688 }
Christopher Tated7faf532016-02-25 12:43:38 -08002689 parseWallpaperAttributes(parser, lockWallpaper, false);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002690 }
2691 }
2692 } while (type != XmlPullParser.END_DOCUMENT);
2693 success = true;
Dianne Hackborn13579ed2012-11-28 18:05:36 -08002694 } catch (FileNotFoundException e) {
2695 Slog.w(TAG, "no current wallpaper -- first boot?");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002696 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002697 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002698 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002699 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002700 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002701 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002702 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002703 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002704 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002705 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002706 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002707 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002708
2709 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002710 wallpaper.width = -1;
2711 wallpaper.height = -1;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002712 wallpaper.cropHint.set(0, 0, 0, 0);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002713 wallpaper.padding.set(0, 0, 0, 0);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002714 wallpaper.name = "";
Adrian Roosc28e3a92016-04-14 10:47:52 -07002715
2716 mLockWallpaperMap.remove(userId);
Christopher Tatead3c2592016-01-20 18:13:17 -08002717 } else {
2718 if (wallpaper.wallpaperId <= 0) {
2719 wallpaper.wallpaperId = makeWallpaperIdLocked();
2720 if (DEBUG) {
2721 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
2722 + "); now " + wallpaper.wallpaperId);
2723 }
2724 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002725 }
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002726
Adrian Roosc28e3a92016-04-14 10:47:52 -07002727 ensureSaneWallpaperData(wallpaper);
2728 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2729 if (lockWallpaper != null) {
2730 ensureSaneWallpaperData(lockWallpaper);
2731 }
2732 }
2733
2734 private void ensureSaneWallpaperData(WallpaperData wallpaper) {
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002735 // We always want to have some reasonable width hint.
John Spurlock7ea91ec2013-11-04 13:48:38 -05002736 int baseSize = getMaximumSizeDimension();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002737 if (wallpaper.width < baseSize) {
2738 wallpaper.width = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002739 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002740 if (wallpaper.height < baseSize) {
2741 wallpaper.height = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002742 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002743 // and crop, if not previously specified
2744 if (wallpaper.cropHint.width() <= 0
2745 || wallpaper.cropHint.height() <= 0) {
2746 wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
2747 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002748 }
2749
Christopher Tated7faf532016-02-25 12:43:38 -08002750 private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
2751 boolean keepDimensionHints) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002752 final String idString = parser.getAttributeValue(null, "id");
2753 if (idString != null) {
2754 final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
2755 if (id > mWallpaperId) {
2756 mWallpaperId = id;
2757 }
2758 } else {
2759 wallpaper.wallpaperId = makeWallpaperIdLocked();
2760 }
2761
Christopher Tated7faf532016-02-25 12:43:38 -08002762 if (!keepDimensionHints) {
2763 wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
2764 wallpaper.height = Integer.parseInt(parser
2765 .getAttributeValue(null, "height"));
2766 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002767 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
2768 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
2769 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
2770 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
2771 wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
2772 wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
2773 wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
2774 wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002775 int colorsCount = getAttributeInt(parser, "colorsCount", 0);
2776 if (colorsCount > 0) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002777 Color primary = null, secondary = null, tertiary = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002778 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002779 Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
2780 if (i == 0) {
2781 primary = color;
2782 } else if (i == 1) {
2783 secondary = color;
2784 } else if (i == 2) {
2785 tertiary = color;
2786 } else {
2787 break;
2788 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002789 }
Lucas Dupin84b89d92017-05-09 12:16:19 -07002790 int colorHints = getAttributeInt(parser, "colorHints", 0);
2791 wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002792 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002793 wallpaper.name = parser.getAttributeValue(null, "name");
Christopher Tated7faf532016-02-25 12:43:38 -08002794 wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
Christopher Tatebe132e62016-02-10 12:59:49 -08002795 }
2796
John Spurlock7ea91ec2013-11-04 13:48:38 -05002797 private int getMaximumSizeDimension() {
2798 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
2799 Display d = wm.getDefaultDisplay();
2800 return d.getMaximumSizeDimension();
2801 }
2802
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002803 // Called by SystemBackupAgent after files are restored to disk.
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08002804 public void settingsRestored() {
2805 // Verify caller is the system
2806 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2807 throw new RuntimeException("settingsRestored() can only be called from the system process");
2808 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002809 // TODO: If necessary, make it work for secondary users as well. This currently assumes
2810 // restores only to the primary user
Joe Onorato8a9b2202010-02-26 18:56:32 -08002811 if (DEBUG) Slog.v(TAG, "settingsRestored");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002812 WallpaperData wallpaper = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002813 boolean success = false;
2814 synchronized (mLock) {
Christopher Tated7faf532016-02-25 12:43:38 -08002815 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatedb27b842016-02-25 14:39:17 -08002816 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tatead3c2592016-01-20 18:13:17 -08002817 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
Christopher Tated7faf532016-02-25 12:43:38 -08002818 wallpaper.allowBackup = true; // by definition if it was restored
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002819 if (wallpaper.nextWallpaperComponent != null
Justin Koh29c30162014-09-05 17:10:10 -07002820 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002821 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002822 wallpaper, null)) {
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002823 // No such live wallpaper or other failure; fall back to the default
2824 // live wallpaper (since the profile being restored indicated that the
2825 // user had selected a live rather than static one).
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002826 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002827 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002828 success = true;
2829 } else {
Mike Clerona428b2c2009-11-15 22:53:08 -08002830 // If there's a wallpaper name, we use that. If that can't be loaded, then we
2831 // use the default.
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002832 if ("".equals(wallpaper.name)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002833 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
Mike Clerona428b2c2009-11-15 22:53:08 -08002834 success = true;
2835 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002836 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002837 success = restoreNamedResourceLocked(wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002838 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002839 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
2840 + " id=" + wallpaper.wallpaperId);
Mike Clerona428b2c2009-11-15 22:53:08 -08002841 if (success) {
Christopher Tate41297ff2016-03-10 16:46:15 -08002842 generateCrop(wallpaper); // based on the new image + metadata
2843 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002844 wallpaper, null);
Mike Clerona428b2c2009-11-15 22:53:08 -08002845 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002846 }
2847 }
2848
2849 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002850 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
2851 wallpaper.name = "";
Christopher Tatedb27b842016-02-25 14:39:17 -08002852 getWallpaperDir(UserHandle.USER_SYSTEM).delete();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002853 }
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002854
2855 synchronized (mLock) {
Christopher Tatedb27b842016-02-25 14:39:17 -08002856 saveSettingsLocked(UserHandle.USER_SYSTEM);
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002857 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002858 }
2859
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002860 // Restore the named resource bitmap to both source + crop files
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002861 boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
2862 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
2863 String resName = wallpaper.name.substring(4);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002864
2865 String pkg = null;
2866 int colon = resName.indexOf(':');
2867 if (colon > 0) {
2868 pkg = resName.substring(0, colon);
2869 }
2870
2871 String ident = null;
2872 int slash = resName.lastIndexOf('/');
2873 if (slash > 0) {
2874 ident = resName.substring(slash+1);
2875 }
2876
2877 String type = null;
2878 if (colon > 0 && slash > 0 && (slash-colon) > 1) {
2879 type = resName.substring(colon+1, slash);
2880 }
2881
2882 if (pkg != null && ident != null && type != null) {
2883 int resId = -1;
2884 InputStream res = null;
2885 FileOutputStream fos = null;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002886 FileOutputStream cos = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002887 try {
2888 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
2889 Resources r = c.getResources();
2890 resId = r.getIdentifier(resName, null, null);
2891 if (resId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002892 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002893 + " ident=" + ident);
2894 return false;
2895 }
2896
2897 res = r.openRawResource(resId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002898 if (wallpaper.wallpaperFile.exists()) {
2899 wallpaper.wallpaperFile.delete();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002900 wallpaper.cropFile.delete();
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07002901 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002902 fos = new FileOutputStream(wallpaper.wallpaperFile);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002903 cos = new FileOutputStream(wallpaper.cropFile);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002904
2905 byte[] buffer = new byte[32768];
2906 int amt;
2907 while ((amt=res.read(buffer)) > 0) {
2908 fos.write(buffer, 0, amt);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002909 cos.write(buffer, 0, amt);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002910 }
2911 // mWallpaperObserver will notice the close and send the change broadcast
2912
Joe Onorato8a9b2202010-02-26 18:56:32 -08002913 Slog.v(TAG, "Restored wallpaper: " + resName);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002914 return true;
2915 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002916 Slog.e(TAG, "Package name " + pkg + " not found");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002917 } catch (Resources.NotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002918 Slog.e(TAG, "Resource not found: " + resId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002919 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002920 Slog.e(TAG, "IOException while restoring wallpaper ", e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002921 } finally {
Christopher Tatead3c2592016-01-20 18:13:17 -08002922 IoUtils.closeQuietly(res);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002923 if (fos != null) {
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07002924 FileUtils.sync(fos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002925 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002926 if (cos != null) {
2927 FileUtils.sync(cos);
2928 }
2929 IoUtils.closeQuietly(fos);
2930 IoUtils.closeQuietly(cos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002931 }
2932 }
2933 }
2934 return false;
2935 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002936
Dianne Hackborneb034652009-09-07 00:49:58 -07002937 @Override
2938 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06002939 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Dianne Hackborneb034652009-09-07 00:49:58 -07002940
2941 synchronized (mLock) {
Adrian Roosc28e3a92016-04-14 10:47:52 -07002942 pw.println("System wallpaper state:");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002943 for (int i = 0; i < mWallpaperMap.size(); i++) {
2944 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
Christopher Tatead3c2592016-01-20 18:13:17 -08002945 pw.print(" User "); pw.print(wallpaper.userId);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002946 pw.print(": id="); pw.println(wallpaper.wallpaperId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002947 pw.print(" mWidth=");
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002948 pw.print(wallpaper.width);
2949 pw.print(" mHeight=");
2950 pw.println(wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002951 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002952 pw.print(" mPadding="); pw.println(wallpaper.padding);
2953 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01002954 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002955 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002956 if (wallpaper.connection != null) {
2957 WallpaperConnection conn = wallpaper.connection;
2958 pw.print(" Wallpaper connection ");
2959 pw.print(conn);
2960 pw.println(":");
2961 if (conn.mInfo != null) {
2962 pw.print(" mInfo.component=");
2963 pw.println(conn.mInfo.getComponent());
2964 }
2965 pw.print(" mToken=");
2966 pw.println(conn.mToken);
2967 pw.print(" mService=");
2968 pw.println(conn.mService);
2969 pw.print(" mEngine=");
2970 pw.println(conn.mEngine);
2971 pw.print(" mLastDiedTime=");
2972 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
2973 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002974 }
Adrian Roosc28e3a92016-04-14 10:47:52 -07002975 pw.println("Lock wallpaper state:");
2976 for (int i = 0; i < mLockWallpaperMap.size(); i++) {
2977 WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
2978 pw.print(" User "); pw.print(wallpaper.userId);
2979 pw.print(": id="); pw.println(wallpaper.wallpaperId);
2980 pw.print(" mWidth="); pw.print(wallpaper.width);
2981 pw.print(" mHeight="); pw.println(wallpaper.height);
2982 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
2983 pw.print(" mPadding="); pw.println(wallpaper.padding);
2984 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01002985 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002986 }
2987
Dianne Hackborneb034652009-09-07 00:49:58 -07002988 }
2989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002990}