blob: b888ec21e70864147ed3d2f4584850682de56f72 [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;
Christopher Tate1e1e2e02016-01-25 15:34:36 -080054import android.graphics.Bitmap;
55import android.graphics.BitmapFactory;
56import android.graphics.BitmapRegionDecoder;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -070057import android.graphics.Color;
John Spurlock41f64642013-11-04 13:48:38 -050058import android.graphics.Point;
Dianne Hackborn067e5f62014-09-07 23:14:30 -070059import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.os.Binder;
Dianne Hackborn284ac932009-08-28 10:34:25 -070061import android.os.Bundle;
Amith Yamasani13593602012-03-22 16:16:17 -070062import android.os.Environment;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060063import android.os.FileObserver;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070064import android.os.FileUtils;
Christopher Tatec349e59f2017-05-05 17:37:43 -070065import android.os.Handler;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070066import android.os.IBinder;
Lucas Dupin50ba9912017-07-14 11:55:05 -070067import android.os.IInterface;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -070068import android.os.IRemoteCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.os.ParcelFileDescriptor;
Lucas Dupin75ec3792017-06-29 14:07:18 -070070import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.os.RemoteCallbackList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060072import android.os.RemoteException;
rpcraig554cb0c2012-07-05 06:41:43 -040073import android.os.SELinux;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070074import android.os.ServiceManager;
Dianne Hackborn0cd48872009-08-13 18:51:59 -070075import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070076import android.os.UserHandle;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070077import android.os.UserManager;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070078import android.service.wallpaper.IWallpaperConnection;
79import android.service.wallpaper.IWallpaperEngine;
80import android.service.wallpaper.IWallpaperService;
81import android.service.wallpaper.WallpaperService;
Christopher Tate8347b632016-04-29 18:59:18 -070082import android.system.ErrnoException;
83import android.system.Os;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -070084import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080085import android.util.Slog;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080086import android.util.SparseArray;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070087import android.util.Xml;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -070088import android.view.Display;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070089import android.view.IWindowManager;
90import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060092import com.android.internal.R;
93import com.android.internal.content.PackageMonitor;
Christopher Tate190e8532016-07-11 11:35:34 -070094import com.android.internal.os.BackgroundThread;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060095import com.android.internal.util.DumpUtils;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060096import com.android.internal.util.FastXmlSerializer;
97import com.android.internal.util.JournaledFile;
98import com.android.server.EventLogTags;
Adrian Roosc3f915e2016-09-06 11:40:53 -070099import com.android.server.FgThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600100import com.android.server.SystemService;
101
102import libcore.io.IoUtils;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700103
104import org.xmlpull.v1.XmlPullParser;
105import org.xmlpull.v1.XmlPullParserException;
106import org.xmlpull.v1.XmlSerializer;
107
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600108import java.io.BufferedOutputStream;
109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
113import java.io.FileOutputStream;
114import java.io.IOException;
115import java.io.InputStream;
116import java.io.PrintWriter;
117import java.nio.charset.StandardCharsets;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400118import java.util.ArrayList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600119import java.util.Arrays;
120import java.util.List;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700121import java.util.Objects;
Christopher Tatead3c2592016-01-20 18:13:17 -0800122
Amith Yamasani09e9cdc2013-11-06 14:54:50 -0800123public class WallpaperManagerService extends IWallpaperManager.Stub {
124 static final String TAG = "WallpaperManagerService";
Joe Onorato7e1693a2016-02-01 17:45:03 -0800125 static final boolean DEBUG = false;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700126 static final boolean DEBUG_LIVE = DEBUG || true;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700127
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600128 public static class Lifecycle extends SystemService {
129 private WallpaperManagerService mService;
130
131 public Lifecycle(Context context) {
132 super(context);
133 }
134
135 @Override
136 public void onStart() {
137 mService = new WallpaperManagerService(getContext());
138 publishBinderService(Context.WALLPAPER_SERVICE, mService);
139 }
140
141 @Override
142 public void onBootPhase(int phase) {
143 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
144 mService.systemReady();
Jeff Sharkey383f9fe2016-04-13 16:08:15 -0600145 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
146 mService.switchUser(UserHandle.USER_SYSTEM, null);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600147 }
148 }
149
150 @Override
151 public void onUnlockUser(int userHandle) {
152 mService.onUnlockUser(userHandle);
153 }
154 }
155
Christopher Tatebe132e62016-02-10 12:59:49 -0800156 final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700158 /**
159 * Minimum time between crashes of a wallpaper service for us to consider
160 * restarting it vs. just reverting to the static wallpaper.
161 */
162 static final long MIN_WALLPAPER_CRASH_TIME = 10000;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700163 static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800164 static final String WALLPAPER = "wallpaper_orig";
165 static final String WALLPAPER_CROP = "wallpaper";
Christopher Tatebe132e62016-02-10 12:59:49 -0800166 static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
167 static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800168 static final String WALLPAPER_INFO = "wallpaper_info.xml";
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700169
Christopher Tatebe132e62016-02-10 12:59:49 -0800170 // All the various per-user state files we need to be aware of
171 static final String[] sPerUserFiles = new String[] {
172 WALLPAPER, WALLPAPER_CROP,
173 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
174 WALLPAPER_INFO
175 };
176
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700177 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
179 * that the wallpaper has changed. The CREATE is triggered when there is no
180 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
Christopher Tate190e8532016-07-11 11:35:34 -0700181 * every time the wallpaper is changed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 */
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800183 private class WallpaperObserver extends FileObserver {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700184
Christopher Tatebe132e62016-02-10 12:59:49 -0800185 final int mUserId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800186 final WallpaperData mWallpaper;
187 final File mWallpaperDir;
188 final File mWallpaperFile;
Christopher Tatebe132e62016-02-10 12:59:49 -0800189 final File mWallpaperLockFile;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800190
191 public WallpaperObserver(WallpaperData wallpaper) {
192 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
Christopher Tateda058e22014-10-08 14:51:09 -0700193 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
Christopher Tatebe132e62016-02-10 12:59:49 -0800194 mUserId = wallpaper.userId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800195 mWallpaperDir = getWallpaperDir(wallpaper.userId);
196 mWallpaper = wallpaper;
197 mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
Christopher Tatebe132e62016-02-10 12:59:49 -0800198 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800199 }
200
Christopher Tatebe132e62016-02-10 12:59:49 -0800201 private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
202 WallpaperData wallpaper = null;
203 synchronized (mLock) {
204 if (lockChanged) {
205 wallpaper = mLockWallpaperMap.get(mUserId);
206 }
207 if (wallpaper == null) {
208 // no lock-specific wallpaper exists, or sys case, handled together
209 wallpaper = mWallpaperMap.get(mUserId);
210 }
211 }
212 return (wallpaper != null) ? wallpaper : mWallpaper;
213 }
214
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800215 @Override
216 public void onEvent(int event, String path) {
217 if (path == null) {
218 return;
219 }
Christopher Tated7faf532016-02-25 12:43:38 -0800220 final boolean moved = (event == MOVED_TO);
221 final boolean written = (event == CLOSE_WRITE || moved);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800222 final File changedFile = new File(mWallpaperDir, path);
223
Christopher Tatebe132e62016-02-10 12:59:49 -0800224 // System and system+lock changes happen on the system wallpaper input file;
225 // lock-only changes happen on the dedicated lock wallpaper input file
226 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
227 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700228 int notifyColorsWhich = 0;
Christopher Tatebe132e62016-02-10 12:59:49 -0800229 WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
230
231 if (DEBUG) {
232 Slog.v(TAG, "Wallpaper file change: evt=" + event
233 + " path=" + path
234 + " sys=" + sysWallpaperChanged
235 + " lock=" + lockWallpaperChanged
236 + " imagePending=" + wallpaper.imageWallpaperPending
237 + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
238 + " written=" + written);
239 }
Christopher Tate8347b632016-04-29 18:59:18 -0700240
241 if (moved && lockWallpaperChanged) {
242 // We just migrated sys -> lock to preserve imagery for an impending
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700243 // new system-only wallpaper. Tell keyguard about it and make sure it
244 // has the right SELinux label.
Christopher Tate8347b632016-04-29 18:59:18 -0700245 if (DEBUG) {
246 Slog.i(TAG, "Sys -> lock MOVED_TO");
247 }
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700248 SELinux.restorecon(changedFile);
Christopher Tate8347b632016-04-29 18:59:18 -0700249 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700250 notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK);
Christopher Tate8347b632016-04-29 18:59:18 -0700251 return;
252 }
253
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800254 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800255 if (sysWallpaperChanged || lockWallpaperChanged) {
256 notifyCallbacksLocked(wallpaper);
257 if (wallpaper.wallpaperComponent == null
Christopher Tateda058e22014-10-08 14:51:09 -0700258 || event != CLOSE_WRITE // includes the MOVED_TO case
Christopher Tatebe132e62016-02-10 12:59:49 -0800259 || wallpaper.imageWallpaperPending) {
Christopher Tateda058e22014-10-08 14:51:09 -0700260 if (written) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800261 // The image source has finished writing the source image,
262 // so we now produce the crop rect (in the background), and
263 // only publish the new displayable (sub)image as a result
264 // of that work.
Christopher Tatebe132e62016-02-10 12:59:49 -0800265 if (DEBUG) {
266 Slog.v(TAG, "Wallpaper written; generating crop");
267 }
Christopher Tateebadfb12016-07-25 14:50:08 -0700268 SELinux.restorecon(changedFile);
Christopher Tated7faf532016-02-25 12:43:38 -0800269 if (moved) {
270 // This is a restore, so generate the crop using any just-restored new
271 // crop guidelines, making sure to preserve our local dimension hints.
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700272 // We also make sure to reapply the correct SELinux label.
Christopher Tated7faf532016-02-25 12:43:38 -0800273 if (DEBUG) {
274 Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
275 }
276 loadSettingsLocked(wallpaper.userId, true);
277 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800278 generateCrop(wallpaper);
279 if (DEBUG) {
280 Slog.v(TAG, "Crop done; invoking completion callback");
281 }
282 wallpaper.imageWallpaperPending = false;
Christopher Tatebe132e62016-02-10 12:59:49 -0800283 if (sysWallpaperChanged) {
284 // If this was the system wallpaper, rebind...
285 bindWallpaperComponentLocked(mImageWallpaper, true,
286 false, wallpaper, null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700287 notifyColorsWhich |= FLAG_SYSTEM;
Christopher Tatebe132e62016-02-10 12:59:49 -0800288 }
289 if (lockWallpaperChanged
Christopher Tateedf7d042016-03-29 18:24:25 -0700290 || (wallpaper.whichPending & FLAG_LOCK) != 0) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800291 if (DEBUG) {
Christopher Tatedb27b842016-02-25 14:39:17 -0800292 Slog.i(TAG, "Lock-relevant wallpaper changed");
Christopher Tatebe132e62016-02-10 12:59:49 -0800293 }
Christopher Tatedb27b842016-02-25 14:39:17 -0800294 // either a lock-only wallpaper commit or a system+lock event.
295 // if it's system-plus-lock we need to wipe the lock bookkeeping;
296 // we're falling back to displaying the system wallpaper there.
297 if (!lockWallpaperChanged) {
298 mLockWallpaperMap.remove(wallpaper.userId);
299 }
300 // and in any case, tell keyguard about it
Christopher Tate8347b632016-04-29 18:59:18 -0700301 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700302 notifyColorsWhich |= FLAG_LOCK;
Christopher Tatebe132e62016-02-10 12:59:49 -0800303 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700304
Christopher Tatedb27b842016-02-25 14:39:17 -0800305 saveSettingsLocked(wallpaper.userId);
Christopher Tate8efbe0d2017-08-29 16:50:13 -0700306
307 // Publish completion *after* we've persisted the changes
308 if (wallpaper.setComplete != null) {
309 try {
310 wallpaper.setComplete.onWallpaperChanged();
311 } catch (RemoteException e) {
312 // if this fails we don't really care; the setting app may just
313 // have crashed and that sort of thing is a fact of life.
314 }
315 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 }
318 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800319 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700320
321 // Outside of the lock since it will synchronize itself
322 if (notifyColorsWhich != 0) {
323 notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
324 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800325 }
326 }
327
Christopher Tate8347b632016-04-29 18:59:18 -0700328 void notifyLockWallpaperChanged() {
329 final IWallpaperManagerCallback cb = mKeyguardListener;
330 if (cb != null) {
331 try {
332 cb.onWallpaperChanged();
333 } catch (RemoteException e) {
334 // Oh well it went away; no big deal
335 }
336 }
337 }
338
Lucas Dupin50ba9912017-07-14 11:55:05 -0700339 private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700340 boolean needsExtraction;
341 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700342 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
343 mColorsChangedListeners.get(wallpaper.userId);
344 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
345 mColorsChangedListeners.get(UserHandle.USER_ALL);
346 // No-op until someone is listening to it.
347 if (emptyCallbackList(currentUserColorListeners) &&
348 emptyCallbackList(userAllColorListeners)) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700349 return;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700350 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700351
352 if (DEBUG) {
353 Slog.v(TAG, "notifyWallpaperColorsChanged " + which);
354 }
355
356 needsExtraction = wallpaper.primaryColors == null;
357 }
358
Lucas Dupin75ec3792017-06-29 14:07:18 -0700359 // Let's notify the current values, it's fine if it's null, it just means
360 // that we don't know yet.
Lucas Dupin50ba9912017-07-14 11:55:05 -0700361 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700362
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700363 if (needsExtraction) {
364 extractColors(wallpaper);
Lucas Dupin50ba9912017-07-14 11:55:05 -0700365 synchronized (mLock) {
366 // Don't need to notify if nothing changed.
367 if (wallpaper.primaryColors == null) {
368 return;
369 }
370 }
371 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700372 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700373 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700374
Lucas Dupin50ba9912017-07-14 11:55:05 -0700375 private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
376 return (list == null || list.getRegisteredCallbackCount() == 0);
377 }
378
379 private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
380 int userId) {
Lucas Dupin75ec3792017-06-29 14:07:18 -0700381 final IWallpaperManagerCallback keyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400382 final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700383 synchronized (mLock) {
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400384 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
385 mColorsChangedListeners.get(userId);
386 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
387 mColorsChangedListeners.get(UserHandle.USER_ALL);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700388 keyguardListener = mKeyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400389
390 if (currentUserColorListeners != null) {
391 final int count = currentUserColorListeners.beginBroadcast();
392 for (int i = 0; i < count; i++) {
393 colorListeners.add(currentUserColorListeners.getBroadcastItem(i));
394 }
395 currentUserColorListeners.finishBroadcast();
396 }
397
398 if (userAllColorListeners != null) {
399 final int count = userAllColorListeners.beginBroadcast();
400 for (int i = 0; i < count; i++) {
401 colorListeners.add(userAllColorListeners.getBroadcastItem(i));
402 }
403 userAllColorListeners.finishBroadcast();
404 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700405 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700406
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400407 final int count = colorListeners.size();
408 for (int i = 0; i < count; i++) {
409 try {
410 colorListeners.get(i).onWallpaperColorsChanged(wallpaperColors, which, userId);
411 } catch (RemoteException e) {
412 // Callback is gone, it's not necessary to unregister it since
413 // RemoteCallbackList#getBroadcastItem will take care of it.
Lucas Dupin75ec3792017-06-29 14:07:18 -0700414 }
415 }
416
417 if (keyguardListener != null) {
418 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700419 keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700420 } catch (RemoteException e) {
421 // Oh well it went away; no big deal
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700422 }
423 }
424 }
425
Lucas Dupinbcae5852017-05-03 12:42:58 -0700426 /**
427 * We can easily extract colors from an ImageWallpaper since it's only a bitmap.
Lucas Dupin284836b2017-06-23 15:28:41 -0700428 * In this case, using the crop is more than enough. Live wallpapers are just ignored.
Lucas Dupinbcae5852017-05-03 12:42:58 -0700429 *
430 * @param wallpaper a wallpaper representation
431 */
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700432 private void extractColors(WallpaperData wallpaper) {
433 String cropFile = null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700434 int wallpaperId;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700435
Lucas Dupinbcae5852017-05-03 12:42:58 -0700436 synchronized (mLock) {
Lucas Dupin284836b2017-06-23 15:28:41 -0700437 // Not having a wallpaperComponent means it's a lock screen wallpaper.
438 final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
Lucas Dupinbcae5852017-05-03 12:42:58 -0700439 || wallpaper.wallpaperComponent == null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700440 if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
441 cropFile = wallpaper.cropFile.getAbsolutePath();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700442 }
443 wallpaperId = wallpaper.wallpaperId;
444 }
445
Lucas Dupin84b89d92017-05-09 12:16:19 -0700446 WallpaperColors colors = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700447 if (cropFile != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700448 Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
Lucas Dupin284836b2017-06-23 15:28:41 -0700449 if (bitmap != null) {
450 colors = WallpaperColors.fromBitmap(bitmap);
451 bitmap.recycle();
452 }
Lucas Dupinbcae5852017-05-03 12:42:58 -0700453 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700454
Lucas Dupin84b89d92017-05-09 12:16:19 -0700455 if (colors == null) {
Lucas Dupinbcae5852017-05-03 12:42:58 -0700456 Slog.w(TAG, "Cannot extract colors because wallpaper could not be read.");
457 return;
458 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700459
Lucas Dupinbcae5852017-05-03 12:42:58 -0700460 synchronized (mLock) {
461 if (wallpaper.wallpaperId == wallpaperId) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700462 wallpaper.primaryColors = colors;
Lucas Dupin75ec3792017-06-29 14:07:18 -0700463 // Now that we have the colors, let's save them into the xml
464 // to avoid having to run this again.
465 saveSettingsLocked(wallpaper.userId);
Lucas Dupinbcae5852017-05-03 12:42:58 -0700466 } else {
467 Slog.w(TAG, "Not setting primary colors since wallpaper changed");
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700468 }
469 }
470 }
471
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800472 /**
473 * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
474 * for display.
475 */
476 private void generateCrop(WallpaperData wallpaper) {
477 boolean success = false;
Christopher Tate1a96b632016-03-22 15:25:42 -0700478
479 Rect cropHint = new Rect(wallpaper.cropHint);
Christopher Tatebe132e62016-02-10 12:59:49 -0800480
481 if (DEBUG) {
482 Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
483 + Integer.toHexString(wallpaper.whichPending)
Christopher Tate1a96b632016-03-22 15:25:42 -0700484 + " to " + wallpaper.cropFile.getName()
485 + " crop=(" + cropHint.width() + 'x' + cropHint.height()
486 + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
Christopher Tatebe132e62016-02-10 12:59:49 -0800487 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800488
489 // Analyse the source; needed in multiple cases
490 BitmapFactory.Options options = new BitmapFactory.Options();
491 options.inJustDecodeBounds = true;
492 BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
Christopher Tate1a96b632016-03-22 15:25:42 -0700493 if (options.outWidth <= 0 || options.outHeight <= 0) {
Joe LaPennac298b162016-05-02 15:25:50 -0700494 Slog.w(TAG, "Invalid wallpaper data");
Christopher Tate1a96b632016-03-22 15:25:42 -0700495 success = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800496 } else {
Christopher Tate1a96b632016-03-22 15:25:42 -0700497 boolean needCrop = false;
498 boolean needScale = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800499
Christopher Tate1a96b632016-03-22 15:25:42 -0700500 // Empty crop means use the full image
501 if (cropHint.isEmpty()) {
502 cropHint.left = cropHint.top = 0;
503 cropHint.right = options.outWidth;
504 cropHint.bottom = options.outHeight;
505 } else {
506 // force the crop rect to lie within the measured bounds
507 cropHint.offset(
508 (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
509 (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
510
Adrian Roos5c97ff22016-08-31 10:25:38 -0700511 // If the crop hint was larger than the image we just overshot. Patch things up.
512 if (cropHint.left < 0) {
513 cropHint.left = 0;
514 }
515 if (cropHint.top < 0) {
516 cropHint.top = 0;
517 }
518
Christopher Tate1a96b632016-03-22 15:25:42 -0700519 // Don't bother cropping if what we're left with is identity
Christopher Tateebadfb12016-07-25 14:50:08 -0700520 needCrop = (options.outHeight > cropHint.height()
Adrian Roos5c97ff22016-08-31 10:25:38 -0700521 || options.outWidth > cropHint.width());
Christopher Tate1a96b632016-03-22 15:25:42 -0700522 }
523
524 // scale if the crop height winds up not matching the recommended metrics
525 needScale = (wallpaper.height != cropHint.height());
526
527 if (DEBUG) {
528 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
529 Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
530 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
531 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
532 }
533
534 if (!needCrop && !needScale) {
535 // Simple case: the nominal crop fits what we want, so we take
536 // the whole thing and just copy the image file directly.
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800537 if (DEBUG) {
Christopher Tate1a96b632016-03-22 15:25:42 -0700538 Slog.v(TAG, "Null crop of new wallpaper; copying");
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800539 }
Christopher Tate1a96b632016-03-22 15:25:42 -0700540 success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
541 if (!success) {
542 wallpaper.cropFile.delete();
543 // TODO: fall back to default wallpaper in this case
544 }
545 } else {
546 // Fancy case: crop and scale. First, we decode and scale down if appropriate.
547 FileOutputStream f = null;
548 BufferedOutputStream bos = null;
549 try {
550 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
551 wallpaper.wallpaperFile.getAbsolutePath(), false);
552
553 // This actually downsamples only by powers of two, but that's okay; we do
554 // a proper scaling blit later. This is to minimize transient RAM use.
555 // We calculate the largest power-of-two under the actual ratio rather than
556 // just let the decode take care of it because we also want to remap where the
557 // cropHint rectangle lies in the decoded [super]rect.
558 final BitmapFactory.Options scaler;
559 final int actualScale = cropHint.height() / wallpaper.height;
560 int scale = 1;
561 while (2*scale < actualScale) {
562 scale *= 2;
563 }
564 if (scale > 1) {
565 scaler = new BitmapFactory.Options();
566 scaler.inSampleSize = scale;
567 if (DEBUG) {
568 Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
569 }
570 } else {
571 scaler = null;
572 }
573 Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
574 decoder.recycle();
575
576 if (cropped == null) {
577 Slog.e(TAG, "Could not decode new wallpaper");
578 } else {
579 // We've got the extracted crop; now we want to scale it properly to
580 // the desired rectangle. That's a height-biased operation: make it
581 // fit the hinted height, and accept whatever width we end up with.
582 cropHint.offsetTo(0, 0);
583 cropHint.right /= scale; // adjust by downsampling factor
584 cropHint.bottom /= scale;
585 final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
586 if (DEBUG) {
587 Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
588 }
589 final int destWidth = (int)(cropHint.width() * heightR);
590 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
591 destWidth, wallpaper.height, true);
592 if (DEBUG) {
593 Slog.v(TAG, "Final extract:");
594 Slog.v(TAG, " dims: w=" + wallpaper.width
595 + " h=" + wallpaper.height);
596 Slog.v(TAG, " out: w=" + finalCrop.getWidth()
597 + " h=" + finalCrop.getHeight());
598 }
599
600 f = new FileOutputStream(wallpaper.cropFile);
601 bos = new BufferedOutputStream(f, 32*1024);
Christopher Tatec484f542016-05-11 14:31:34 -0700602 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
Christopher Tate1a96b632016-03-22 15:25:42 -0700603 bos.flush(); // don't rely on the implicit flush-at-close when noting success
604 success = true;
605 }
606 } catch (Exception e) {
607 if (DEBUG) {
608 Slog.e(TAG, "Error decoding crop", e);
609 }
610 } finally {
611 IoUtils.closeQuietly(bos);
612 IoUtils.closeQuietly(f);
613 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800614 }
615 }
616
617 if (!success) {
618 Slog.e(TAG, "Unable to apply new wallpaper");
619 wallpaper.cropFile.delete();
620 }
621
622 if (wallpaper.cropFile.exists()) {
623 boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
624 if (DEBUG) {
625 Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
626 }
627 }
628 }
629
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700630 final Context mContext;
631 final IWindowManager mIWindowManager;
Amith Yamasani4e2820c2012-08-28 22:17:23 -0700632 final IPackageManager mIPackageManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800633 final MyPackageMonitor mMonitor;
Benjamin Franzf3ece362015-02-11 10:51:10 +0000634 final AppOpsManager mAppOpsManager;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700635 /**
636 * Map of color listeners per user id.
637 * The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
638 */
639 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> mColorsChangedListeners;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800640 WallpaperData mLastWallpaper;
Christopher Tatebe132e62016-02-10 12:59:49 -0800641 IWallpaperManagerCallback mKeyguardListener;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600642 boolean mWaitingForUnlock;
Christopher Tate762dfd12016-10-10 17:44:48 -0700643 boolean mShuttingDown;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644
Justin Koh29c30162014-09-05 17:10:10 -0700645 /**
Christopher Tatead3c2592016-01-20 18:13:17 -0800646 * ID of the current wallpaper, changed every time anything sets a wallpaper.
647 * This is used for external detection of wallpaper update activity.
648 */
649 int mWallpaperId;
650
651 /**
Justin Koh29c30162014-09-05 17:10:10 -0700652 * Name of the component used to display bitmap wallpapers from either the gallery or
653 * built-in wallpapers.
654 */
655 final ComponentName mImageWallpaper;
656
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700657 /**
658 * Name of the default wallpaper component; might be different from mImageWallpaper
659 */
660 final ComponentName mDefaultWallpaperComponent;
661
Christopher Tatebe132e62016-02-10 12:59:49 -0800662 final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
663 final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
Dianne Hackborn07213e62011-08-24 20:05:39 -0700664
Christopher Tate38a5dc32016-07-20 15:10:18 -0700665 final SparseArray<Boolean> mUserRestorecon = new SparseArray<Boolean>();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800666 int mCurrentUserId;
Dianne Hackborn07213e62011-08-24 20:05:39 -0700667
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800668 static class WallpaperData {
669
670 int userId;
671
Christopher Tatebe132e62016-02-10 12:59:49 -0800672 final File wallpaperFile; // source image
673 final File cropFile; // eventual destination
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800674
675 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800676 * True while the client is writing a new wallpaper
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800677 */
678 boolean imageWallpaperPending;
679
680 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800681 * Which new wallpapers are being written; mirrors the 'which'
682 * selector bit field to setWallpaper().
683 */
684 int whichPending;
685
686 /**
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800687 * Callback once the set + crop is finished
688 */
689 IWallpaperManagerCallback setComplete;
690
691 /**
Christopher Tated7faf532016-02-25 12:43:38 -0800692 * Is the OS allowed to back up this wallpaper imagery?
693 */
694 boolean allowBackup;
695
696 /**
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800697 * Resource name if using a picture from the wallpaper gallery
698 */
699 String name = "";
700
701 /**
702 * The component name of the currently set live wallpaper.
703 */
704 ComponentName wallpaperComponent;
705
706 /**
707 * The component name of the wallpaper that should be set next.
708 */
709 ComponentName nextWallpaperComponent;
710
Christopher Tatead3c2592016-01-20 18:13:17 -0800711 /**
712 * The ID of this wallpaper
713 */
714 int wallpaperId;
715
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700716 /**
717 * Primary colors histogram
718 */
719 WallpaperColors primaryColors;
720
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800721 WallpaperConnection connection;
722 long lastDiedTime;
723 boolean wallpaperUpdating;
724 WallpaperObserver wallpaperObserver;
725
726 /**
727 * List of callbacks registered they should each be notified when the wallpaper is changed.
728 */
729 private RemoteCallbackList<IWallpaperManagerCallback> callbacks
730 = new RemoteCallbackList<IWallpaperManagerCallback>();
731
732 int width = -1;
733 int height = -1;
734
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800735 /**
736 * The crop hint supplied for displaying a subset of the source image
737 */
738 final Rect cropHint = new Rect(0, 0, 0, 0);
739
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700740 final Rect padding = new Rect(0, 0, 0, 0);
741
Christopher Tatebe132e62016-02-10 12:59:49 -0800742 WallpaperData(int userId, String inputFileName, String cropFileName) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800743 this.userId = userId;
Christopher Tatebe132e62016-02-10 12:59:49 -0800744 final File wallpaperDir = getWallpaperDir(userId);
745 wallpaperFile = new File(wallpaperDir, inputFileName);
746 cropFile = new File(wallpaperDir, cropFileName);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800747 }
748
Christopher Tatebe132e62016-02-10 12:59:49 -0800749 // Called during initialization of a given user's wallpaper bookkeeping
Christopher Tate41297ff2016-03-10 16:46:15 -0800750 boolean cropExists() {
751 return cropFile.exists();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800752 }
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700753
754 boolean sourceExists() {
755 return wallpaperFile.exists();
756 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800757 }
758
Christopher Tatead3c2592016-01-20 18:13:17 -0800759 int makeWallpaperIdLocked() {
760 do {
761 ++mWallpaperId;
762 } while (mWallpaperId == 0);
763 return mWallpaperId;
764 }
765
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700766 class WallpaperConnection extends IWallpaperConnection.Stub
767 implements ServiceConnection {
Adrian Roosc3f915e2016-09-06 11:40:53 -0700768
769 /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
770 * middle of an update). If exceeded, the wallpaper gets reset to the system default. */
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700771 private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000;
Adrian Roosc3f915e2016-09-06 11:40:53 -0700772
Dianne Hackborneb034652009-09-07 00:49:58 -0700773 final WallpaperInfo mInfo;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700774 final Binder mToken = new Binder();
775 IWallpaperService mService;
776 IWallpaperEngine mEngine;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800777 WallpaperData mWallpaper;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700778 IRemoteCallback mReply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779
Michael Wright5203a8b2013-10-03 14:16:42 -0700780 boolean mDimensionsChanged = false;
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700781 boolean mPaddingChanged = false;
Michael Wright5203a8b2013-10-03 14:16:42 -0700782
Adrian Roosc3f915e2016-09-06 11:40:53 -0700783 private Runnable mResetRunnable = () -> {
784 synchronized (mLock) {
Christopher Tate762dfd12016-10-10 17:44:48 -0700785 if (mShuttingDown) {
786 // Don't expect wallpaper services to relaunch during shutdown
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700787 if (DEBUG_LIVE) {
Christopher Tate762dfd12016-10-10 17:44:48 -0700788 Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
789 }
790 return;
791 }
792
Adrian Roosc3f915e2016-09-06 11:40:53 -0700793 if (!mWallpaper.wallpaperUpdating
794 && mWallpaper.userId == mCurrentUserId) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700795 Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
796 + ", reverting to built-in wallpaper!");
Adrian Roosc3f915e2016-09-06 11:40:53 -0700797 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
798 null);
799 }
800 }
801 };
802
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800803 public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700804 mInfo = info;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800805 mWallpaper = wallpaper;
Dianne Hackborneb034652009-09-07 00:49:58 -0700806 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700807
808 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700809 public void onServiceConnected(ComponentName name, IBinder service) {
810 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800811 if (mWallpaper.connection == this) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700812 mService = IWallpaperService.Stub.asInterface(service);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800813 attachServiceLocked(this, mWallpaper);
Dianne Hackborneb034652009-09-07 00:49:58 -0700814 // XXX should probably do saveSettingsLocked() later
815 // when we have an engine, but I'm not sure about
816 // locking there and anyway we always need to be able to
817 // recover if there is something wrong.
Christopher Tatedb27b842016-02-25 14:39:17 -0800818 saveSettingsLocked(mWallpaper.userId);
Adrian Roosc3f915e2016-09-06 11:40:53 -0700819 FgThread.getHandler().removeCallbacks(mResetRunnable);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700820 }
821 }
822 }
823
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700824 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700825 public void onServiceDisconnected(ComponentName name) {
826 synchronized (mLock) {
Christopher Tatec349e59f2017-05-05 17:37:43 -0700827 Slog.w(TAG, "Wallpaper service gone: " + name);
828 if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
829 Slog.e(TAG, "Does not match expected wallpaper component "
830 + mWallpaper.wallpaperComponent);
831 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700832 mService = null;
833 mEngine = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800834 if (mWallpaper.connection == this) {
Christopher Tatec349e59f2017-05-05 17:37:43 -0700835 // There is an inherent ordering race between this callback and the
836 // package monitor that receives notice that a package is being updated,
837 // so we cannot quite trust at this moment that we know for sure that
838 // this is not an update. If we think this is a genuine non-update
839 // wallpaper outage, we do our "wait for reset" work as a continuation,
840 // a short time in the future, specifically to allow any pending package
841 // update message on this same looper thread to be processed.
842 if (!mWallpaper.wallpaperUpdating) {
843 mContext.getMainThreadHandler().postDelayed(() -> processDisconnect(this),
844 1000);
845 }
846 }
847 }
848 }
849
850 private void processDisconnect(final ServiceConnection connection) {
851 synchronized (mLock) {
852 // The wallpaper disappeared. If this isn't a system-default one, track
853 // crashes and fall back to default if it continues to misbehave.
854 if (connection == mWallpaper.connection) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700855 final ComponentName wpService = mWallpaper.wallpaperComponent;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800856 if (!mWallpaper.wallpaperUpdating
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700857 && mWallpaper.userId == mCurrentUserId
858 && !Objects.equals(mDefaultWallpaperComponent, wpService)
859 && !Objects.equals(mImageWallpaper, wpService)) {
Selim Cinekebebadb2014-03-05 22:17:26 +0100860 // There is a race condition which causes
861 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is
862 // currently updating since the broadcast notifying us is async.
863 // This race is overcome by the general rule that we only reset the
864 // wallpaper if its service was shut down twice
865 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
866 if (mWallpaper.lastDiedTime != 0
867 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
Christopher Tatec349e59f2017-05-05 17:37:43 -0700868 > SystemClock.uptimeMillis()) {
Selim Cinekebebadb2014-03-05 22:17:26 +0100869 Slog.w(TAG, "Reverting to built-in wallpaper!");
Christopher Tateedf7d042016-03-29 18:24:25 -0700870 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Selim Cinekebebadb2014-03-05 22:17:26 +0100871 } else {
872 mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
Adrian Roosc3f915e2016-09-06 11:40:53 -0700873
874 // If we didn't reset it right away, do so after we couldn't connect to
875 // it for an extended amount of time to avoid having a black wallpaper.
Christopher Tatec349e59f2017-05-05 17:37:43 -0700876 final Handler fgHandler = FgThread.getHandler();
877 fgHandler.removeCallbacks(mResetRunnable);
878 fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700879 if (DEBUG_LIVE) {
880 Slog.i(TAG, "Started wallpaper reconnect timeout for " + wpService);
881 }
Selim Cinekebebadb2014-03-05 22:17:26 +0100882 }
Christopher Tatec349e59f2017-05-05 17:37:43 -0700883 final String flattened = wpService.flattenToString();
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700884 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
Filip Gruszczynski5a589432014-10-14 12:06:06 -0700885 flattened.substring(0, Math.min(flattened.length(),
886 MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700887 }
Christopher Tatec349e59f2017-05-05 17:37:43 -0700888 } else {
889 if (DEBUG_LIVE) {
890 Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring");
891 }
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700892 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700893 }
894 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800895
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700896 /**
897 * Called by a live wallpaper if its colors have changed.
898 * @param primaryColors representation of wallpaper primary colors
899 */
900 @Override
901 public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
902 int which;
903 synchronized (mLock) {
904 // Do not broadcast changes on ImageWallpaper since it's handled
905 // internally by this class.
906 if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
907 return;
908 }
909
910 mWallpaper.primaryColors = primaryColors;
911
912 // Live wallpapers always are system wallpapers.
913 which = FLAG_SYSTEM;
914 // It's also the lock screen wallpaper when we don't have a bitmap in there
Lucas Dupin50ba9912017-07-14 11:55:05 -0700915 WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700916 if (lockedWallpaper == null) {
917 which |= FLAG_LOCK;
918 }
919 }
920 if (which != 0) {
921 notifyWallpaperColorsChanged(mWallpaper, which);
922 }
923 }
924
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700925 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700926 public void attachEngine(IWallpaperEngine engine) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700927 synchronized (mLock) {
928 mEngine = engine;
Michael Wright5203a8b2013-10-03 14:16:42 -0700929 if (mDimensionsChanged) {
930 try {
931 mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
932 } catch (RemoteException e) {
933 Slog.w(TAG, "Failed to set wallpaper dimensions", e);
934 }
935 mDimensionsChanged = false;
936 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700937 if (mPaddingChanged) {
938 try {
939 mEngine.setDisplayPadding(mWallpaper.padding);
940 } catch (RemoteException e) {
941 Slog.w(TAG, "Failed to set wallpaper padding", e);
942 }
943 mPaddingChanged = false;
944 }
Lucas Dupin50ba9912017-07-14 11:55:05 -0700945 try {
946 // This will trigger onComputeColors in the wallpaper engine.
947 // It's fine to be locked in here since the binder is oneway.
948 mEngine.requestWallpaperColors();
949 } catch (RemoteException e) {
950 Slog.w(TAG, "Failed to request wallpaper colors", e);
951 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700952 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700953 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800954
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700955 @Override
956 public void engineShown(IWallpaperEngine engine) {
957 synchronized (mLock) {
958 if (mReply != null) {
959 long ident = Binder.clearCallingIdentity();
960 try {
961 mReply.sendResult(null);
962 } catch (RemoteException e) {
963 Binder.restoreCallingIdentity(ident);
964 }
965 mReply = null;
966 }
967 }
968 }
969
970 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700971 public ParcelFileDescriptor setWallpaper(String name) {
972 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800973 if (mWallpaper.connection == this) {
Christopher Tatead3c2592016-01-20 18:13:17 -0800974 return updateWallpaperBitmapLocked(name, mWallpaper, null);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700975 }
976 return null;
977 }
978 }
979 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800980
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800981 class MyPackageMonitor extends PackageMonitor {
982 @Override
983 public void onPackageUpdateFinished(String packageName, int uid) {
984 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700985 if (mCurrentUserId != getChangingUserId()) {
986 return;
987 }
988 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
989 if (wallpaper != null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700990 final ComponentName wpService = wallpaper.wallpaperComponent;
991 if (wpService != null && wpService.getPackageName().equals(packageName)) {
992 if (DEBUG_LIVE) {
993 Slog.i(TAG, "Wallpaper " + wpService + " update has finished");
994 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800995 wallpaper.wallpaperUpdating = false;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800996 clearWallpaperComponentLocked(wallpaper);
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700997 if (!bindWallpaperComponentLocked(wpService, false, false,
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700998 wallpaper, null)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700999 Slog.w(TAG, "Wallpaper " + wpService
1000 + " no longer available; reverting to default");
Christopher Tateedf7d042016-03-29 18:24:25 -07001001 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001002 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001003 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001004 }
1005 }
1006 }
1007
1008 @Override
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001009 public void onPackageModified(String packageName) {
1010 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001011 if (mCurrentUserId != getChangingUserId()) {
1012 return;
1013 }
1014 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1015 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001016 if (wallpaper.wallpaperComponent == null
1017 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001018 return;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001019 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001020 doPackagesChangedLocked(true, wallpaper);
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001021 }
1022 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001023 }
1024
1025 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001026 public void onPackageUpdateStarted(String packageName, int uid) {
1027 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001028 if (mCurrentUserId != getChangingUserId()) {
1029 return;
1030 }
1031 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1032 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001033 if (wallpaper.wallpaperComponent != null
1034 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001035 if (DEBUG_LIVE) {
1036 Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent
1037 + " is updating");
1038 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001039 wallpaper.wallpaperUpdating = true;
Adrian Roosc3f915e2016-09-06 11:40:53 -07001040 if (wallpaper.connection != null) {
1041 FgThread.getHandler().removeCallbacks(
1042 wallpaper.connection.mResetRunnable);
1043 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001044 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001045 }
1046 }
1047 }
1048
1049 @Override
1050 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001051 synchronized (mLock) {
1052 boolean changed = false;
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001053 if (mCurrentUserId != getChangingUserId()) {
1054 return false;
1055 }
1056 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1057 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001058 boolean res = doPackagesChangedLocked(doit, wallpaper);
1059 changed |= res;
1060 }
1061 return changed;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001062 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001063 }
1064
1065 @Override
1066 public void onSomePackagesChanged() {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001067 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001068 if (mCurrentUserId != getChangingUserId()) {
1069 return;
1070 }
1071 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1072 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001073 doPackagesChangedLocked(true, wallpaper);
1074 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001075 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001076 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001077
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001078 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001079 boolean changed = false;
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001080 if (wallpaper.wallpaperComponent != null) {
1081 int change = isPackageDisappearing(wallpaper.wallpaperComponent
1082 .getPackageName());
1083 if (change == PACKAGE_PERMANENT_CHANGE
1084 || change == PACKAGE_TEMPORARY_CHANGE) {
1085 changed = true;
1086 if (doit) {
1087 Slog.w(TAG, "Wallpaper uninstalled, removing: "
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001088 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001089 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001090 }
1091 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001092 }
1093 if (wallpaper.nextWallpaperComponent != null) {
1094 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
1095 .getPackageName());
1096 if (change == PACKAGE_PERMANENT_CHANGE
1097 || change == PACKAGE_TEMPORARY_CHANGE) {
1098 wallpaper.nextWallpaperComponent = null;
1099 }
1100 }
1101 if (wallpaper.wallpaperComponent != null
1102 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
1103 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001104 mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
1105 PackageManager.MATCH_DIRECT_BOOT_AWARE
1106 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001107 } catch (NameNotFoundException e) {
1108 Slog.w(TAG, "Wallpaper component gone, removing: "
1109 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001110 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001111 }
1112 }
1113 if (wallpaper.nextWallpaperComponent != null
1114 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
1115 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001116 mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
1117 PackageManager.MATCH_DIRECT_BOOT_AWARE
1118 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001119 } catch (NameNotFoundException e) {
1120 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001121 }
1122 }
1123 return changed;
1124 }
1125 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001126
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001127 public WallpaperManagerService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001128 if (DEBUG) Slog.v(TAG, "WallpaperService startup");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 mContext = context;
Christopher Tate762dfd12016-10-10 17:44:48 -07001130 mShuttingDown = false;
Justin Koh29c30162014-09-05 17:10:10 -07001131 mImageWallpaper = ComponentName.unflattenFromString(
1132 context.getResources().getString(R.string.image_wallpaper_component));
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001133 mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001134 mIWindowManager = IWindowManager.Stub.asInterface(
1135 ServiceManager.getService(Context.WINDOW_SERVICE));
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001136 mIPackageManager = AppGlobals.getPackageManager();
Benjamin Franzf3ece362015-02-11 10:51:10 +00001137 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001138 mMonitor = new MyPackageMonitor();
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001139 mMonitor.register(context, null, UserHandle.ALL, true);
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001140 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
Christopher Tatef717b932017-09-11 15:52:54 -07001141
1142 // Initialize state from the persistent store, then guarantee that the
1143 // WallpaperData for the system imagery is instantiated & active, creating
1144 // it from defaults if necessary.
Christopher Tated7faf532016-02-25 12:43:38 -08001145 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatef717b932017-09-11 15:52:54 -07001146 getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);
1147
Lucas Dupin50ba9912017-07-14 11:55:05 -07001148 mColorsChangedListeners = new SparseArray<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001150
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001151 private static File getWallpaperDir(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07001152 return Environment.getUserSystemDirectory(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001153 }
1154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 @Override
1156 protected void finalize() throws Throwable {
1157 super.finalize();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001158 for (int i = 0; i < mWallpaperMap.size(); i++) {
1159 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
1160 wallpaper.wallpaperObserver.stopWatching();
1161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
Amith Yamasani13593602012-03-22 16:16:17 -07001163
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001164 void systemReady() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001165 if (DEBUG) Slog.v(TAG, "systemReady");
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001166 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001167 // If we think we're going to be using the system image wallpaper imagery, make
1168 // sure we have something to render
1169 if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
1170 // No crop file? Make sure we've finished the processing sequence if necessary
1171 if (!wallpaper.cropExists()) {
1172 if (DEBUG) {
1173 Slog.i(TAG, "No crop; regenerating from source");
1174 }
1175 generateCrop(wallpaper);
1176 }
1177 // Still nothing? Fall back to default.
1178 if (!wallpaper.cropExists()) {
1179 if (DEBUG) {
1180 Slog.i(TAG, "Unable to regenerate crop; resetting");
1181 }
Christopher Tateedf7d042016-03-29 18:24:25 -07001182 clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001183 }
1184 } else {
1185 if (DEBUG) {
1186 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
1187 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001188 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001189
Amith Yamasani13593602012-03-22 16:16:17 -07001190 IntentFilter userFilter = new IntentFilter();
Amith Yamasani13593602012-03-22 16:16:17 -07001191 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1192 mContext.registerReceiver(new BroadcastReceiver() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001193 @Override
Amith Yamasani13593602012-03-22 16:16:17 -07001194 public void onReceive(Context context, Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001195 final String action = intent.getAction();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001196 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani756901d2012-10-12 12:30:07 -07001197 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1198 UserHandle.USER_NULL));
Amith Yamasani13593602012-03-22 16:16:17 -07001199 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001200 }
Amith Yamasani13593602012-03-22 16:16:17 -07001201 }, userFilter);
Amith Yamasani756901d2012-10-12 12:30:07 -07001202
Christopher Tate762dfd12016-10-10 17:44:48 -07001203 final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
1204 mContext.registerReceiver(new BroadcastReceiver() {
1205 @Override
1206 public void onReceive(Context context, Intent intent) {
1207 if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
1208 if (DEBUG) {
1209 Slog.i(TAG, "Shutting down");
1210 }
1211 synchronized (mLock) {
1212 mShuttingDown = true;
1213 }
1214 }
1215 }
1216 }, shutdownFilter);
1217
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001218 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001219 ActivityManager.getService().registerUserSwitchObserver(
Sudheer Shanka2c4522c2016-08-27 20:53:28 -07001220 new UserSwitchObserver() {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001221 @Override
1222 public void onUserSwitching(int newUserId, IRemoteCallback reply) {
1223 switchUser(newUserId, reply);
1224 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001225 }, TAG);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001226 } catch (RemoteException e) {
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001227 e.rethrowAsRuntimeException();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001228 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001229 }
1230
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08001231 /** Called by SystemBackupAgent */
1232 public String getName() {
1233 // Verify caller is the system
1234 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
1235 throw new RuntimeException("getName() can only be called from the system process");
1236 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001237 synchronized (mLock) {
1238 return mWallpaperMap.get(0).name;
1239 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001240 }
1241
Christopher Tatebe132e62016-02-10 12:59:49 -08001242 void stopObserver(WallpaperData wallpaper) {
1243 if (wallpaper != null) {
1244 if (wallpaper.wallpaperObserver != null) {
1245 wallpaper.wallpaperObserver.stopWatching();
1246 wallpaper.wallpaperObserver = null;
Amith Yamasani13593602012-03-22 16:16:17 -07001247 }
Amith Yamasani756901d2012-10-12 12:30:07 -07001248 }
1249 }
1250
Christopher Tatebe132e62016-02-10 12:59:49 -08001251 void stopObserversLocked(int userId) {
1252 stopObserver(mWallpaperMap.get(userId));
1253 stopObserver(mLockWallpaperMap.get(userId));
1254 mWallpaperMap.remove(userId);
1255 mLockWallpaperMap.remove(userId);
1256 }
1257
Christopher Tate190e8532016-07-11 11:35:34 -07001258 void onUnlockUser(final int userId) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001259 synchronized (mLock) {
Christopher Tate38a5dc32016-07-20 15:10:18 -07001260 if (mCurrentUserId == userId) {
1261 if (mWaitingForUnlock) {
1262 // If we're switching users, now is when we transition the wallpaper
1263 switchUser(userId, null);
1264 }
Christopher Tate190e8532016-07-11 11:35:34 -07001265
1266 // Make sure that the SELinux labeling of all the relevant files is correct.
1267 // This corrects for mislabeling bugs that might have arisen from move-to
1268 // operations involving the wallpaper files. This isn't timing-critical,
1269 // so we do it in the background to avoid holding up the user unlock operation.
Christopher Tate38a5dc32016-07-20 15:10:18 -07001270 if (mUserRestorecon.get(userId) != Boolean.TRUE) {
1271 mUserRestorecon.put(userId, Boolean.TRUE);
1272 Runnable relabeler = new Runnable() {
1273 @Override
1274 public void run() {
1275 final File wallpaperDir = getWallpaperDir(userId);
1276 for (String filename : sPerUserFiles) {
1277 File f = new File(wallpaperDir, filename);
1278 if (f.exists()) {
1279 SELinux.restorecon(f);
1280 }
Christopher Tate190e8532016-07-11 11:35:34 -07001281 }
1282 }
Christopher Tate38a5dc32016-07-20 15:10:18 -07001283 };
1284 BackgroundThread.getHandler().post(relabeler);
1285 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001286 }
1287 }
1288 }
1289
Amith Yamasani756901d2012-10-12 12:30:07 -07001290 void onRemoveUser(int userId) {
1291 if (userId < 1) return;
Christopher Tatebe132e62016-02-10 12:59:49 -08001292
1293 final File wallpaperDir = getWallpaperDir(userId);
Amith Yamasani756901d2012-10-12 12:30:07 -07001294 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001295 stopObserversLocked(userId);
1296 for (String filename : sPerUserFiles) {
1297 new File(wallpaperDir, filename).delete();
1298 }
Sudheer Shanka69f0cb52016-10-06 17:33:20 -07001299 mUserRestorecon.remove(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001300 }
1301 }
1302
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001303 void switchUser(int userId, IRemoteCallback reply) {
Lucas Dupin9272d452017-09-14 14:15:42 -07001304 final WallpaperData systemWallpaper;
1305 final WallpaperData lockWallpaper;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001306 synchronized (mLock) {
1307 mCurrentUserId = userId;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001308 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Lucas Dupin9272d452017-09-14 14:15:42 -07001309 final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
1310 lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001311 // Not started watching yet, in case wallpaper data was loaded for other reasons.
1312 if (systemWallpaper.wallpaperObserver == null) {
1313 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
1314 systemWallpaper.wallpaperObserver.startWatching();
1315 }
1316 switchWallpaper(systemWallpaper, reply);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001317 }
Lucas Dupin9272d452017-09-14 14:15:42 -07001318
1319 // Offload color extraction to another thread since switchUser will be called
1320 // from the main thread.
1321 FgThread.getHandler().post(() -> {
1322 notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
1323 notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
1324 });
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001325 }
1326
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001327 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001328 synchronized (mLock) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001329 mWaitingForUnlock = false;
1330 final ComponentName cname = wallpaper.wallpaperComponent != null ?
1331 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
1332 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
1333 // We failed to bind the desired wallpaper, but that might
1334 // happen if the wallpaper isn't direct-boot aware
1335 ServiceInfo si = null;
1336 try {
1337 si = mIPackageManager.getServiceInfo(cname,
1338 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
1339 } catch (RemoteException ignored) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001340 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001341
1342 if (si == null) {
1343 Slog.w(TAG, "Failure starting previous wallpaper; clearing");
1344 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
1345 } else {
1346 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
1347 // We might end up persisting the current wallpaper data
1348 // while locked, so pretend like the component was actually
1349 // bound into place
1350 wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
1351 final WallpaperData fallback = new WallpaperData(wallpaper.userId,
1352 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
Adrian Roosc28e3a92016-04-14 10:47:52 -07001353 ensureSaneWallpaperData(fallback);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001354 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
1355 mWaitingForUnlock = true;
1356 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001357 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001358 }
1359 }
1360
Christopher Tatebe132e62016-02-10 12:59:49 -08001361 @Override
1362 public void clearWallpaper(String callingPackage, int which, int userId) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001363 if (DEBUG) Slog.v(TAG, "clearWallpaper");
Benjamin Franzf3ece362015-02-11 10:51:10 +00001364 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tate98d609c2016-05-18 17:31:58 -07001365 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001366 return;
1367 }
Christopher Tatee409f0e2016-03-21 14:53:15 -07001368 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1369 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001370
Lucas Dupin41f69422017-05-03 15:26:22 -07001371 WallpaperData data = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001372 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001373 clearWallpaperLocked(false, which, userId, null);
Lucas Dupin41f69422017-05-03 15:26:22 -07001374
1375 if (which == FLAG_LOCK) {
1376 data = mLockWallpaperMap.get(userId);
1377 }
1378 if (which == FLAG_SYSTEM || data == null) {
1379 data = mWallpaperMap.get(userId);
1380 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001381 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001382
1383 // When clearing a wallpaper, broadcast new valid colors
Lucas Dupin41f69422017-05-03 15:26:22 -07001384 if (data != null) {
1385 notifyWallpaperColorsChanged(data, which);
1386 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001387 }
1388
Christopher Tatebe132e62016-02-10 12:59:49 -08001389 void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
Christopher Tateedf7d042016-03-29 18:24:25 -07001390 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001391 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1392 }
1393
1394 WallpaperData wallpaper = null;
Christopher Tateedf7d042016-03-29 18:24:25 -07001395 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001396 wallpaper = mLockWallpaperMap.get(userId);
1397 if (wallpaper == null) {
1398 // It's already gone; we're done.
Christopher Tate79a24572016-03-02 14:42:44 -08001399 if (DEBUG) {
1400 Slog.i(TAG, "Lock wallpaper already cleared");
1401 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001402 return;
1403 }
1404 } else {
1405 wallpaper = mWallpaperMap.get(userId);
1406 if (wallpaper == null) {
1407 // Might need to bring it in the first time to establish our rewrite
Christopher Tated7faf532016-02-25 12:43:38 -08001408 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08001409 wallpaper = mWallpaperMap.get(userId);
1410 }
1411 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001412 if (wallpaper == null) {
1413 return;
1414 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001415
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001416 final long ident = Binder.clearCallingIdentity();
1417 try {
Christopher Tatebe132e62016-02-10 12:59:49 -08001418 if (wallpaper.wallpaperFile.exists()) {
1419 wallpaper.wallpaperFile.delete();
1420 wallpaper.cropFile.delete();
Christopher Tateedf7d042016-03-29 18:24:25 -07001421 if (which == FLAG_LOCK) {
Christopher Tate79a24572016-03-02 14:42:44 -08001422 mLockWallpaperMap.remove(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001423 final IWallpaperManagerCallback cb = mKeyguardListener;
1424 if (cb != null) {
Christopher Tate79a24572016-03-02 14:42:44 -08001425 if (DEBUG) {
1426 Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
1427 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001428 try {
1429 cb.onWallpaperChanged();
1430 } catch (RemoteException e) {
1431 // Oh well it went away; no big deal
1432 }
1433 }
Christopher Tate79a24572016-03-02 14:42:44 -08001434 saveSettingsLocked(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001435 return;
1436 }
1437 }
1438
Christopher Tateecd827a2014-09-05 17:42:34 -07001439 RuntimeException e = null;
1440 try {
Lucas Dupin75ec3792017-06-29 14:07:18 -07001441 wallpaper.primaryColors = null;
Christopher Tateecd827a2014-09-05 17:42:34 -07001442 wallpaper.imageWallpaperPending = false;
1443 if (userId != mCurrentUserId) return;
1444 if (bindWallpaperComponentLocked(defaultFailed
1445 ? mImageWallpaper
1446 : null, true, false, wallpaper, reply)) {
1447 return;
1448 }
1449 } catch (IllegalArgumentException e1) {
1450 e = e1;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001451 }
Christopher Tateecd827a2014-09-05 17:42:34 -07001452
1453 // This can happen if the default wallpaper component doesn't
1454 // exist. This should be a system configuration problem, but
1455 // let's not let it crash the system and just live with no
1456 // wallpaper.
1457 Slog.e(TAG, "Default wallpaper component not found!", e);
1458 clearWallpaperComponentLocked(wallpaper);
1459 if (reply != null) {
1460 try {
1461 reply.sendResult(null);
1462 } catch (RemoteException e1) {
1463 }
1464 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001465 } finally {
1466 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001468 }
1469
1470 public boolean hasNamedWallpaper(String name) {
1471 synchronized (mLock) {
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001472 List<UserInfo> users;
1473 long ident = Binder.clearCallingIdentity();
1474 try {
1475 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
1476 } finally {
1477 Binder.restoreCallingIdentity(ident);
1478 }
1479 for (UserInfo user: users) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001480 // ignore managed profiles
1481 if (user.isManagedProfile()) {
1482 continue;
1483 }
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001484 WallpaperData wd = mWallpaperMap.get(user.id);
1485 if (wd == null) {
1486 // User hasn't started yet, so load her settings to peek at the wallpaper
Christopher Tated7faf532016-02-25 12:43:38 -08001487 loadSettingsLocked(user.id, false);
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001488 wd = mWallpaperMap.get(user.id);
1489 }
1490 if (wd != null && name.equals(wd.name)) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001491 return true;
1492 }
1493 }
1494 }
1495 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 }
1497
John Spurlock41f64642013-11-04 13:48:38 -05001498 private Point getDefaultDisplaySize() {
1499 Point p = new Point();
John Spurlockd6e836c2013-11-18 14:14:49 -05001500 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1501 Display d = wm.getDefaultDisplay();
1502 d.getRealSize(p);
John Spurlock41f64642013-11-04 13:48:38 -05001503 return p;
1504 }
1505
Benjamin Franzf3ece362015-02-11 10:51:10 +00001506 public void setDimensionHints(int width, int height, String callingPackage)
1507 throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001509 if (!isWallpaperSupported(callingPackage)) {
1510 return;
1511 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001512 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001513 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001514 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001515 if (width <= 0 || height <= 0) {
1516 throw new IllegalArgumentException("width and height must be > 0");
1517 }
John Spurlock41f64642013-11-04 13:48:38 -05001518 // Make sure it is at least as large as the display.
1519 Point displaySize = getDefaultDisplaySize();
1520 width = Math.max(width, displaySize.x);
1521 height = Math.max(height, displaySize.y);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001522
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001523 if (width != wallpaper.width || height != wallpaper.height) {
1524 wallpaper.width = width;
1525 wallpaper.height = height;
Christopher Tatedb27b842016-02-25 14:39:17 -08001526 saveSettingsLocked(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001527 if (mCurrentUserId != userId) return; // Don't change the properties now
1528 if (wallpaper.connection != null) {
1529 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001530 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001531 wallpaper.connection.mEngine.setDesiredSize(
Dianne Hackborn284ac932009-08-28 10:34:25 -07001532 width, height);
1533 } catch (RemoteException e) {
1534 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001535 notifyCallbacksLocked(wallpaper);
Michael Wright5203a8b2013-10-03 14:16:42 -07001536 } else if (wallpaper.connection.mService != null) {
1537 // We've attached to the service but the engine hasn't attached back to us
1538 // yet. This means it will be created with the previous dimensions, so we
1539 // need to update it to the new dimensions once it attaches.
1540 wallpaper.connection.mDimensionsChanged = true;
Dianne Hackborn284ac932009-08-28 10:34:25 -07001541 }
1542 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 }
1545 }
1546
1547 public int getWidthHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001548 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001549 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001550 if (wallpaper != null) {
1551 return wallpaper.width;
1552 } else {
1553 return 0;
1554 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 }
1557
1558 public int getHeightHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001559 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001560 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001561 if (wallpaper != null) {
1562 return wallpaper.height;
1563 } else {
1564 return 0;
1565 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 }
1568
Benjamin Franzf3ece362015-02-11 10:51:10 +00001569 public void setDisplayPadding(Rect padding, String callingPackage) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001570 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001571 if (!isWallpaperSupported(callingPackage)) {
1572 return;
1573 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001574 synchronized (mLock) {
1575 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001576 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001577 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
1578 throw new IllegalArgumentException("padding must be positive: " + padding);
1579 }
1580
1581 if (!padding.equals(wallpaper.padding)) {
1582 wallpaper.padding.set(padding);
Christopher Tatedb27b842016-02-25 14:39:17 -08001583 saveSettingsLocked(userId);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001584 if (mCurrentUserId != userId) return; // Don't change the properties now
1585 if (wallpaper.connection != null) {
1586 if (wallpaper.connection.mEngine != null) {
1587 try {
1588 wallpaper.connection.mEngine.setDisplayPadding(padding);
1589 } catch (RemoteException e) {
1590 }
1591 notifyCallbacksLocked(wallpaper);
1592 } else if (wallpaper.connection.mService != null) {
1593 // We've attached to the service but the engine hasn't attached back to us
1594 // yet. This means it will be created with the previous dimensions, so we
1595 // need to update it to the new dimensions once it attaches.
1596 wallpaper.connection.mPaddingChanged = true;
1597 }
1598 }
1599 }
1600 }
1601 }
1602
Christopher Tate93252de2017-06-15 14:48:41 -07001603 private void enforceCallingOrSelfPermissionAndAppOp(String permission, final String callingPkg,
1604 final int callingUid, String message) {
1605 mContext.enforceCallingOrSelfPermission(permission, message);
1606
1607 final String opName = AppOpsManager.permissionToOp(permission);
1608 if (opName != null) {
1609 final int appOpMode = mAppOpsManager.noteOp(opName, callingUid, callingPkg);
1610 if (appOpMode != AppOpsManager.MODE_ALLOWED) {
1611 throw new SecurityException(
1612 message + ": " + callingPkg + " is not allowed to " + permission);
1613 }
1614 }
1615 }
1616
Yorke Leedcd93cc2016-01-08 14:12:55 -08001617 @Override
Christopher Tate93252de2017-06-15 14:48:41 -07001618 public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
1619 final int which, Bundle outParams, int wallpaperUserId) {
Christopher Tate8a71c482017-08-14 16:45:03 -07001620 final int hasPrivilege = mContext.checkCallingOrSelfPermission(
1621 android.Manifest.permission.READ_WALLPAPER_INTERNAL);
1622 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
1623 enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
1624 callingPkg, Binder.getCallingUid(), "read wallpaper");
1625 }
Christopher Tate93252de2017-06-15 14:48:41 -07001626
Christopher Tatee409f0e2016-03-21 14:53:15 -07001627 wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1628 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001629
Christopher Tateedf7d042016-03-29 18:24:25 -07001630 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001631 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1632 }
1633
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001634 synchronized (mLock) {
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001635 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07001636 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001637 WallpaperData wallpaper = whichSet.get(wallpaperUserId);
1638 if (wallpaper == null) {
Christopher Tatef717b932017-09-11 15:52:54 -07001639 // There is no established wallpaper imagery of this type (expected
1640 // only for lock wallpapers; a system WallpaperData is established at
1641 // user switch)
1642 return null;
Benjamin Franzf3ece362015-02-11 10:51:10 +00001643 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001644 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001645 if (outParams != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001646 outParams.putInt("width", wallpaper.width);
1647 outParams.putInt("height", wallpaper.height);
Dianne Hackborn284ac932009-08-28 10:34:25 -07001648 }
Christopher Tateea6724a2016-02-18 18:39:19 -08001649 if (cb != null) {
1650 wallpaper.callbacks.register(cb);
1651 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001652 if (!wallpaper.cropFile.exists()) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001653 return null;
1654 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001655 return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001656 } catch (FileNotFoundException e) {
1657 /* Shouldn't happen as we check to see if the file exists */
Joe Onorato8a9b2202010-02-26 18:56:32 -08001658 Slog.w(TAG, "Error getting wallpaper", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001660 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 }
1663
Christopher Tatee409f0e2016-03-21 14:53:15 -07001664 @Override
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001665 public WallpaperInfo getWallpaperInfo(int userId) {
1666 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Christopher Tatef717b932017-09-11 15:52:54 -07001667 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null);
Dianne Hackborneb034652009-09-07 00:49:58 -07001668 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001669 WallpaperData wallpaper = mWallpaperMap.get(userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001670 if (wallpaper != null && wallpaper.connection != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001671 return wallpaper.connection.mInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -07001672 }
1673 return null;
1674 }
1675 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001676
Christopher Tatead3c2592016-01-20 18:13:17 -08001677 @Override
Christopher Tatee409f0e2016-03-21 14:53:15 -07001678 public int getWallpaperIdForUser(int which, int userId) {
1679 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1680 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
1681
Christopher Tateedf7d042016-03-29 18:24:25 -07001682 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001683 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
1684 }
1685
1686 final SparseArray<WallpaperData> map =
Christopher Tateedf7d042016-03-29 18:24:25 -07001687 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatee409f0e2016-03-21 14:53:15 -07001688 synchronized (mLock) {
1689 WallpaperData wallpaper = map.get(userId);
1690 if (wallpaper != null) {
1691 return wallpaper.wallpaperId;
1692 }
1693 }
1694 return -1;
1695 }
1696
1697 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001698 public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
1699 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1700 userId, true, true, "registerWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001701 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001702 RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
1703 mColorsChangedListeners.get(userId);
1704 if (userColorsChangedListeners == null) {
1705 userColorsChangedListeners = new RemoteCallbackList<>();
1706 mColorsChangedListeners.put(userId, userColorsChangedListeners);
1707 }
1708 userColorsChangedListeners.register(cb);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001709 }
1710 }
1711
1712 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001713 public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
1714 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1715 userId, true, true, "unregisterWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001716 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001717 final RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
1718 mColorsChangedListeners.get(userId);
1719 if (userColorsChangedListeners != null) {
1720 userColorsChangedListeners.unregister(cb);
1721 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001722 }
1723 }
1724
1725 @Override
Christopher Tatebe132e62016-02-10 12:59:49 -08001726 public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
1727 checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
1728 synchronized (mLock) {
1729 mKeyguardListener = cb;
1730 }
1731 return true;
1732 }
1733
1734 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001735 public WallpaperColors getWallpaperColors(int which, int userId) throws RemoteException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001736 if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
1737 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
1738 }
Lucas Dupin50ba9912017-07-14 11:55:05 -07001739 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1740 userId, false, true, "getWallpaperColors", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001741
1742 WallpaperData wallpaperData = null;
1743 boolean shouldExtract;
1744
1745 synchronized (mLock) {
1746 if (which == FLAG_LOCK) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001747 wallpaperData = mLockWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001748 }
1749
1750 // Try to get the system wallpaper anyway since it might
1751 // also be the lock screen wallpaper
1752 if (wallpaperData == null) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001753 wallpaperData = mWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001754 }
1755
1756 if (wallpaperData == null) {
1757 return null;
1758 }
1759 shouldExtract = wallpaperData.primaryColors == null;
1760 }
1761
1762 if (shouldExtract) {
1763 extractColors(wallpaperData);
1764 }
1765
1766 synchronized (mLock) {
1767 return wallpaperData.primaryColors;
1768 }
1769 }
1770
1771 @Override
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001772 public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Christopher Tated7faf532016-02-25 12:43:38 -08001773 Rect cropHint, boolean allowBackup, Bundle extras, int which,
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001774 IWallpaperManagerCallback completion, int userId) {
1775 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
1776 false /* all */, true /* full */, "changing wallpaper", null /* pkg */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tatead3c2592016-01-20 18:13:17 -08001778
Christopher Tateedf7d042016-03-29 18:24:25 -07001779 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001780 final String msg = "Must specify a valid wallpaper category to set";
1781 Slog.e(TAG, msg);
1782 throw new IllegalArgumentException(msg);
Christopher Tatead3c2592016-01-20 18:13:17 -08001783 }
1784
Christopher Tate98d609c2016-05-18 17:31:58 -07001785 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001786 return null;
1787 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001788
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001789 // "null" means the no-op crop, preserving the full input image
1790 if (cropHint == null) {
1791 cropHint = new Rect(0, 0, 0, 0);
1792 } else {
1793 if (cropHint.isEmpty()
1794 || cropHint.left < 0
1795 || cropHint.top < 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001796 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001797 }
1798 }
1799
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001800 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001801 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
1802 WallpaperData wallpaper;
1803
Christopher Tate8347b632016-04-29 18:59:18 -07001804 /* If we're setting system but not lock, and lock is currently sharing the system
1805 * wallpaper, we need to migrate that image over to being lock-only before
1806 * the caller here writes new bitmap data.
1807 */
1808 if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
1809 if (DEBUG) {
1810 Slog.i(TAG, "Migrating system->lock to preserve");
1811 }
1812 migrateSystemToLockWallpaperLocked(userId);
1813 }
1814
Christopher Tatebe132e62016-02-10 12:59:49 -08001815 wallpaper = getWallpaperSafeLocked(userId, which);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001816 final long ident = Binder.clearCallingIdentity();
1817 try {
Christopher Tatead3c2592016-01-20 18:13:17 -08001818 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001819 if (pfd != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001820 wallpaper.imageWallpaperPending = true;
Christopher Tatebe132e62016-02-10 12:59:49 -08001821 wallpaper.whichPending = which;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001822 wallpaper.setComplete = completion;
1823 wallpaper.cropHint.set(cropHint);
Christopher Tatec613c632016-08-12 14:13:02 -07001824 wallpaper.allowBackup = allowBackup;
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001825 }
1826 return pfd;
1827 } finally {
1828 Binder.restoreCallingIdentity(ident);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831 }
1832
Christopher Tate8347b632016-04-29 18:59:18 -07001833 private void migrateSystemToLockWallpaperLocked(int userId) {
1834 WallpaperData sysWP = mWallpaperMap.get(userId);
1835 if (sysWP == null) {
1836 if (DEBUG) {
1837 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
1838 }
1839 return;
1840 }
1841
1842 // We know a-priori that there is no lock-only wallpaper currently
1843 WallpaperData lockWP = new WallpaperData(userId,
1844 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
1845 lockWP.wallpaperId = sysWP.wallpaperId;
1846 lockWP.cropHint.set(sysWP.cropHint);
1847 lockWP.width = sysWP.width;
1848 lockWP.height = sysWP.height;
Christopher Tateedd8dc82016-10-12 15:17:58 -07001849 lockWP.allowBackup = sysWP.allowBackup;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001850 lockWP.primaryColors = sysWP.primaryColors;
Christopher Tate8347b632016-04-29 18:59:18 -07001851
1852 // Migrate the bitmap files outright; no need to copy
1853 try {
1854 Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
1855 Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
1856 } catch (ErrnoException e) {
1857 Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
1858 lockWP.wallpaperFile.delete();
1859 lockWP.cropFile.delete();
1860 return;
1861 }
1862
1863 mLockWallpaperMap.put(userId, lockWP);
1864 }
1865
Christopher Tatead3c2592016-01-20 18:13:17 -08001866 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
1867 Bundle extras) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001868 if (name == null) name = "";
1869 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001870 File dir = getWallpaperDir(wallpaper.userId);
1871 if (!dir.exists()) {
1872 dir.mkdir();
Dianne Hackbornebac48c2011-11-29 18:01:50 -08001873 FileUtils.setPermissions(
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001874 dir.getPath(),
Dianne Hackbornebac48c2011-11-29 18:01:50 -08001875 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1876 -1, -1);
1877 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001878 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
Christopher Tate90f86ba2014-09-11 12:37:19 -07001879 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
Christopher Tatebe132e62016-02-10 12:59:49 -08001880 if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
rpcraig554cb0c2012-07-05 06:41:43 -04001881 return null;
1882 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001883 wallpaper.name = name;
Christopher Tatead3c2592016-01-20 18:13:17 -08001884 wallpaper.wallpaperId = makeWallpaperIdLocked();
1885 if (extras != null) {
1886 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
1887 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001888 // Nullify field to require new computation
1889 wallpaper.primaryColors = null;
Christopher Tatead3c2592016-01-20 18:13:17 -08001890 if (DEBUG) {
1891 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
Christopher Tatebe132e62016-02-10 12:59:49 -08001892 + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
Christopher Tatead3c2592016-01-20 18:13:17 -08001893 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001894 return fd;
1895 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001896 Slog.w(TAG, "Error setting wallpaper", e);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001897 }
1898 return null;
1899 }
1900
Christopher Tated57d17c2016-03-25 13:41:46 -07001901 @Override
Adrian Roos40ea0832016-07-14 14:19:55 -07001902 public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
1903 int userId) {
1904
Christopher Tate98d609c2016-05-18 17:31:58 -07001905 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001906 setWallpaperComponent(name, userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001907 }
1908 }
1909
1910 // ToDo: Remove this version of the function
Christopher Tated57d17c2016-03-25 13:41:46 -07001911 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001912 public void setWallpaperComponent(ComponentName name) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001913 setWallpaperComponent(name, UserHandle.getCallingUserId());
1914 }
1915
1916 private void setWallpaperComponent(ComponentName name, int userId) {
1917 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
1918 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001919 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
Adrian Roos40ea0832016-07-14 14:19:55 -07001920
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001921 int which = FLAG_SYSTEM;
1922 boolean shouldNotifyColors = false;
1923 WallpaperData wallpaper;
1924
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001925 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001926 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001927 wallpaper = mWallpaperMap.get(userId);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001928 if (wallpaper == null) {
1929 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
1930 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001931 final long ident = Binder.clearCallingIdentity();
Christopher Tate7cd00102016-12-19 14:38:44 -08001932
1933 // Live wallpapers can't be specified for keyguard. If we're using a static
1934 // system+lock image currently, migrate the system wallpaper to be a lock-only
1935 // image as part of making a different live component active as the system
1936 // wallpaper.
1937 if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
1938 if (mLockWallpaperMap.get(userId) == null) {
1939 // We're using the static imagery and there is no lock-specific image in place,
1940 // therefore it's a shared system+lock image that we need to migrate.
1941 migrateSystemToLockWallpaperLocked(userId);
1942 }
1943 }
1944
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001945 // New live wallpaper is also a lock wallpaper if nothing is set
1946 if (mLockWallpaperMap.get(userId) == null) {
1947 which |= FLAG_LOCK;
1948 }
1949
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001950 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001951 wallpaper.imageWallpaperPending = false;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001952 boolean same = changingToSame(name, wallpaper);
Christopher Tated57d17c2016-03-25 13:41:46 -07001953 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001954 if (!same) {
1955 wallpaper.primaryColors = null;
1956 }
Christopher Tated57d17c2016-03-25 13:41:46 -07001957 wallpaper.wallpaperId = makeWallpaperIdLocked();
Sunny Goyal0572e182016-03-31 11:05:51 -07001958 notifyCallbacksLocked(wallpaper);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001959 shouldNotifyColors = true;
Christopher Tated57d17c2016-03-25 13:41:46 -07001960 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001961 } finally {
1962 Binder.restoreCallingIdentity(ident);
1963 }
1964 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001965
1966 if (shouldNotifyColors) {
1967 notifyWallpaperColorsChanged(wallpaper, which);
1968 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001969 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001970
Lucas Dupin50ba9912017-07-14 11:55:05 -07001971 private boolean changingToSame(ComponentName componentName, WallpaperData wallpaper) {
1972 if (wallpaper.connection != null) {
1973 if (wallpaper.wallpaperComponent == null) {
1974 if (componentName == null) {
1975 if (DEBUG) Slog.v(TAG, "changingToSame: still using default");
1976 // Still using default wallpaper.
1977 return true;
1978 }
1979 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
1980 // Changing to same wallpaper.
1981 if (DEBUG) Slog.v(TAG, "same wallpaper");
1982 return true;
1983 }
1984 }
1985 return false;
1986 }
1987
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001988 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001989 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001990 if (DEBUG_LIVE) {
1991 Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
1992 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001993 // Has the component changed?
Lucas Dupin50ba9912017-07-14 11:55:05 -07001994 if (!force && changingToSame(componentName, wallpaper)) {
1995 return true;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001996 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001997
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001998 try {
Mike Clerona428b2c2009-11-15 22:53:08 -08001999 if (componentName == null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002000 componentName = mDefaultWallpaperComponent;
Mike Clerona428b2c2009-11-15 22:53:08 -08002001 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -08002002 // Fall back to static image wallpaper
Justin Koh29c30162014-09-05 17:10:10 -07002003 componentName = mImageWallpaper;
Mike Cleron322b6ee2009-11-12 07:45:47 -08002004 //clearWallpaperComponentLocked();
2005 //return;
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002006 if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper");
Mike Cleron322b6ee2009-11-12 07:45:47 -08002007 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002008 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002009 int serviceUserId = wallpaper.userId;
2010 ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
2011 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
Christopher Tate90952202013-09-08 13:01:28 -07002012 if (si == null) {
2013 // The wallpaper component we're trying to use doesn't exist
2014 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
2015 return false;
2016 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002017 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002018 String msg = "Selected service does not require "
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002019 + android.Manifest.permission.BIND_WALLPAPER
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002020 + ": " + componentName;
2021 if (fromUser) {
2022 throw new SecurityException(msg);
2023 }
2024 Slog.w(TAG, msg);
2025 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002026 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002027
Dianne Hackborneb034652009-09-07 00:49:58 -07002028 WallpaperInfo wi = null;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002029
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002030 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
Justin Koh29c30162014-09-05 17:10:10 -07002031 if (componentName != null && !componentName.equals(mImageWallpaper)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002032 // Make sure the selected service is actually a wallpaper service.
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002033 List<ResolveInfo> ris =
2034 mIPackageManager.queryIntentServices(intent,
2035 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
Jeff Sharkeyd5896632016-03-04 16:16:00 -07002036 PackageManager.GET_META_DATA, serviceUserId).getList();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002037 for (int i=0; i<ris.size(); i++) {
2038 ServiceInfo rsi = ris.get(i).serviceInfo;
2039 if (rsi.name.equals(si.name) &&
2040 rsi.packageName.equals(si.packageName)) {
Dianne Hackborneb034652009-09-07 00:49:58 -07002041 try {
2042 wi = new WallpaperInfo(mContext, ris.get(i));
2043 } catch (XmlPullParserException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002044 if (fromUser) {
2045 throw new IllegalArgumentException(e);
2046 }
2047 Slog.w(TAG, e);
2048 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002049 } catch (IOException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002050 if (fromUser) {
2051 throw new IllegalArgumentException(e);
2052 }
2053 Slog.w(TAG, e);
2054 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002055 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002056 break;
2057 }
2058 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002059 if (wi == null) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002060 String msg = "Selected service is not a wallpaper: "
2061 + componentName;
2062 if (fromUser) {
2063 throw new SecurityException(msg);
2064 }
2065 Slog.w(TAG, msg);
2066 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002067 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002068 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002069
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002070 // Bind the service!
Joe Onorato8a9b2202010-02-26 18:56:32 -08002071 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002072 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002073 intent.setComponent(componentName);
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002074 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2075 com.android.internal.R.string.wallpaper_binding_label);
Dianne Hackborn41203752012-08-31 14:05:51 -07002076 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
Dianne Hackborneb034652009-09-07 00:49:58 -07002077 mContext, 0,
2078 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
2079 mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
Dianne Hackborn41203752012-08-31 14:05:51 -07002080 0, null, new UserHandle(serviceUserId)));
Dianne Hackbornc8230512013-07-13 21:32:12 -07002081 if (!mContext.bindServiceAsUser(intent, newConn,
Dianne Hackbornd69e4c12015-04-24 09:54:54 -07002082 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
2083 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
Amith Yamasani27b89e62013-01-16 12:30:11 -08002084 new UserHandle(serviceUserId))) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002085 String msg = "Unable to bind service: "
2086 + componentName;
2087 if (fromUser) {
2088 throw new IllegalArgumentException(msg);
2089 }
2090 Slog.w(TAG, msg);
2091 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002092 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002093 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
2094 detachWallpaperLocked(mLastWallpaper);
2095 }
2096 wallpaper.wallpaperComponent = componentName;
2097 wallpaper.connection = newConn;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002098 newConn.mReply = reply;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002099 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002100 if (wallpaper.userId == mCurrentUserId) {
2101 if (DEBUG)
2102 Slog.v(TAG, "Adding window token: " + newConn.mToken);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002103 mIWindowManager.addWindowToken(newConn.mToken, TYPE_WALLPAPER, DEFAULT_DISPLAY);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002104 mLastWallpaper = wallpaper;
2105 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002106 } catch (RemoteException e) {
2107 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002108 } catch (RemoteException e) {
2109 String msg = "Remote exception for " + componentName + "\n" + e;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002110 if (fromUser) {
2111 throw new IllegalArgumentException(msg);
2112 }
2113 Slog.w(TAG, msg);
2114 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002115 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002116 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002117 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002118
2119 void detachWallpaperLocked(WallpaperData wallpaper) {
2120 if (wallpaper.connection != null) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002121 if (wallpaper.connection.mReply != null) {
2122 try {
2123 wallpaper.connection.mReply.sendResult(null);
2124 } catch (RemoteException e) {
2125 }
2126 wallpaper.connection.mReply = null;
2127 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002128 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002129 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002130 wallpaper.connection.mEngine.destroy();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002131 } catch (RemoteException e) {
2132 }
2133 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002134 mContext.unbindService(wallpaper.connection);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07002135 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002136 if (DEBUG)
2137 Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002138 mIWindowManager.removeWindowToken(wallpaper.connection.mToken, DEFAULT_DISPLAY);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07002139 } catch (RemoteException e) {
2140 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002141 wallpaper.connection.mService = null;
2142 wallpaper.connection.mEngine = null;
2143 wallpaper.connection = null;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002144 }
2145 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002146
2147 void clearWallpaperComponentLocked(WallpaperData wallpaper) {
2148 wallpaper.wallpaperComponent = null;
2149 detachWallpaperLocked(wallpaper);
2150 }
2151
2152 void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002153 try {
Dianne Hackborn3be63c02009-08-20 19:31:38 -07002154 conn.mService.attach(conn, conn.mToken,
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002155 TYPE_WALLPAPER, false,
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002156 wallpaper.width, wallpaper.height, wallpaper.padding);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002157 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002158 Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002159 if (!wallpaper.wallpaperUpdating) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002160 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08002161 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002162 }
2163 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002164
2165 private void notifyCallbacksLocked(WallpaperData wallpaper) {
2166 final int n = wallpaper.callbacks.beginBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 for (int i = 0; i < n; i++) {
2168 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002169 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 } catch (RemoteException e) {
2171
2172 // The RemoteCallbackList will take care of removing
2173 // the dead object for us.
2174 }
2175 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002176 wallpaper.callbacks.finishBroadcast();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002178 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002179 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002180 }
2181
2182 private void checkPermission(String permission) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002183 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
2185 + ", must have permission " + permission);
2186 }
2187 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002188
Benjamin Franzf3ece362015-02-11 10:51:10 +00002189 /**
2190 * Certain user types do not support wallpapers (e.g. managed profiles). The check is
2191 * implemented through through the OP_WRITE_WALLPAPER AppOp.
2192 */
2193 public boolean isWallpaperSupported(String callingPackage) {
2194 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
2195 callingPackage) == AppOpsManager.MODE_ALLOWED;
2196 }
2197
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002198 @Override
Christopher Tate98d609c2016-05-18 17:31:58 -07002199 public boolean isSetWallpaperAllowed(String callingPackage) {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002200 final PackageManager pm = mContext.getPackageManager();
2201 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
2202 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
2203 if (!uidMatchPackage) {
2204 return false; // callingPackage was faked.
2205 }
2206
2207 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
2208 if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
2209 return true;
2210 }
2211 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
2212 return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
2213 }
2214
Christopher Tated7faf532016-02-25 12:43:38 -08002215 @Override
Christopher Tate61722662016-08-10 16:13:14 -07002216 public boolean isWallpaperBackupEligible(int which, int userId) {
Christopher Tated7faf532016-02-25 12:43:38 -08002217 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
2218 throw new SecurityException("Only the system may call isWallpaperBackupEligible");
2219 }
2220
Christopher Tate61722662016-08-10 16:13:14 -07002221 WallpaperData wallpaper = (which == FLAG_LOCK)
Christopher Tatef7d1b5d2016-08-19 11:21:07 -07002222 ? mLockWallpaperMap.get(userId)
2223 : mWallpaperMap.get(userId);
Christopher Tated7faf532016-02-25 12:43:38 -08002224 return (wallpaper != null) ? wallpaper.allowBackup : false;
2225 }
2226
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002227 private static JournaledFile makeJournaledFile(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07002228 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002229 return new JournaledFile(new File(base), new File(base + ".tmp"));
2230 }
2231
Christopher Tatedb27b842016-02-25 14:39:17 -08002232 private void saveSettingsLocked(int userId) {
2233 JournaledFile journal = makeJournaledFile(userId);
2234 FileOutputStream fstream = null;
2235 BufferedOutputStream stream = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002236 try {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002237 XmlSerializer out = new FastXmlSerializer();
Christopher Tatedb27b842016-02-25 14:39:17 -08002238 fstream = new FileOutputStream(journal.chooseForWrite(), false);
2239 stream = new BufferedOutputStream(fstream);
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002240 out.setOutput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002241 out.startDocument(null, true);
2242
Christopher Tatedb27b842016-02-25 14:39:17 -08002243 WallpaperData wallpaper;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002244
Christopher Tatedb27b842016-02-25 14:39:17 -08002245 wallpaper = mWallpaperMap.get(userId);
2246 if (wallpaper != null) {
2247 writeWallpaperAttributes(out, "wp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002248 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002249 wallpaper = mLockWallpaperMap.get(userId);
2250 if (wallpaper != null) {
2251 writeWallpaperAttributes(out, "kwp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002252 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002253
2254 out.endDocument();
Christopher Tatedb27b842016-02-25 14:39:17 -08002255
2256 stream.flush(); // also flushes fstream
2257 FileUtils.sync(fstream);
2258 stream.close(); // also closes fstream
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002259 journal.commit();
2260 } catch (IOException e) {
Christopher Tatead3c2592016-01-20 18:13:17 -08002261 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002262 journal.rollback();
2263 }
2264 }
2265
Christopher Tatedb27b842016-02-25 14:39:17 -08002266 private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
2267 throws IllegalArgumentException, IllegalStateException, IOException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002268 if (DEBUG) {
Christopher Tatef717b932017-09-11 15:52:54 -07002269 Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002270 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002271 out.startTag(null, tag);
2272 out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
2273 out.attribute(null, "width", Integer.toString(wallpaper.width));
2274 out.attribute(null, "height", Integer.toString(wallpaper.height));
2275
2276 out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
2277 out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
2278 out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
2279 out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
2280
2281 if (wallpaper.padding.left != 0) {
2282 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
2283 }
2284 if (wallpaper.padding.top != 0) {
2285 out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
2286 }
2287 if (wallpaper.padding.right != 0) {
2288 out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
2289 }
2290 if (wallpaper.padding.bottom != 0) {
2291 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
2292 }
2293
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002294 if (wallpaper.primaryColors != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002295 int colorsCount = wallpaper.primaryColors.getMainColors().size();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002296 out.attribute(null, "colorsCount", Integer.toString(colorsCount));
2297 if (colorsCount > 0) {
2298 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002299 final Color wc = wallpaper.primaryColors.getMainColors().get(i);
2300 out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002301 }
2302 }
Lucas Dupin75ec3792017-06-29 14:07:18 -07002303 out.attribute(null, "colorHints",
Lucas Dupin84b89d92017-05-09 12:16:19 -07002304 Integer.toString(wallpaper.primaryColors.getColorHints()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002305 }
2306
Christopher Tatedb27b842016-02-25 14:39:17 -08002307 out.attribute(null, "name", wallpaper.name);
2308 if (wallpaper.wallpaperComponent != null
2309 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
2310 out.attribute(null, "component",
2311 wallpaper.wallpaperComponent.flattenToShortString());
2312 }
Christopher Tated7faf532016-02-25 12:43:38 -08002313
2314 if (wallpaper.allowBackup) {
2315 out.attribute(null, "backup", "true");
2316 }
2317
Christopher Tatedb27b842016-02-25 14:39:17 -08002318 out.endTag(null, tag);
2319 }
2320
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002321 private void migrateFromOld() {
Christopher Tate9f224432017-08-01 16:32:49 -07002322 // Pre-N, what existed is the one we're now using as the display crop
2323 File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP);
2324 // In the very-long-ago, imagery lived with the settings app
2325 File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
2326 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
2327
2328 // Migrations from earlier wallpaper image storage schemas
2329 if (preNWallpaper.exists()) {
2330 if (!newWallpaper.exists()) {
2331 // we've got the 'wallpaper' crop file but not the nominal source image,
2332 // so do the simple "just take everything" straight copy of legacy data
2333 if (DEBUG) {
2334 Slog.i(TAG, "Migrating wallpaper schema");
2335 }
2336 FileUtils.copyFile(preNWallpaper, newWallpaper);
2337 } // else we're in the usual modern case: both source & crop exist
2338 } else if (originalWallpaper.exists()) {
2339 // VERY old schema; make sure things exist and are in the right place
2340 if (DEBUG) {
2341 Slog.i(TAG, "Migrating antique wallpaper schema");
2342 }
2343 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
2344 if (oldInfo.exists()) {
2345 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
2346 oldInfo.renameTo(newInfo);
2347 }
2348
2349 FileUtils.copyFile(originalWallpaper, preNWallpaper);
2350 originalWallpaper.renameTo(newWallpaper);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002351 }
2352 }
2353
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002354 private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
2355 String value = parser.getAttributeValue(null, name);
2356 if (value == null) {
2357 return defValue;
2358 }
2359 return Integer.parseInt(value);
2360 }
2361
Xiaohui Chenac531942015-05-13 13:20:52 -07002362 /**
2363 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could
2364 * happen during user switch. The async user switch observer may not have received
2365 * the event yet. We use this safe method when we don't care about this ordering and just
2366 * want to update the data. The data is going to be applied when the user switch observer
2367 * is eventually executed.
Christopher Tatef717b932017-09-11 15:52:54 -07002368 *
2369 * Important: this method loads settings to initialize the given user's wallpaper data if
2370 * there is no current in-memory state.
Xiaohui Chenac531942015-05-13 13:20:52 -07002371 */
Christopher Tatebe132e62016-02-10 12:59:49 -08002372 private WallpaperData getWallpaperSafeLocked(int userId, int which) {
2373 // We're setting either just system (work with the system wallpaper),
2374 // both (also work with the system wallpaper), or just the lock
2375 // wallpaper (update against the existing lock wallpaper if any).
2376 // Combined or just-system operations use the 'system' WallpaperData
2377 // for this use; lock-only operations use the dedicated one.
2378 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07002379 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatebe132e62016-02-10 12:59:49 -08002380 WallpaperData wallpaper = whichSet.get(userId);
Xiaohui Chenac531942015-05-13 13:20:52 -07002381 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002382 // common case, this is the first lookup post-boot of the system or
2383 // unified lock, so we bring up the saved state lazily now and recheck.
Christopher Tated7faf532016-02-25 12:43:38 -08002384 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08002385 wallpaper = whichSet.get(userId);
2386 // if it's still null here, this is a lock-only operation and there is not
2387 // yet a lock-only wallpaper set for this user, so we need to establish
2388 // it now.
2389 if (wallpaper == null) {
Christopher Tateedf7d042016-03-29 18:24:25 -07002390 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002391 wallpaper = new WallpaperData(userId,
2392 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2393 mLockWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002394 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08002395 } else {
2396 // sanity fallback: we're in bad shape, but establishing a known
2397 // valid system+lock WallpaperData will keep us from dying.
2398 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
2399 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
2400 mWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002401 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08002402 }
2403 }
Xiaohui Chenac531942015-05-13 13:20:52 -07002404 }
2405 return wallpaper;
2406 }
2407
Christopher Tated7faf532016-02-25 12:43:38 -08002408 private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002409 JournaledFile journal = makeJournaledFile(userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002410 FileInputStream stream = null;
2411 File file = journal.chooseForRead();
Christopher Tate9f224432017-08-01 16:32:49 -07002412
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002413 WallpaperData wallpaper = mWallpaperMap.get(userId);
2414 if (wallpaper == null) {
Christopher Tate9f224432017-08-01 16:32:49 -07002415 // Do this once per boot
2416 migrateFromOld();
2417
Christopher Tatebe132e62016-02-10 12:59:49 -08002418 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
Christopher Tated7faf532016-02-25 12:43:38 -08002419 wallpaper.allowBackup = true;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002420 mWallpaperMap.put(userId, wallpaper);
Christopher Tate41297ff2016-03-10 16:46:15 -08002421 if (!wallpaper.cropExists()) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002422 if (wallpaper.sourceExists()) {
2423 generateCrop(wallpaper);
2424 } else {
2425 Slog.i(TAG, "No static wallpaper imagery; defaults will be shown");
2426 }
Christopher Tate41297ff2016-03-10 16:46:15 -08002427 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002428 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002429 boolean success = false;
2430 try {
2431 stream = new FileInputStream(file);
2432 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002433 parser.setInput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002434
2435 int type;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002436 do {
2437 type = parser.next();
2438 if (type == XmlPullParser.START_TAG) {
2439 String tag = parser.getName();
2440 if ("wp".equals(tag)) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002441 // Common to system + lock wallpapers
Christopher Tated7faf532016-02-25 12:43:38 -08002442 parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
Christopher Tatead3c2592016-01-20 18:13:17 -08002443
Christopher Tatebe132e62016-02-10 12:59:49 -08002444 // A system wallpaper might also be a live wallpaper
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002445 String comp = parser.getAttributeValue(null, "component");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002446 wallpaper.nextWallpaperComponent = comp != null
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002447 ? ComponentName.unflattenFromString(comp)
2448 : null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002449 if (wallpaper.nextWallpaperComponent == null
2450 || "android".equals(wallpaper.nextWallpaperComponent
2451 .getPackageName())) {
Justin Koh29c30162014-09-05 17:10:10 -07002452 wallpaper.nextWallpaperComponent = mImageWallpaper;
Dianne Hackborn9ea31632011-08-05 14:43:50 -07002453 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002454
Mike Clerona428b2c2009-11-15 22:53:08 -08002455 if (DEBUG) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002456 Slog.v(TAG, "mWidth:" + wallpaper.width);
2457 Slog.v(TAG, "mHeight:" + wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002458 Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002459 Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002460 Slog.v(TAG, "mName:" + wallpaper.name);
2461 Slog.v(TAG, "mNextWallpaperComponent:"
2462 + wallpaper.nextWallpaperComponent);
Mike Clerona428b2c2009-11-15 22:53:08 -08002463 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002464 } else if ("kwp".equals(tag)) {
2465 // keyguard-specific wallpaper for this user
2466 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2467 if (lockWallpaper == null) {
2468 lockWallpaper = new WallpaperData(userId,
2469 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2470 mLockWallpaperMap.put(userId, lockWallpaper);
2471 }
Christopher Tated7faf532016-02-25 12:43:38 -08002472 parseWallpaperAttributes(parser, lockWallpaper, false);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002473 }
2474 }
2475 } while (type != XmlPullParser.END_DOCUMENT);
2476 success = true;
Dianne Hackborn13579ed2012-11-28 18:05:36 -08002477 } catch (FileNotFoundException e) {
2478 Slog.w(TAG, "no current wallpaper -- first boot?");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002479 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002480 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002481 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002482 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002483 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002484 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002485 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002486 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002487 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002488 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002489 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002490 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002491
2492 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002493 wallpaper.width = -1;
2494 wallpaper.height = -1;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002495 wallpaper.cropHint.set(0, 0, 0, 0);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002496 wallpaper.padding.set(0, 0, 0, 0);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002497 wallpaper.name = "";
Adrian Roosc28e3a92016-04-14 10:47:52 -07002498
2499 mLockWallpaperMap.remove(userId);
Christopher Tatead3c2592016-01-20 18:13:17 -08002500 } else {
2501 if (wallpaper.wallpaperId <= 0) {
2502 wallpaper.wallpaperId = makeWallpaperIdLocked();
2503 if (DEBUG) {
2504 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
2505 + "); now " + wallpaper.wallpaperId);
2506 }
2507 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002508 }
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002509
Adrian Roosc28e3a92016-04-14 10:47:52 -07002510 ensureSaneWallpaperData(wallpaper);
2511 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2512 if (lockWallpaper != null) {
2513 ensureSaneWallpaperData(lockWallpaper);
2514 }
2515 }
2516
2517 private void ensureSaneWallpaperData(WallpaperData wallpaper) {
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002518 // We always want to have some reasonable width hint.
John Spurlock7ea91ec2013-11-04 13:48:38 -05002519 int baseSize = getMaximumSizeDimension();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002520 if (wallpaper.width < baseSize) {
2521 wallpaper.width = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002522 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002523 if (wallpaper.height < baseSize) {
2524 wallpaper.height = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002525 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002526 // and crop, if not previously specified
2527 if (wallpaper.cropHint.width() <= 0
2528 || wallpaper.cropHint.height() <= 0) {
2529 wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
2530 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002531 }
2532
Christopher Tated7faf532016-02-25 12:43:38 -08002533 private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
2534 boolean keepDimensionHints) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002535 final String idString = parser.getAttributeValue(null, "id");
2536 if (idString != null) {
2537 final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
2538 if (id > mWallpaperId) {
2539 mWallpaperId = id;
2540 }
2541 } else {
2542 wallpaper.wallpaperId = makeWallpaperIdLocked();
2543 }
2544
Christopher Tated7faf532016-02-25 12:43:38 -08002545 if (!keepDimensionHints) {
2546 wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
2547 wallpaper.height = Integer.parseInt(parser
2548 .getAttributeValue(null, "height"));
2549 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002550 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
2551 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
2552 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
2553 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
2554 wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
2555 wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
2556 wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
2557 wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002558 int colorsCount = getAttributeInt(parser, "colorsCount", 0);
2559 if (colorsCount > 0) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002560 Color primary = null, secondary = null, tertiary = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002561 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002562 Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
2563 if (i == 0) {
2564 primary = color;
2565 } else if (i == 1) {
2566 secondary = color;
2567 } else if (i == 2) {
2568 tertiary = color;
2569 } else {
2570 break;
2571 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002572 }
Lucas Dupin84b89d92017-05-09 12:16:19 -07002573 int colorHints = getAttributeInt(parser, "colorHints", 0);
2574 wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002575 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002576 wallpaper.name = parser.getAttributeValue(null, "name");
Christopher Tated7faf532016-02-25 12:43:38 -08002577 wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
Christopher Tatebe132e62016-02-10 12:59:49 -08002578 }
2579
John Spurlock7ea91ec2013-11-04 13:48:38 -05002580 private int getMaximumSizeDimension() {
2581 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
2582 Display d = wm.getDefaultDisplay();
2583 return d.getMaximumSizeDimension();
2584 }
2585
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002586 // Called by SystemBackupAgent after files are restored to disk.
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08002587 public void settingsRestored() {
2588 // Verify caller is the system
2589 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2590 throw new RuntimeException("settingsRestored() can only be called from the system process");
2591 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002592 // TODO: If necessary, make it work for secondary users as well. This currently assumes
2593 // restores only to the primary user
Joe Onorato8a9b2202010-02-26 18:56:32 -08002594 if (DEBUG) Slog.v(TAG, "settingsRestored");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002595 WallpaperData wallpaper = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002596 boolean success = false;
2597 synchronized (mLock) {
Christopher Tated7faf532016-02-25 12:43:38 -08002598 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatedb27b842016-02-25 14:39:17 -08002599 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tatead3c2592016-01-20 18:13:17 -08002600 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
Christopher Tated7faf532016-02-25 12:43:38 -08002601 wallpaper.allowBackup = true; // by definition if it was restored
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002602 if (wallpaper.nextWallpaperComponent != null
Justin Koh29c30162014-09-05 17:10:10 -07002603 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002604 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002605 wallpaper, null)) {
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002606 // No such live wallpaper or other failure; fall back to the default
2607 // live wallpaper (since the profile being restored indicated that the
2608 // user had selected a live rather than static one).
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002609 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002610 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002611 success = true;
2612 } else {
Mike Clerona428b2c2009-11-15 22:53:08 -08002613 // If there's a wallpaper name, we use that. If that can't be loaded, then we
2614 // use the default.
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002615 if ("".equals(wallpaper.name)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002616 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
Mike Clerona428b2c2009-11-15 22:53:08 -08002617 success = true;
2618 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002619 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002620 success = restoreNamedResourceLocked(wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002621 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002622 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
2623 + " id=" + wallpaper.wallpaperId);
Mike Clerona428b2c2009-11-15 22:53:08 -08002624 if (success) {
Christopher Tate41297ff2016-03-10 16:46:15 -08002625 generateCrop(wallpaper); // based on the new image + metadata
2626 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002627 wallpaper, null);
Mike Clerona428b2c2009-11-15 22:53:08 -08002628 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002629 }
2630 }
2631
2632 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002633 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
2634 wallpaper.name = "";
Christopher Tatedb27b842016-02-25 14:39:17 -08002635 getWallpaperDir(UserHandle.USER_SYSTEM).delete();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002636 }
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002637
2638 synchronized (mLock) {
Christopher Tatedb27b842016-02-25 14:39:17 -08002639 saveSettingsLocked(UserHandle.USER_SYSTEM);
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002640 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002641 }
2642
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002643 // Restore the named resource bitmap to both source + crop files
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002644 boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
2645 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
2646 String resName = wallpaper.name.substring(4);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002647
2648 String pkg = null;
2649 int colon = resName.indexOf(':');
2650 if (colon > 0) {
2651 pkg = resName.substring(0, colon);
2652 }
2653
2654 String ident = null;
2655 int slash = resName.lastIndexOf('/');
2656 if (slash > 0) {
2657 ident = resName.substring(slash+1);
2658 }
2659
2660 String type = null;
2661 if (colon > 0 && slash > 0 && (slash-colon) > 1) {
2662 type = resName.substring(colon+1, slash);
2663 }
2664
2665 if (pkg != null && ident != null && type != null) {
2666 int resId = -1;
2667 InputStream res = null;
2668 FileOutputStream fos = null;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002669 FileOutputStream cos = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002670 try {
2671 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
2672 Resources r = c.getResources();
2673 resId = r.getIdentifier(resName, null, null);
2674 if (resId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002675 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002676 + " ident=" + ident);
2677 return false;
2678 }
2679
2680 res = r.openRawResource(resId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002681 if (wallpaper.wallpaperFile.exists()) {
2682 wallpaper.wallpaperFile.delete();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002683 wallpaper.cropFile.delete();
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07002684 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002685 fos = new FileOutputStream(wallpaper.wallpaperFile);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002686 cos = new FileOutputStream(wallpaper.cropFile);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002687
2688 byte[] buffer = new byte[32768];
2689 int amt;
2690 while ((amt=res.read(buffer)) > 0) {
2691 fos.write(buffer, 0, amt);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002692 cos.write(buffer, 0, amt);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002693 }
2694 // mWallpaperObserver will notice the close and send the change broadcast
2695
Joe Onorato8a9b2202010-02-26 18:56:32 -08002696 Slog.v(TAG, "Restored wallpaper: " + resName);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002697 return true;
2698 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002699 Slog.e(TAG, "Package name " + pkg + " not found");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002700 } catch (Resources.NotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002701 Slog.e(TAG, "Resource not found: " + resId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002702 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002703 Slog.e(TAG, "IOException while restoring wallpaper ", e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002704 } finally {
Christopher Tatead3c2592016-01-20 18:13:17 -08002705 IoUtils.closeQuietly(res);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002706 if (fos != null) {
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07002707 FileUtils.sync(fos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002708 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002709 if (cos != null) {
2710 FileUtils.sync(cos);
2711 }
2712 IoUtils.closeQuietly(fos);
2713 IoUtils.closeQuietly(cos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002714 }
2715 }
2716 }
2717 return false;
2718 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002719
Dianne Hackborneb034652009-09-07 00:49:58 -07002720 @Override
2721 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06002722 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Dianne Hackborneb034652009-09-07 00:49:58 -07002723
2724 synchronized (mLock) {
Adrian Roosc28e3a92016-04-14 10:47:52 -07002725 pw.println("System wallpaper state:");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002726 for (int i = 0; i < mWallpaperMap.size(); i++) {
2727 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
Christopher Tatead3c2592016-01-20 18:13:17 -08002728 pw.print(" User "); pw.print(wallpaper.userId);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002729 pw.print(": id="); pw.println(wallpaper.wallpaperId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002730 pw.print(" mWidth=");
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002731 pw.print(wallpaper.width);
2732 pw.print(" mHeight=");
2733 pw.println(wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002734 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002735 pw.print(" mPadding="); pw.println(wallpaper.padding);
2736 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01002737 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002738 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002739 if (wallpaper.connection != null) {
2740 WallpaperConnection conn = wallpaper.connection;
2741 pw.print(" Wallpaper connection ");
2742 pw.print(conn);
2743 pw.println(":");
2744 if (conn.mInfo != null) {
2745 pw.print(" mInfo.component=");
2746 pw.println(conn.mInfo.getComponent());
2747 }
2748 pw.print(" mToken=");
2749 pw.println(conn.mToken);
2750 pw.print(" mService=");
2751 pw.println(conn.mService);
2752 pw.print(" mEngine=");
2753 pw.println(conn.mEngine);
2754 pw.print(" mLastDiedTime=");
2755 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
2756 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002757 }
Adrian Roosc28e3a92016-04-14 10:47:52 -07002758 pw.println("Lock wallpaper state:");
2759 for (int i = 0; i < mLockWallpaperMap.size(); i++) {
2760 WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
2761 pw.print(" User "); pw.print(wallpaper.userId);
2762 pw.print(": id="); pw.println(wallpaper.wallpaperId);
2763 pw.print(" mWidth="); pw.print(wallpaper.width);
2764 pw.print(" mHeight="); pw.println(wallpaper.height);
2765 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
2766 pw.print(" mPadding="); pw.println(wallpaper.padding);
2767 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01002768 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002769 }
2770
Dianne Hackborneb034652009-09-07 00:49:58 -07002771 }
2772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773}