blob: 397c50f949b989a613683222da0ab969826c6a9d [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
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900102import java.lang.reflect.InvocationTargetException;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600103import libcore.io.IoUtils;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700104
105import org.xmlpull.v1.XmlPullParser;
106import org.xmlpull.v1.XmlPullParserException;
107import org.xmlpull.v1.XmlSerializer;
108
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600109import java.io.BufferedOutputStream;
110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
114import java.io.FileOutputStream;
115import java.io.IOException;
116import java.io.InputStream;
117import java.io.PrintWriter;
118import java.nio.charset.StandardCharsets;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400119import java.util.ArrayList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600120import java.util.Arrays;
121import java.util.List;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700122import java.util.Objects;
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900123import com.android.internal.R;
Christopher Tatead3c2592016-01-20 18:13:17 -0800124
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900125public class WallpaperManagerService extends IWallpaperManager.Stub
126 implements IWallpaperManagerService {
Amith Yamasani09e9cdc2013-11-06 14:54:50 -0800127 static final String TAG = "WallpaperManagerService";
Joe Onorato7e1693a2016-02-01 17:45:03 -0800128 static final boolean DEBUG = false;
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700129 static final boolean DEBUG_LIVE = DEBUG || true;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700130
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600131 public static class Lifecycle extends SystemService {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900132 private IWallpaperManagerService mService;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600133
134 public Lifecycle(Context context) {
135 super(context);
136 }
137
138 @Override
139 public void onStart() {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900140 try {
141 final Class<? extends IWallpaperManagerService> klass =
142 (Class<? extends IWallpaperManagerService>)Class.forName(
143 getContext().getResources().getString(
144 R.string.config_wallpaperManagerServiceName));
145 mService = klass.getConstructor(Context.class).newInstance(getContext());
146 publishBinderService(Context.WALLPAPER_SERVICE, mService);
147 } catch (Exception exp) {
148 Slog.wtf(TAG, "Failed to instantiate WallpaperManagerService", exp);
149 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600150 }
151
152 @Override
153 public void onBootPhase(int phase) {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900154 if (mService != null) {
155 mService.onBootPhase(phase);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600156 }
157 }
158
159 @Override
160 public void onUnlockUser(int userHandle) {
Daichi Hirono4bbf8522017-12-06 10:34:18 +0900161 if (mService != null) {
162 mService.onUnlockUser(userHandle);
163 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600164 }
165 }
166
Christopher Tatebe132e62016-02-10 12:59:49 -0800167 final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700169 /**
170 * Minimum time between crashes of a wallpaper service for us to consider
171 * restarting it vs. just reverting to the static wallpaper.
172 */
173 static final long MIN_WALLPAPER_CRASH_TIME = 10000;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700174 static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800175 static final String WALLPAPER = "wallpaper_orig";
176 static final String WALLPAPER_CROP = "wallpaper";
Christopher Tatebe132e62016-02-10 12:59:49 -0800177 static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
178 static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800179 static final String WALLPAPER_INFO = "wallpaper_info.xml";
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700180
Christopher Tatebe132e62016-02-10 12:59:49 -0800181 // All the various per-user state files we need to be aware of
182 static final String[] sPerUserFiles = new String[] {
183 WALLPAPER, WALLPAPER_CROP,
184 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
185 WALLPAPER_INFO
186 };
187
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700188 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
190 * that the wallpaper has changed. The CREATE is triggered when there is no
191 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
Christopher Tate190e8532016-07-11 11:35:34 -0700192 * every time the wallpaper is changed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 */
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800194 private class WallpaperObserver extends FileObserver {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700195
Christopher Tatebe132e62016-02-10 12:59:49 -0800196 final int mUserId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800197 final WallpaperData mWallpaper;
198 final File mWallpaperDir;
199 final File mWallpaperFile;
Christopher Tatebe132e62016-02-10 12:59:49 -0800200 final File mWallpaperLockFile;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800201
202 public WallpaperObserver(WallpaperData wallpaper) {
203 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
Christopher Tateda058e22014-10-08 14:51:09 -0700204 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
Christopher Tatebe132e62016-02-10 12:59:49 -0800205 mUserId = wallpaper.userId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800206 mWallpaperDir = getWallpaperDir(wallpaper.userId);
207 mWallpaper = wallpaper;
208 mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
Christopher Tatebe132e62016-02-10 12:59:49 -0800209 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800210 }
211
Christopher Tatebe132e62016-02-10 12:59:49 -0800212 private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
213 WallpaperData wallpaper = null;
214 synchronized (mLock) {
215 if (lockChanged) {
216 wallpaper = mLockWallpaperMap.get(mUserId);
217 }
218 if (wallpaper == null) {
219 // no lock-specific wallpaper exists, or sys case, handled together
220 wallpaper = mWallpaperMap.get(mUserId);
221 }
222 }
223 return (wallpaper != null) ? wallpaper : mWallpaper;
224 }
225
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800226 @Override
227 public void onEvent(int event, String path) {
228 if (path == null) {
229 return;
230 }
Christopher Tated7faf532016-02-25 12:43:38 -0800231 final boolean moved = (event == MOVED_TO);
232 final boolean written = (event == CLOSE_WRITE || moved);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800233 final File changedFile = new File(mWallpaperDir, path);
234
Christopher Tatebe132e62016-02-10 12:59:49 -0800235 // System and system+lock changes happen on the system wallpaper input file;
236 // lock-only changes happen on the dedicated lock wallpaper input file
237 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
238 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700239 int notifyColorsWhich = 0;
Christopher Tatebe132e62016-02-10 12:59:49 -0800240 WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
241
242 if (DEBUG) {
243 Slog.v(TAG, "Wallpaper file change: evt=" + event
244 + " path=" + path
245 + " sys=" + sysWallpaperChanged
246 + " lock=" + lockWallpaperChanged
247 + " imagePending=" + wallpaper.imageWallpaperPending
248 + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
249 + " written=" + written);
250 }
Christopher Tate8347b632016-04-29 18:59:18 -0700251
252 if (moved && lockWallpaperChanged) {
253 // We just migrated sys -> lock to preserve imagery for an impending
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700254 // new system-only wallpaper. Tell keyguard about it and make sure it
255 // has the right SELinux label.
Christopher Tate8347b632016-04-29 18:59:18 -0700256 if (DEBUG) {
257 Slog.i(TAG, "Sys -> lock MOVED_TO");
258 }
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700259 SELinux.restorecon(changedFile);
Christopher Tate8347b632016-04-29 18:59:18 -0700260 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700261 notifyWallpaperColorsChanged(wallpaper, FLAG_LOCK);
Christopher Tate8347b632016-04-29 18:59:18 -0700262 return;
263 }
264
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800265 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800266 if (sysWallpaperChanged || lockWallpaperChanged) {
267 notifyCallbacksLocked(wallpaper);
268 if (wallpaper.wallpaperComponent == null
Christopher Tateda058e22014-10-08 14:51:09 -0700269 || event != CLOSE_WRITE // includes the MOVED_TO case
Christopher Tatebe132e62016-02-10 12:59:49 -0800270 || wallpaper.imageWallpaperPending) {
Christopher Tateda058e22014-10-08 14:51:09 -0700271 if (written) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800272 // The image source has finished writing the source image,
273 // so we now produce the crop rect (in the background), and
274 // only publish the new displayable (sub)image as a result
275 // of that work.
Christopher Tatebe132e62016-02-10 12:59:49 -0800276 if (DEBUG) {
277 Slog.v(TAG, "Wallpaper written; generating crop");
278 }
Christopher Tateebadfb12016-07-25 14:50:08 -0700279 SELinux.restorecon(changedFile);
Christopher Tated7faf532016-02-25 12:43:38 -0800280 if (moved) {
281 // This is a restore, so generate the crop using any just-restored new
282 // crop guidelines, making sure to preserve our local dimension hints.
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700283 // We also make sure to reapply the correct SELinux label.
Christopher Tated7faf532016-02-25 12:43:38 -0800284 if (DEBUG) {
285 Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
286 }
287 loadSettingsLocked(wallpaper.userId, true);
288 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800289 generateCrop(wallpaper);
290 if (DEBUG) {
291 Slog.v(TAG, "Crop done; invoking completion callback");
292 }
293 wallpaper.imageWallpaperPending = false;
Christopher Tatebe132e62016-02-10 12:59:49 -0800294 if (sysWallpaperChanged) {
295 // If this was the system wallpaper, rebind...
296 bindWallpaperComponentLocked(mImageWallpaper, true,
297 false, wallpaper, null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700298 notifyColorsWhich |= FLAG_SYSTEM;
Christopher Tatebe132e62016-02-10 12:59:49 -0800299 }
300 if (lockWallpaperChanged
Christopher Tateedf7d042016-03-29 18:24:25 -0700301 || (wallpaper.whichPending & FLAG_LOCK) != 0) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800302 if (DEBUG) {
Christopher Tatedb27b842016-02-25 14:39:17 -0800303 Slog.i(TAG, "Lock-relevant wallpaper changed");
Christopher Tatebe132e62016-02-10 12:59:49 -0800304 }
Christopher Tatedb27b842016-02-25 14:39:17 -0800305 // either a lock-only wallpaper commit or a system+lock event.
306 // if it's system-plus-lock we need to wipe the lock bookkeeping;
307 // we're falling back to displaying the system wallpaper there.
308 if (!lockWallpaperChanged) {
309 mLockWallpaperMap.remove(wallpaper.userId);
310 }
311 // and in any case, tell keyguard about it
Christopher Tate8347b632016-04-29 18:59:18 -0700312 notifyLockWallpaperChanged();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700313 notifyColorsWhich |= FLAG_LOCK;
Christopher Tatebe132e62016-02-10 12:59:49 -0800314 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700315
Christopher Tatedb27b842016-02-25 14:39:17 -0800316 saveSettingsLocked(wallpaper.userId);
Christopher Tate8efbe0d2017-08-29 16:50:13 -0700317
318 // Publish completion *after* we've persisted the changes
319 if (wallpaper.setComplete != null) {
320 try {
321 wallpaper.setComplete.onWallpaperChanged();
322 } catch (RemoteException e) {
323 // if this fails we don't really care; the setting app may just
324 // have crashed and that sort of thing is a fact of life.
325 }
326 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700327 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 }
329 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800330 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700331
332 // Outside of the lock since it will synchronize itself
333 if (notifyColorsWhich != 0) {
334 notifyWallpaperColorsChanged(wallpaper, notifyColorsWhich);
335 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800336 }
337 }
338
Christopher Tate8347b632016-04-29 18:59:18 -0700339 void notifyLockWallpaperChanged() {
340 final IWallpaperManagerCallback cb = mKeyguardListener;
341 if (cb != null) {
342 try {
343 cb.onWallpaperChanged();
344 } catch (RemoteException e) {
345 // Oh well it went away; no big deal
346 }
347 }
348 }
349
Lucas Dupin50ba9912017-07-14 11:55:05 -0700350 private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700351 boolean needsExtraction;
352 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700353 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
354 mColorsChangedListeners.get(wallpaper.userId);
355 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
356 mColorsChangedListeners.get(UserHandle.USER_ALL);
357 // No-op until someone is listening to it.
358 if (emptyCallbackList(currentUserColorListeners) &&
359 emptyCallbackList(userAllColorListeners)) {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700360 return;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700361 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700362
363 if (DEBUG) {
364 Slog.v(TAG, "notifyWallpaperColorsChanged " + which);
365 }
366
367 needsExtraction = wallpaper.primaryColors == null;
368 }
369
Lucas Dupin75ec3792017-06-29 14:07:18 -0700370 // Let's notify the current values, it's fine if it's null, it just means
371 // that we don't know yet.
Lucas Dupin50ba9912017-07-14 11:55:05 -0700372 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700373
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700374 if (needsExtraction) {
375 extractColors(wallpaper);
Lucas Dupin50ba9912017-07-14 11:55:05 -0700376 synchronized (mLock) {
377 // Don't need to notify if nothing changed.
378 if (wallpaper.primaryColors == null) {
379 return;
380 }
381 }
382 notifyColorListeners(wallpaper.primaryColors, which, wallpaper.userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700383 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700384 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700385
Lucas Dupin50ba9912017-07-14 11:55:05 -0700386 private static <T extends IInterface> boolean emptyCallbackList(RemoteCallbackList<T> list) {
387 return (list == null || list.getRegisteredCallbackCount() == 0);
388 }
389
390 private void notifyColorListeners(@NonNull WallpaperColors wallpaperColors, int which,
391 int userId) {
Lucas Dupin75ec3792017-06-29 14:07:18 -0700392 final IWallpaperManagerCallback keyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400393 final ArrayList<IWallpaperManagerCallback> colorListeners = new ArrayList<>();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700394 synchronized (mLock) {
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400395 final RemoteCallbackList<IWallpaperManagerCallback> currentUserColorListeners =
396 mColorsChangedListeners.get(userId);
397 final RemoteCallbackList<IWallpaperManagerCallback> userAllColorListeners =
398 mColorsChangedListeners.get(UserHandle.USER_ALL);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700399 keyguardListener = mKeyguardListener;
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400400
401 if (currentUserColorListeners != null) {
402 final int count = currentUserColorListeners.beginBroadcast();
403 for (int i = 0; i < count; i++) {
404 colorListeners.add(currentUserColorListeners.getBroadcastItem(i));
405 }
406 currentUserColorListeners.finishBroadcast();
407 }
408
409 if (userAllColorListeners != null) {
410 final int count = userAllColorListeners.beginBroadcast();
411 for (int i = 0; i < count; i++) {
412 colorListeners.add(userAllColorListeners.getBroadcastItem(i));
413 }
414 userAllColorListeners.finishBroadcast();
415 }
Lucas Dupin75ec3792017-06-29 14:07:18 -0700416 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700417
Lucas Dupinfb3ab2a2017-08-08 14:17:30 -0400418 final int count = colorListeners.size();
419 for (int i = 0; i < count; i++) {
420 try {
421 colorListeners.get(i).onWallpaperColorsChanged(wallpaperColors, which, userId);
422 } catch (RemoteException e) {
423 // Callback is gone, it's not necessary to unregister it since
424 // RemoteCallbackList#getBroadcastItem will take care of it.
Lucas Dupin75ec3792017-06-29 14:07:18 -0700425 }
426 }
427
428 if (keyguardListener != null) {
429 try {
Lucas Dupin50ba9912017-07-14 11:55:05 -0700430 keyguardListener.onWallpaperColorsChanged(wallpaperColors, which, userId);
Lucas Dupin75ec3792017-06-29 14:07:18 -0700431 } catch (RemoteException e) {
432 // Oh well it went away; no big deal
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700433 }
434 }
435 }
436
Lucas Dupinbcae5852017-05-03 12:42:58 -0700437 /**
438 * We can easily extract colors from an ImageWallpaper since it's only a bitmap.
Lucas Dupin284836b2017-06-23 15:28:41 -0700439 * In this case, using the crop is more than enough. Live wallpapers are just ignored.
Lucas Dupinbcae5852017-05-03 12:42:58 -0700440 *
441 * @param wallpaper a wallpaper representation
442 */
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700443 private void extractColors(WallpaperData wallpaper) {
444 String cropFile = null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700445 int wallpaperId;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700446
Lucas Dupinbcae5852017-05-03 12:42:58 -0700447 synchronized (mLock) {
Lucas Dupin284836b2017-06-23 15:28:41 -0700448 // Not having a wallpaperComponent means it's a lock screen wallpaper.
449 final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
Lucas Dupinbcae5852017-05-03 12:42:58 -0700450 || wallpaper.wallpaperComponent == null;
Lucas Dupin284836b2017-06-23 15:28:41 -0700451 if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
452 cropFile = wallpaper.cropFile.getAbsolutePath();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700453 }
454 wallpaperId = wallpaper.wallpaperId;
455 }
456
Lucas Dupin84b89d92017-05-09 12:16:19 -0700457 WallpaperColors colors = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700458 if (cropFile != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700459 Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
Lucas Dupin284836b2017-06-23 15:28:41 -0700460 if (bitmap != null) {
461 colors = WallpaperColors.fromBitmap(bitmap);
462 bitmap.recycle();
463 }
Lucas Dupinbcae5852017-05-03 12:42:58 -0700464 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700465
Lucas Dupin84b89d92017-05-09 12:16:19 -0700466 if (colors == null) {
Lucas Dupinbcae5852017-05-03 12:42:58 -0700467 Slog.w(TAG, "Cannot extract colors because wallpaper could not be read.");
468 return;
469 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700470
Lucas Dupinbcae5852017-05-03 12:42:58 -0700471 synchronized (mLock) {
472 if (wallpaper.wallpaperId == wallpaperId) {
Lucas Dupin84b89d92017-05-09 12:16:19 -0700473 wallpaper.primaryColors = colors;
Lucas Dupin75ec3792017-06-29 14:07:18 -0700474 // Now that we have the colors, let's save them into the xml
475 // to avoid having to run this again.
476 saveSettingsLocked(wallpaper.userId);
Lucas Dupinbcae5852017-05-03 12:42:58 -0700477 } else {
478 Slog.w(TAG, "Not setting primary colors since wallpaper changed");
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700479 }
480 }
481 }
482
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800483 /**
484 * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
485 * for display.
486 */
487 private void generateCrop(WallpaperData wallpaper) {
488 boolean success = false;
Christopher Tate1a96b632016-03-22 15:25:42 -0700489
490 Rect cropHint = new Rect(wallpaper.cropHint);
Christopher Tatebe132e62016-02-10 12:59:49 -0800491
492 if (DEBUG) {
493 Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
494 + Integer.toHexString(wallpaper.whichPending)
Christopher Tate1a96b632016-03-22 15:25:42 -0700495 + " to " + wallpaper.cropFile.getName()
496 + " crop=(" + cropHint.width() + 'x' + cropHint.height()
497 + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
Christopher Tatebe132e62016-02-10 12:59:49 -0800498 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800499
500 // Analyse the source; needed in multiple cases
501 BitmapFactory.Options options = new BitmapFactory.Options();
502 options.inJustDecodeBounds = true;
503 BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
Christopher Tate1a96b632016-03-22 15:25:42 -0700504 if (options.outWidth <= 0 || options.outHeight <= 0) {
Joe LaPennac298b162016-05-02 15:25:50 -0700505 Slog.w(TAG, "Invalid wallpaper data");
Christopher Tate1a96b632016-03-22 15:25:42 -0700506 success = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800507 } else {
Christopher Tate1a96b632016-03-22 15:25:42 -0700508 boolean needCrop = false;
509 boolean needScale = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800510
Christopher Tate1a96b632016-03-22 15:25:42 -0700511 // Empty crop means use the full image
512 if (cropHint.isEmpty()) {
513 cropHint.left = cropHint.top = 0;
514 cropHint.right = options.outWidth;
515 cropHint.bottom = options.outHeight;
516 } else {
517 // force the crop rect to lie within the measured bounds
518 cropHint.offset(
519 (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
520 (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
521
Adrian Roos5c97ff22016-08-31 10:25:38 -0700522 // If the crop hint was larger than the image we just overshot. Patch things up.
523 if (cropHint.left < 0) {
524 cropHint.left = 0;
525 }
526 if (cropHint.top < 0) {
527 cropHint.top = 0;
528 }
529
Christopher Tate1a96b632016-03-22 15:25:42 -0700530 // Don't bother cropping if what we're left with is identity
Christopher Tateebadfb12016-07-25 14:50:08 -0700531 needCrop = (options.outHeight > cropHint.height()
Adrian Roos5c97ff22016-08-31 10:25:38 -0700532 || options.outWidth > cropHint.width());
Christopher Tate1a96b632016-03-22 15:25:42 -0700533 }
534
535 // scale if the crop height winds up not matching the recommended metrics
536 needScale = (wallpaper.height != cropHint.height());
537
538 if (DEBUG) {
539 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
540 Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
541 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
542 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
543 }
544
545 if (!needCrop && !needScale) {
546 // Simple case: the nominal crop fits what we want, so we take
547 // the whole thing and just copy the image file directly.
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800548 if (DEBUG) {
Christopher Tate1a96b632016-03-22 15:25:42 -0700549 Slog.v(TAG, "Null crop of new wallpaper; copying");
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800550 }
Christopher Tate1a96b632016-03-22 15:25:42 -0700551 success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
552 if (!success) {
553 wallpaper.cropFile.delete();
554 // TODO: fall back to default wallpaper in this case
555 }
556 } else {
557 // Fancy case: crop and scale. First, we decode and scale down if appropriate.
558 FileOutputStream f = null;
559 BufferedOutputStream bos = null;
560 try {
561 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
562 wallpaper.wallpaperFile.getAbsolutePath(), false);
563
564 // This actually downsamples only by powers of two, but that's okay; we do
565 // a proper scaling blit later. This is to minimize transient RAM use.
566 // We calculate the largest power-of-two under the actual ratio rather than
567 // just let the decode take care of it because we also want to remap where the
568 // cropHint rectangle lies in the decoded [super]rect.
569 final BitmapFactory.Options scaler;
570 final int actualScale = cropHint.height() / wallpaper.height;
571 int scale = 1;
572 while (2*scale < actualScale) {
573 scale *= 2;
574 }
575 if (scale > 1) {
576 scaler = new BitmapFactory.Options();
577 scaler.inSampleSize = scale;
578 if (DEBUG) {
579 Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
580 }
581 } else {
582 scaler = null;
583 }
584 Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
585 decoder.recycle();
586
587 if (cropped == null) {
588 Slog.e(TAG, "Could not decode new wallpaper");
589 } else {
590 // We've got the extracted crop; now we want to scale it properly to
591 // the desired rectangle. That's a height-biased operation: make it
592 // fit the hinted height, and accept whatever width we end up with.
593 cropHint.offsetTo(0, 0);
594 cropHint.right /= scale; // adjust by downsampling factor
595 cropHint.bottom /= scale;
596 final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
597 if (DEBUG) {
598 Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
599 }
600 final int destWidth = (int)(cropHint.width() * heightR);
601 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
602 destWidth, wallpaper.height, true);
603 if (DEBUG) {
604 Slog.v(TAG, "Final extract:");
605 Slog.v(TAG, " dims: w=" + wallpaper.width
606 + " h=" + wallpaper.height);
607 Slog.v(TAG, " out: w=" + finalCrop.getWidth()
608 + " h=" + finalCrop.getHeight());
609 }
610
611 f = new FileOutputStream(wallpaper.cropFile);
612 bos = new BufferedOutputStream(f, 32*1024);
Christopher Tatec484f542016-05-11 14:31:34 -0700613 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
Christopher Tate1a96b632016-03-22 15:25:42 -0700614 bos.flush(); // don't rely on the implicit flush-at-close when noting success
615 success = true;
616 }
617 } catch (Exception e) {
618 if (DEBUG) {
619 Slog.e(TAG, "Error decoding crop", e);
620 }
621 } finally {
622 IoUtils.closeQuietly(bos);
623 IoUtils.closeQuietly(f);
624 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800625 }
626 }
627
628 if (!success) {
629 Slog.e(TAG, "Unable to apply new wallpaper");
630 wallpaper.cropFile.delete();
631 }
632
633 if (wallpaper.cropFile.exists()) {
634 boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
635 if (DEBUG) {
636 Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
637 }
638 }
639 }
640
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700641 final Context mContext;
642 final IWindowManager mIWindowManager;
Amith Yamasani4e2820c2012-08-28 22:17:23 -0700643 final IPackageManager mIPackageManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800644 final MyPackageMonitor mMonitor;
Benjamin Franzf3ece362015-02-11 10:51:10 +0000645 final AppOpsManager mAppOpsManager;
Lucas Dupin50ba9912017-07-14 11:55:05 -0700646 /**
647 * Map of color listeners per user id.
648 * The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
649 */
650 final SparseArray<RemoteCallbackList<IWallpaperManagerCallback>> mColorsChangedListeners;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800651 WallpaperData mLastWallpaper;
Christopher Tatebe132e62016-02-10 12:59:49 -0800652 IWallpaperManagerCallback mKeyguardListener;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600653 boolean mWaitingForUnlock;
Christopher Tate762dfd12016-10-10 17:44:48 -0700654 boolean mShuttingDown;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655
Justin Koh29c30162014-09-05 17:10:10 -0700656 /**
Christopher Tatead3c2592016-01-20 18:13:17 -0800657 * ID of the current wallpaper, changed every time anything sets a wallpaper.
658 * This is used for external detection of wallpaper update activity.
659 */
660 int mWallpaperId;
661
662 /**
Justin Koh29c30162014-09-05 17:10:10 -0700663 * Name of the component used to display bitmap wallpapers from either the gallery or
664 * built-in wallpapers.
665 */
666 final ComponentName mImageWallpaper;
667
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700668 /**
669 * Name of the default wallpaper component; might be different from mImageWallpaper
670 */
671 final ComponentName mDefaultWallpaperComponent;
672
Christopher Tatebe132e62016-02-10 12:59:49 -0800673 final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
674 final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
Dianne Hackborn07213e62011-08-24 20:05:39 -0700675
Christopher Tate38a5dc32016-07-20 15:10:18 -0700676 final SparseArray<Boolean> mUserRestorecon = new SparseArray<Boolean>();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800677 int mCurrentUserId;
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700678 boolean mInAmbientMode;
Dianne Hackborn07213e62011-08-24 20:05:39 -0700679
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800680 static class WallpaperData {
681
682 int userId;
683
Christopher Tatebe132e62016-02-10 12:59:49 -0800684 final File wallpaperFile; // source image
685 final File cropFile; // eventual destination
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800686
687 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800688 * True while the client is writing a new wallpaper
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800689 */
690 boolean imageWallpaperPending;
691
692 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800693 * Which new wallpapers are being written; mirrors the 'which'
694 * selector bit field to setWallpaper().
695 */
696 int whichPending;
697
698 /**
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800699 * Callback once the set + crop is finished
700 */
701 IWallpaperManagerCallback setComplete;
702
703 /**
Christopher Tated7faf532016-02-25 12:43:38 -0800704 * Is the OS allowed to back up this wallpaper imagery?
705 */
706 boolean allowBackup;
707
708 /**
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800709 * Resource name if using a picture from the wallpaper gallery
710 */
711 String name = "";
712
713 /**
714 * The component name of the currently set live wallpaper.
715 */
716 ComponentName wallpaperComponent;
717
718 /**
719 * The component name of the wallpaper that should be set next.
720 */
721 ComponentName nextWallpaperComponent;
722
Christopher Tatead3c2592016-01-20 18:13:17 -0800723 /**
724 * The ID of this wallpaper
725 */
726 int wallpaperId;
727
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700728 /**
729 * Primary colors histogram
730 */
731 WallpaperColors primaryColors;
732
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800733 WallpaperConnection connection;
734 long lastDiedTime;
735 boolean wallpaperUpdating;
736 WallpaperObserver wallpaperObserver;
737
738 /**
739 * List of callbacks registered they should each be notified when the wallpaper is changed.
740 */
741 private RemoteCallbackList<IWallpaperManagerCallback> callbacks
742 = new RemoteCallbackList<IWallpaperManagerCallback>();
743
744 int width = -1;
745 int height = -1;
746
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800747 /**
748 * The crop hint supplied for displaying a subset of the source image
749 */
750 final Rect cropHint = new Rect(0, 0, 0, 0);
751
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700752 final Rect padding = new Rect(0, 0, 0, 0);
753
Christopher Tatebe132e62016-02-10 12:59:49 -0800754 WallpaperData(int userId, String inputFileName, String cropFileName) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800755 this.userId = userId;
Christopher Tatebe132e62016-02-10 12:59:49 -0800756 final File wallpaperDir = getWallpaperDir(userId);
757 wallpaperFile = new File(wallpaperDir, inputFileName);
758 cropFile = new File(wallpaperDir, cropFileName);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800759 }
760
Christopher Tatebe132e62016-02-10 12:59:49 -0800761 // Called during initialization of a given user's wallpaper bookkeeping
Christopher Tate41297ff2016-03-10 16:46:15 -0800762 boolean cropExists() {
763 return cropFile.exists();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800764 }
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700765
766 boolean sourceExists() {
767 return wallpaperFile.exists();
768 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800769 }
770
Christopher Tatead3c2592016-01-20 18:13:17 -0800771 int makeWallpaperIdLocked() {
772 do {
773 ++mWallpaperId;
774 } while (mWallpaperId == 0);
775 return mWallpaperId;
776 }
777
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700778 class WallpaperConnection extends IWallpaperConnection.Stub
779 implements ServiceConnection {
Adrian Roosc3f915e2016-09-06 11:40:53 -0700780
781 /** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
782 * middle of an update). If exceeded, the wallpaper gets reset to the system default. */
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700783 private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000;
Adrian Roosc3f915e2016-09-06 11:40:53 -0700784
Dianne Hackborneb034652009-09-07 00:49:58 -0700785 final WallpaperInfo mInfo;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700786 final Binder mToken = new Binder();
787 IWallpaperService mService;
788 IWallpaperEngine mEngine;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800789 WallpaperData mWallpaper;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700790 IRemoteCallback mReply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791
Michael Wright5203a8b2013-10-03 14:16:42 -0700792 boolean mDimensionsChanged = false;
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700793 boolean mPaddingChanged = false;
Michael Wright5203a8b2013-10-03 14:16:42 -0700794
Adrian Roosc3f915e2016-09-06 11:40:53 -0700795 private Runnable mResetRunnable = () -> {
796 synchronized (mLock) {
Christopher Tate762dfd12016-10-10 17:44:48 -0700797 if (mShuttingDown) {
798 // Don't expect wallpaper services to relaunch during shutdown
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700799 if (DEBUG_LIVE) {
Christopher Tate762dfd12016-10-10 17:44:48 -0700800 Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
801 }
802 return;
803 }
804
Adrian Roosc3f915e2016-09-06 11:40:53 -0700805 if (!mWallpaper.wallpaperUpdating
806 && mWallpaper.userId == mCurrentUserId) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700807 Slog.w(TAG, "Wallpaper reconnect timed out for " + mWallpaper.wallpaperComponent
808 + ", reverting to built-in wallpaper!");
Adrian Roosc3f915e2016-09-06 11:40:53 -0700809 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId,
810 null);
811 }
812 }
813 };
814
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800815 public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700816 mInfo = info;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800817 mWallpaper = wallpaper;
Dianne Hackborneb034652009-09-07 00:49:58 -0700818 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700819
820 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700821 public void onServiceConnected(ComponentName name, IBinder service) {
822 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800823 if (mWallpaper.connection == this) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700824 mService = IWallpaperService.Stub.asInterface(service);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800825 attachServiceLocked(this, mWallpaper);
Dianne Hackborneb034652009-09-07 00:49:58 -0700826 // XXX should probably do saveSettingsLocked() later
827 // when we have an engine, but I'm not sure about
828 // locking there and anyway we always need to be able to
829 // recover if there is something wrong.
Christopher Tatedb27b842016-02-25 14:39:17 -0800830 saveSettingsLocked(mWallpaper.userId);
Adrian Roosc3f915e2016-09-06 11:40:53 -0700831 FgThread.getHandler().removeCallbacks(mResetRunnable);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700832 }
833 }
834 }
835
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700836 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700837 public void onServiceDisconnected(ComponentName name) {
838 synchronized (mLock) {
Christopher Tatec349e59f2017-05-05 17:37:43 -0700839 Slog.w(TAG, "Wallpaper service gone: " + name);
840 if (!Objects.equals(name, mWallpaper.wallpaperComponent)) {
841 Slog.e(TAG, "Does not match expected wallpaper component "
842 + mWallpaper.wallpaperComponent);
843 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700844 mService = null;
845 mEngine = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800846 if (mWallpaper.connection == this) {
Christopher Tatec349e59f2017-05-05 17:37:43 -0700847 // There is an inherent ordering race between this callback and the
848 // package monitor that receives notice that a package is being updated,
849 // so we cannot quite trust at this moment that we know for sure that
850 // this is not an update. If we think this is a genuine non-update
851 // wallpaper outage, we do our "wait for reset" work as a continuation,
852 // a short time in the future, specifically to allow any pending package
853 // update message on this same looper thread to be processed.
854 if (!mWallpaper.wallpaperUpdating) {
855 mContext.getMainThreadHandler().postDelayed(() -> processDisconnect(this),
856 1000);
857 }
858 }
859 }
860 }
861
Tetsutoki Shiozawa06919212018-02-02 14:18:43 +0900862 public void scheduleTimeoutLocked() {
863 // If we didn't reset it right away, do so after we couldn't connect to
864 // it for an extended amount of time to avoid having a black wallpaper.
865 final Handler fgHandler = FgThread.getHandler();
866 fgHandler.removeCallbacks(mResetRunnable);
867 fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
868 if (DEBUG_LIVE) {
869 Slog.i(TAG, "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
870 }
871 }
872
Christopher Tatec349e59f2017-05-05 17:37:43 -0700873 private void processDisconnect(final ServiceConnection connection) {
874 synchronized (mLock) {
875 // The wallpaper disappeared. If this isn't a system-default one, track
876 // crashes and fall back to default if it continues to misbehave.
877 if (connection == mWallpaper.connection) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700878 final ComponentName wpService = mWallpaper.wallpaperComponent;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800879 if (!mWallpaper.wallpaperUpdating
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700880 && mWallpaper.userId == mCurrentUserId
881 && !Objects.equals(mDefaultWallpaperComponent, wpService)
882 && !Objects.equals(mImageWallpaper, wpService)) {
Selim Cinekebebadb2014-03-05 22:17:26 +0100883 // There is a race condition which causes
884 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is
885 // currently updating since the broadcast notifying us is async.
886 // This race is overcome by the general rule that we only reset the
887 // wallpaper if its service was shut down twice
888 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
889 if (mWallpaper.lastDiedTime != 0
890 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
Christopher Tatec349e59f2017-05-05 17:37:43 -0700891 > SystemClock.uptimeMillis()) {
Selim Cinekebebadb2014-03-05 22:17:26 +0100892 Slog.w(TAG, "Reverting to built-in wallpaper!");
Christopher Tateedf7d042016-03-29 18:24:25 -0700893 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Selim Cinekebebadb2014-03-05 22:17:26 +0100894 } else {
895 mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
Adrian Roosc3f915e2016-09-06 11:40:53 -0700896
Tetsutoki Shiozawa06919212018-02-02 14:18:43 +0900897 clearWallpaperComponentLocked(mWallpaper);
898 if (bindWallpaperComponentLocked(
899 wpService, false, false, mWallpaper, null)) {
900 mWallpaper.connection.scheduleTimeoutLocked();
901 } else {
902 Slog.w(TAG, "Reverting to built-in wallpaper!");
903 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Christopher Tate2a6c55f2017-03-31 12:28:30 -0700904 }
Selim Cinekebebadb2014-03-05 22:17:26 +0100905 }
Christopher Tatec349e59f2017-05-05 17:37:43 -0700906 final String flattened = wpService.flattenToString();
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700907 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
Filip Gruszczynski5a589432014-10-14 12:06:06 -0700908 flattened.substring(0, Math.min(flattened.length(),
909 MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700910 }
Christopher Tatec349e59f2017-05-05 17:37:43 -0700911 } else {
912 if (DEBUG_LIVE) {
913 Slog.i(TAG, "Wallpaper changed during disconnect tracking; ignoring");
914 }
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700915 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700916 }
917 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800918
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700919 /**
920 * Called by a live wallpaper if its colors have changed.
921 * @param primaryColors representation of wallpaper primary colors
922 */
923 @Override
924 public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
925 int which;
926 synchronized (mLock) {
927 // Do not broadcast changes on ImageWallpaper since it's handled
928 // internally by this class.
929 if (mImageWallpaper.equals(mWallpaper.wallpaperComponent)) {
930 return;
931 }
932
933 mWallpaper.primaryColors = primaryColors;
934
935 // Live wallpapers always are system wallpapers.
936 which = FLAG_SYSTEM;
937 // It's also the lock screen wallpaper when we don't have a bitmap in there
Lucas Dupin50ba9912017-07-14 11:55:05 -0700938 WallpaperData lockedWallpaper = mLockWallpaperMap.get(mWallpaper.userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -0700939 if (lockedWallpaper == null) {
940 which |= FLAG_LOCK;
941 }
942 }
943 if (which != 0) {
944 notifyWallpaperColorsChanged(mWallpaper, which);
945 }
946 }
947
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700948 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700949 public void attachEngine(IWallpaperEngine engine) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700950 synchronized (mLock) {
951 mEngine = engine;
Michael Wright5203a8b2013-10-03 14:16:42 -0700952 if (mDimensionsChanged) {
953 try {
954 mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
955 } catch (RemoteException e) {
956 Slog.w(TAG, "Failed to set wallpaper dimensions", e);
957 }
958 mDimensionsChanged = false;
959 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700960 if (mPaddingChanged) {
961 try {
962 mEngine.setDisplayPadding(mWallpaper.padding);
963 } catch (RemoteException e) {
964 Slog.w(TAG, "Failed to set wallpaper padding", e);
965 }
966 mPaddingChanged = false;
967 }
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700968 if (mInfo != null && mInfo.getSupportsAmbientMode()) {
969 try {
Lucas Dupin660d5732017-12-19 10:05:19 -0800970 mEngine.setInAmbientMode(mInAmbientMode, false /* animated */);
Lucas Dupin7517b5d2017-08-22 12:51:25 -0700971 } catch (RemoteException e) {
972 Slog.w(TAG, "Failed to set ambient mode state", e);
973 }
974 }
Lucas Dupin50ba9912017-07-14 11:55:05 -0700975 try {
976 // This will trigger onComputeColors in the wallpaper engine.
977 // It's fine to be locked in here since the binder is oneway.
978 mEngine.requestWallpaperColors();
979 } catch (RemoteException e) {
980 Slog.w(TAG, "Failed to request wallpaper colors", e);
981 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700982 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700983 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800984
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700985 @Override
986 public void engineShown(IWallpaperEngine engine) {
987 synchronized (mLock) {
988 if (mReply != null) {
989 long ident = Binder.clearCallingIdentity();
990 try {
991 mReply.sendResult(null);
992 } catch (RemoteException e) {
993 Binder.restoreCallingIdentity(ident);
994 }
995 mReply = null;
996 }
997 }
998 }
999
1000 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001001 public ParcelFileDescriptor setWallpaper(String name) {
1002 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001003 if (mWallpaper.connection == this) {
Christopher Tatead3c2592016-01-20 18:13:17 -08001004 return updateWallpaperBitmapLocked(name, mWallpaper, null);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001005 }
1006 return null;
1007 }
1008 }
1009 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001010
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001011 class MyPackageMonitor extends PackageMonitor {
1012 @Override
1013 public void onPackageUpdateFinished(String packageName, int uid) {
1014 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001015 if (mCurrentUserId != getChangingUserId()) {
1016 return;
1017 }
1018 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1019 if (wallpaper != null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001020 final ComponentName wpService = wallpaper.wallpaperComponent;
1021 if (wpService != null && wpService.getPackageName().equals(packageName)) {
1022 if (DEBUG_LIVE) {
1023 Slog.i(TAG, "Wallpaper " + wpService + " update has finished");
1024 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001025 wallpaper.wallpaperUpdating = false;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001026 clearWallpaperComponentLocked(wallpaper);
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001027 if (!bindWallpaperComponentLocked(wpService, false, false,
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001028 wallpaper, null)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001029 Slog.w(TAG, "Wallpaper " + wpService
1030 + " no longer available; reverting to default");
Christopher Tateedf7d042016-03-29 18:24:25 -07001031 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001032 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001033 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001034 }
1035 }
1036 }
1037
1038 @Override
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001039 public void onPackageModified(String packageName) {
1040 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001041 if (mCurrentUserId != getChangingUserId()) {
1042 return;
1043 }
1044 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1045 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001046 if (wallpaper.wallpaperComponent == null
1047 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001048 return;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001049 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001050 doPackagesChangedLocked(true, wallpaper);
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001051 }
1052 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001053 }
1054
1055 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001056 public void onPackageUpdateStarted(String packageName, int uid) {
1057 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001058 if (mCurrentUserId != getChangingUserId()) {
1059 return;
1060 }
1061 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1062 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001063 if (wallpaper.wallpaperComponent != null
1064 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001065 if (DEBUG_LIVE) {
1066 Slog.i(TAG, "Wallpaper service " + wallpaper.wallpaperComponent
1067 + " is updating");
1068 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001069 wallpaper.wallpaperUpdating = true;
Adrian Roosc3f915e2016-09-06 11:40:53 -07001070 if (wallpaper.connection != null) {
1071 FgThread.getHandler().removeCallbacks(
1072 wallpaper.connection.mResetRunnable);
1073 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001074 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001075 }
1076 }
1077 }
1078
1079 @Override
1080 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001081 synchronized (mLock) {
1082 boolean changed = false;
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001083 if (mCurrentUserId != getChangingUserId()) {
1084 return false;
1085 }
1086 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1087 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001088 boolean res = doPackagesChangedLocked(doit, wallpaper);
1089 changed |= res;
1090 }
1091 return changed;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001092 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001093 }
1094
1095 @Override
1096 public void onSomePackagesChanged() {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001097 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001098 if (mCurrentUserId != getChangingUserId()) {
1099 return;
1100 }
1101 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
1102 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001103 doPackagesChangedLocked(true, wallpaper);
1104 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001105 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001106 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001107
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001108 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001109 boolean changed = false;
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001110 if (wallpaper.wallpaperComponent != null) {
1111 int change = isPackageDisappearing(wallpaper.wallpaperComponent
1112 .getPackageName());
1113 if (change == PACKAGE_PERMANENT_CHANGE
1114 || change == PACKAGE_TEMPORARY_CHANGE) {
1115 changed = true;
1116 if (doit) {
1117 Slog.w(TAG, "Wallpaper uninstalled, removing: "
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001118 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001119 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001120 }
1121 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001122 }
1123 if (wallpaper.nextWallpaperComponent != null) {
1124 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
1125 .getPackageName());
1126 if (change == PACKAGE_PERMANENT_CHANGE
1127 || change == PACKAGE_TEMPORARY_CHANGE) {
1128 wallpaper.nextWallpaperComponent = null;
1129 }
1130 }
1131 if (wallpaper.wallpaperComponent != null
1132 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
1133 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001134 mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
1135 PackageManager.MATCH_DIRECT_BOOT_AWARE
1136 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001137 } catch (NameNotFoundException e) {
1138 Slog.w(TAG, "Wallpaper component gone, removing: "
1139 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -07001140 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001141 }
1142 }
1143 if (wallpaper.nextWallpaperComponent != null
1144 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
1145 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001146 mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
1147 PackageManager.MATCH_DIRECT_BOOT_AWARE
1148 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -07001149 } catch (NameNotFoundException e) {
1150 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001151 }
1152 }
1153 return changed;
1154 }
1155 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001156
Dianne Hackborn8cc6a502009-08-05 21:29:42 -07001157 public WallpaperManagerService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001158 if (DEBUG) Slog.v(TAG, "WallpaperService startup");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 mContext = context;
Christopher Tate762dfd12016-10-10 17:44:48 -07001160 mShuttingDown = false;
Justin Koh29c30162014-09-05 17:10:10 -07001161 mImageWallpaper = ComponentName.unflattenFromString(
1162 context.getResources().getString(R.string.image_wallpaper_component));
Christopher Tate2a6c55f2017-03-31 12:28:30 -07001163 mDefaultWallpaperComponent = WallpaperManager.getDefaultWallpaperComponent(context);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001164 mIWindowManager = IWindowManager.Stub.asInterface(
1165 ServiceManager.getService(Context.WINDOW_SERVICE));
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001166 mIPackageManager = AppGlobals.getPackageManager();
Benjamin Franzf3ece362015-02-11 10:51:10 +00001167 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001168 mMonitor = new MyPackageMonitor();
Dianne Hackbornc72fc672012-09-20 13:12:03 -07001169 mMonitor.register(context, null, UserHandle.ALL, true);
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001170 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
Christopher Tatef717b932017-09-11 15:52:54 -07001171
1172 // Initialize state from the persistent store, then guarantee that the
1173 // WallpaperData for the system imagery is instantiated & active, creating
1174 // it from defaults if necessary.
Christopher Tated7faf532016-02-25 12:43:38 -08001175 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatef717b932017-09-11 15:52:54 -07001176 getWallpaperSafeLocked(UserHandle.USER_SYSTEM, FLAG_SYSTEM);
1177
Lucas Dupin50ba9912017-07-14 11:55:05 -07001178 mColorsChangedListeners = new SparseArray<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001180
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001181 private static File getWallpaperDir(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07001182 return Environment.getUserSystemDirectory(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001183 }
1184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 @Override
1186 protected void finalize() throws Throwable {
1187 super.finalize();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001188 for (int i = 0; i < mWallpaperMap.size(); i++) {
1189 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
1190 wallpaper.wallpaperObserver.stopWatching();
1191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 }
Amith Yamasani13593602012-03-22 16:16:17 -07001193
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001194 void systemReady() {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001195 if (DEBUG) Slog.v(TAG, "systemReady");
Xiaohui Chen233d94c2015-07-30 15:08:00 -07001196 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001197 // If we think we're going to be using the system image wallpaper imagery, make
1198 // sure we have something to render
1199 if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
1200 // No crop file? Make sure we've finished the processing sequence if necessary
1201 if (!wallpaper.cropExists()) {
1202 if (DEBUG) {
1203 Slog.i(TAG, "No crop; regenerating from source");
1204 }
1205 generateCrop(wallpaper);
1206 }
1207 // Still nothing? Fall back to default.
1208 if (!wallpaper.cropExists()) {
1209 if (DEBUG) {
1210 Slog.i(TAG, "Unable to regenerate crop; resetting");
1211 }
Christopher Tateedf7d042016-03-29 18:24:25 -07001212 clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
Christopher Tate2cdd3f22016-03-14 17:36:16 -07001213 }
1214 } else {
1215 if (DEBUG) {
1216 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
1217 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001218 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001219
Amith Yamasani13593602012-03-22 16:16:17 -07001220 IntentFilter userFilter = new IntentFilter();
Amith Yamasani13593602012-03-22 16:16:17 -07001221 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1222 mContext.registerReceiver(new BroadcastReceiver() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001223 @Override
Amith Yamasani13593602012-03-22 16:16:17 -07001224 public void onReceive(Context context, Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001225 final String action = intent.getAction();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001226 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani756901d2012-10-12 12:30:07 -07001227 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1228 UserHandle.USER_NULL));
Amith Yamasani13593602012-03-22 16:16:17 -07001229 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001230 }
Amith Yamasani13593602012-03-22 16:16:17 -07001231 }, userFilter);
Amith Yamasani756901d2012-10-12 12:30:07 -07001232
Christopher Tate762dfd12016-10-10 17:44:48 -07001233 final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
1234 mContext.registerReceiver(new BroadcastReceiver() {
1235 @Override
1236 public void onReceive(Context context, Intent intent) {
1237 if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
1238 if (DEBUG) {
1239 Slog.i(TAG, "Shutting down");
1240 }
1241 synchronized (mLock) {
1242 mShuttingDown = true;
1243 }
1244 }
1245 }
1246 }, shutdownFilter);
1247
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001248 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001249 ActivityManager.getService().registerUserSwitchObserver(
Sudheer Shanka2c4522c2016-08-27 20:53:28 -07001250 new UserSwitchObserver() {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001251 @Override
1252 public void onUserSwitching(int newUserId, IRemoteCallback reply) {
1253 switchUser(newUserId, reply);
1254 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001255 }, TAG);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001256 } catch (RemoteException e) {
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -07001257 e.rethrowAsRuntimeException();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001258 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001259 }
1260
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08001261 /** Called by SystemBackupAgent */
1262 public String getName() {
1263 // Verify caller is the system
1264 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
1265 throw new RuntimeException("getName() can only be called from the system process");
1266 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001267 synchronized (mLock) {
1268 return mWallpaperMap.get(0).name;
1269 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001270 }
1271
Christopher Tatebe132e62016-02-10 12:59:49 -08001272 void stopObserver(WallpaperData wallpaper) {
1273 if (wallpaper != null) {
1274 if (wallpaper.wallpaperObserver != null) {
1275 wallpaper.wallpaperObserver.stopWatching();
1276 wallpaper.wallpaperObserver = null;
Amith Yamasani13593602012-03-22 16:16:17 -07001277 }
Amith Yamasani756901d2012-10-12 12:30:07 -07001278 }
1279 }
1280
Christopher Tatebe132e62016-02-10 12:59:49 -08001281 void stopObserversLocked(int userId) {
1282 stopObserver(mWallpaperMap.get(userId));
1283 stopObserver(mLockWallpaperMap.get(userId));
1284 mWallpaperMap.remove(userId);
1285 mLockWallpaperMap.remove(userId);
1286 }
1287
Daichi Hirono4bbf8522017-12-06 10:34:18 +09001288 @Override
1289 public void onBootPhase(int phase) {
1290 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1291 systemReady();
1292 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1293 switchUser(UserHandle.USER_SYSTEM, null);
1294 }
1295 }
1296
1297 @Override
1298 public void onUnlockUser(final int userId) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001299 synchronized (mLock) {
Christopher Tate38a5dc32016-07-20 15:10:18 -07001300 if (mCurrentUserId == userId) {
1301 if (mWaitingForUnlock) {
1302 // If we're switching users, now is when we transition the wallpaper
1303 switchUser(userId, null);
1304 }
Christopher Tate190e8532016-07-11 11:35:34 -07001305
1306 // Make sure that the SELinux labeling of all the relevant files is correct.
1307 // This corrects for mislabeling bugs that might have arisen from move-to
1308 // operations involving the wallpaper files. This isn't timing-critical,
1309 // so we do it in the background to avoid holding up the user unlock operation.
Christopher Tate38a5dc32016-07-20 15:10:18 -07001310 if (mUserRestorecon.get(userId) != Boolean.TRUE) {
1311 mUserRestorecon.put(userId, Boolean.TRUE);
1312 Runnable relabeler = new Runnable() {
1313 @Override
1314 public void run() {
1315 final File wallpaperDir = getWallpaperDir(userId);
1316 for (String filename : sPerUserFiles) {
1317 File f = new File(wallpaperDir, filename);
1318 if (f.exists()) {
1319 SELinux.restorecon(f);
1320 }
Christopher Tate190e8532016-07-11 11:35:34 -07001321 }
1322 }
Christopher Tate38a5dc32016-07-20 15:10:18 -07001323 };
1324 BackgroundThread.getHandler().post(relabeler);
1325 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001326 }
1327 }
1328 }
1329
Amith Yamasani756901d2012-10-12 12:30:07 -07001330 void onRemoveUser(int userId) {
1331 if (userId < 1) return;
Christopher Tatebe132e62016-02-10 12:59:49 -08001332
1333 final File wallpaperDir = getWallpaperDir(userId);
Amith Yamasani756901d2012-10-12 12:30:07 -07001334 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001335 stopObserversLocked(userId);
1336 for (String filename : sPerUserFiles) {
1337 new File(wallpaperDir, filename).delete();
1338 }
Sudheer Shanka69f0cb52016-10-06 17:33:20 -07001339 mUserRestorecon.remove(userId);
Amith Yamasani13593602012-03-22 16:16:17 -07001340 }
1341 }
1342
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001343 void switchUser(int userId, IRemoteCallback reply) {
Lucas Dupin9272d452017-09-14 14:15:42 -07001344 final WallpaperData systemWallpaper;
1345 final WallpaperData lockWallpaper;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001346 synchronized (mLock) {
1347 mCurrentUserId = userId;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001348 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Lucas Dupin9272d452017-09-14 14:15:42 -07001349 final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
1350 lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
Lucas Dupin50ba9912017-07-14 11:55:05 -07001351 // Not started watching yet, in case wallpaper data was loaded for other reasons.
1352 if (systemWallpaper.wallpaperObserver == null) {
1353 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
1354 systemWallpaper.wallpaperObserver.startWatching();
1355 }
1356 switchWallpaper(systemWallpaper, reply);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001357 }
Lucas Dupin9272d452017-09-14 14:15:42 -07001358
1359 // Offload color extraction to another thread since switchUser will be called
1360 // from the main thread.
1361 FgThread.getHandler().post(() -> {
1362 notifyWallpaperColorsChanged(systemWallpaper, FLAG_SYSTEM);
1363 notifyWallpaperColorsChanged(lockWallpaper, FLAG_LOCK);
1364 });
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001365 }
1366
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001367 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001368 synchronized (mLock) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001369 mWaitingForUnlock = false;
1370 final ComponentName cname = wallpaper.wallpaperComponent != null ?
1371 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
1372 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
1373 // We failed to bind the desired wallpaper, but that might
1374 // happen if the wallpaper isn't direct-boot aware
1375 ServiceInfo si = null;
1376 try {
1377 si = mIPackageManager.getServiceInfo(cname,
1378 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
1379 } catch (RemoteException ignored) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001380 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001381
1382 if (si == null) {
1383 Slog.w(TAG, "Failure starting previous wallpaper; clearing");
1384 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
1385 } else {
1386 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
1387 // We might end up persisting the current wallpaper data
1388 // while locked, so pretend like the component was actually
1389 // bound into place
1390 wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
1391 final WallpaperData fallback = new WallpaperData(wallpaper.userId,
1392 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
Adrian Roosc28e3a92016-04-14 10:47:52 -07001393 ensureSaneWallpaperData(fallback);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001394 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
1395 mWaitingForUnlock = true;
1396 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001397 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001398 }
1399 }
1400
Christopher Tatebe132e62016-02-10 12:59:49 -08001401 @Override
1402 public void clearWallpaper(String callingPackage, int which, int userId) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001403 if (DEBUG) Slog.v(TAG, "clearWallpaper");
Benjamin Franzf3ece362015-02-11 10:51:10 +00001404 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tate98d609c2016-05-18 17:31:58 -07001405 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001406 return;
1407 }
Christopher Tatee409f0e2016-03-21 14:53:15 -07001408 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1409 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001410
Lucas Dupin41f69422017-05-03 15:26:22 -07001411 WallpaperData data = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001412 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001413 clearWallpaperLocked(false, which, userId, null);
Lucas Dupin41f69422017-05-03 15:26:22 -07001414
1415 if (which == FLAG_LOCK) {
1416 data = mLockWallpaperMap.get(userId);
1417 }
1418 if (which == FLAG_SYSTEM || data == null) {
1419 data = mWallpaperMap.get(userId);
1420 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001421 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001422
1423 // When clearing a wallpaper, broadcast new valid colors
Lucas Dupin41f69422017-05-03 15:26:22 -07001424 if (data != null) {
1425 notifyWallpaperColorsChanged(data, which);
1426 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001427 }
1428
Christopher Tatebe132e62016-02-10 12:59:49 -08001429 void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
Christopher Tateedf7d042016-03-29 18:24:25 -07001430 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001431 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1432 }
1433
1434 WallpaperData wallpaper = null;
Christopher Tateedf7d042016-03-29 18:24:25 -07001435 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001436 wallpaper = mLockWallpaperMap.get(userId);
1437 if (wallpaper == null) {
1438 // It's already gone; we're done.
Christopher Tate79a24572016-03-02 14:42:44 -08001439 if (DEBUG) {
1440 Slog.i(TAG, "Lock wallpaper already cleared");
1441 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001442 return;
1443 }
1444 } else {
1445 wallpaper = mWallpaperMap.get(userId);
1446 if (wallpaper == null) {
1447 // Might need to bring it in the first time to establish our rewrite
Christopher Tated7faf532016-02-25 12:43:38 -08001448 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08001449 wallpaper = mWallpaperMap.get(userId);
1450 }
1451 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001452 if (wallpaper == null) {
1453 return;
1454 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001455
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001456 final long ident = Binder.clearCallingIdentity();
1457 try {
Christopher Tatebe132e62016-02-10 12:59:49 -08001458 if (wallpaper.wallpaperFile.exists()) {
1459 wallpaper.wallpaperFile.delete();
1460 wallpaper.cropFile.delete();
Christopher Tateedf7d042016-03-29 18:24:25 -07001461 if (which == FLAG_LOCK) {
Christopher Tate79a24572016-03-02 14:42:44 -08001462 mLockWallpaperMap.remove(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001463 final IWallpaperManagerCallback cb = mKeyguardListener;
1464 if (cb != null) {
Christopher Tate79a24572016-03-02 14:42:44 -08001465 if (DEBUG) {
1466 Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
1467 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001468 try {
1469 cb.onWallpaperChanged();
1470 } catch (RemoteException e) {
1471 // Oh well it went away; no big deal
1472 }
1473 }
Christopher Tate79a24572016-03-02 14:42:44 -08001474 saveSettingsLocked(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001475 return;
1476 }
1477 }
1478
Christopher Tateecd827a2014-09-05 17:42:34 -07001479 RuntimeException e = null;
1480 try {
Lucas Dupin75ec3792017-06-29 14:07:18 -07001481 wallpaper.primaryColors = null;
Christopher Tateecd827a2014-09-05 17:42:34 -07001482 wallpaper.imageWallpaperPending = false;
1483 if (userId != mCurrentUserId) return;
1484 if (bindWallpaperComponentLocked(defaultFailed
1485 ? mImageWallpaper
1486 : null, true, false, wallpaper, reply)) {
1487 return;
1488 }
1489 } catch (IllegalArgumentException e1) {
1490 e = e1;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001491 }
Christopher Tateecd827a2014-09-05 17:42:34 -07001492
1493 // This can happen if the default wallpaper component doesn't
1494 // exist. This should be a system configuration problem, but
1495 // let's not let it crash the system and just live with no
1496 // wallpaper.
1497 Slog.e(TAG, "Default wallpaper component not found!", e);
1498 clearWallpaperComponentLocked(wallpaper);
1499 if (reply != null) {
1500 try {
1501 reply.sendResult(null);
1502 } catch (RemoteException e1) {
1503 }
1504 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001505 } finally {
1506 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001508 }
1509
1510 public boolean hasNamedWallpaper(String name) {
1511 synchronized (mLock) {
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001512 List<UserInfo> users;
1513 long ident = Binder.clearCallingIdentity();
1514 try {
1515 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
1516 } finally {
1517 Binder.restoreCallingIdentity(ident);
1518 }
1519 for (UserInfo user: users) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001520 // ignore managed profiles
1521 if (user.isManagedProfile()) {
1522 continue;
1523 }
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001524 WallpaperData wd = mWallpaperMap.get(user.id);
1525 if (wd == null) {
1526 // User hasn't started yet, so load her settings to peek at the wallpaper
Christopher Tated7faf532016-02-25 12:43:38 -08001527 loadSettingsLocked(user.id, false);
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001528 wd = mWallpaperMap.get(user.id);
1529 }
1530 if (wd != null && name.equals(wd.name)) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001531 return true;
1532 }
1533 }
1534 }
1535 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 }
1537
John Spurlock41f64642013-11-04 13:48:38 -05001538 private Point getDefaultDisplaySize() {
1539 Point p = new Point();
John Spurlockd6e836c2013-11-18 14:14:49 -05001540 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1541 Display d = wm.getDefaultDisplay();
1542 d.getRealSize(p);
John Spurlock41f64642013-11-04 13:48:38 -05001543 return p;
1544 }
1545
Benjamin Franzf3ece362015-02-11 10:51:10 +00001546 public void setDimensionHints(int width, int height, String callingPackage)
1547 throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001549 if (!isWallpaperSupported(callingPackage)) {
1550 return;
1551 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001552 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001553 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001554 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001555 if (width <= 0 || height <= 0) {
1556 throw new IllegalArgumentException("width and height must be > 0");
1557 }
John Spurlock41f64642013-11-04 13:48:38 -05001558 // Make sure it is at least as large as the display.
1559 Point displaySize = getDefaultDisplaySize();
1560 width = Math.max(width, displaySize.x);
1561 height = Math.max(height, displaySize.y);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001562
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001563 if (width != wallpaper.width || height != wallpaper.height) {
1564 wallpaper.width = width;
1565 wallpaper.height = height;
Christopher Tatedb27b842016-02-25 14:39:17 -08001566 saveSettingsLocked(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001567 if (mCurrentUserId != userId) return; // Don't change the properties now
1568 if (wallpaper.connection != null) {
1569 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001570 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001571 wallpaper.connection.mEngine.setDesiredSize(
Dianne Hackborn284ac932009-08-28 10:34:25 -07001572 width, height);
1573 } catch (RemoteException e) {
1574 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001575 notifyCallbacksLocked(wallpaper);
Michael Wright5203a8b2013-10-03 14:16:42 -07001576 } else if (wallpaper.connection.mService != null) {
1577 // We've attached to the service but the engine hasn't attached back to us
1578 // yet. This means it will be created with the previous dimensions, so we
1579 // need to update it to the new dimensions once it attaches.
1580 wallpaper.connection.mDimensionsChanged = true;
Dianne Hackborn284ac932009-08-28 10:34:25 -07001581 }
1582 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
1585 }
1586
1587 public int getWidthHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001588 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001589 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001590 if (wallpaper != null) {
1591 return wallpaper.width;
1592 } else {
1593 return 0;
1594 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596 }
1597
1598 public int getHeightHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001599 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001600 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001601 if (wallpaper != null) {
1602 return wallpaper.height;
1603 } else {
1604 return 0;
1605 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608
Benjamin Franzf3ece362015-02-11 10:51:10 +00001609 public void setDisplayPadding(Rect padding, String callingPackage) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001610 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001611 if (!isWallpaperSupported(callingPackage)) {
1612 return;
1613 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001614 synchronized (mLock) {
1615 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001616 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001617 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
1618 throw new IllegalArgumentException("padding must be positive: " + padding);
1619 }
1620
1621 if (!padding.equals(wallpaper.padding)) {
1622 wallpaper.padding.set(padding);
Christopher Tatedb27b842016-02-25 14:39:17 -08001623 saveSettingsLocked(userId);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001624 if (mCurrentUserId != userId) return; // Don't change the properties now
1625 if (wallpaper.connection != null) {
1626 if (wallpaper.connection.mEngine != null) {
1627 try {
1628 wallpaper.connection.mEngine.setDisplayPadding(padding);
1629 } catch (RemoteException e) {
1630 }
1631 notifyCallbacksLocked(wallpaper);
1632 } else if (wallpaper.connection.mService != null) {
1633 // We've attached to the service but the engine hasn't attached back to us
1634 // yet. This means it will be created with the previous dimensions, so we
1635 // need to update it to the new dimensions once it attaches.
1636 wallpaper.connection.mPaddingChanged = true;
1637 }
1638 }
1639 }
1640 }
1641 }
1642
Christopher Tate93252de2017-06-15 14:48:41 -07001643 private void enforceCallingOrSelfPermissionAndAppOp(String permission, final String callingPkg,
1644 final int callingUid, String message) {
1645 mContext.enforceCallingOrSelfPermission(permission, message);
1646
1647 final String opName = AppOpsManager.permissionToOp(permission);
1648 if (opName != null) {
1649 final int appOpMode = mAppOpsManager.noteOp(opName, callingUid, callingPkg);
1650 if (appOpMode != AppOpsManager.MODE_ALLOWED) {
1651 throw new SecurityException(
1652 message + ": " + callingPkg + " is not allowed to " + permission);
1653 }
1654 }
1655 }
1656
Yorke Leedcd93cc2016-01-08 14:12:55 -08001657 @Override
Christopher Tate93252de2017-06-15 14:48:41 -07001658 public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
1659 final int which, Bundle outParams, int wallpaperUserId) {
Christopher Tate8a71c482017-08-14 16:45:03 -07001660 final int hasPrivilege = mContext.checkCallingOrSelfPermission(
1661 android.Manifest.permission.READ_WALLPAPER_INTERNAL);
1662 if (hasPrivilege != PackageManager.PERMISSION_GRANTED) {
1663 enforceCallingOrSelfPermissionAndAppOp(android.Manifest.permission.READ_EXTERNAL_STORAGE,
1664 callingPkg, Binder.getCallingUid(), "read wallpaper");
1665 }
Christopher Tate93252de2017-06-15 14:48:41 -07001666
Christopher Tatee409f0e2016-03-21 14:53:15 -07001667 wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1668 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001669
Christopher Tateedf7d042016-03-29 18:24:25 -07001670 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001671 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1672 }
1673
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001674 synchronized (mLock) {
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001675 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07001676 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001677 WallpaperData wallpaper = whichSet.get(wallpaperUserId);
1678 if (wallpaper == null) {
Christopher Tatef717b932017-09-11 15:52:54 -07001679 // There is no established wallpaper imagery of this type (expected
1680 // only for lock wallpapers; a system WallpaperData is established at
1681 // user switch)
1682 return null;
Benjamin Franzf3ece362015-02-11 10:51:10 +00001683 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001684 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001685 if (outParams != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001686 outParams.putInt("width", wallpaper.width);
1687 outParams.putInt("height", wallpaper.height);
Dianne Hackborn284ac932009-08-28 10:34:25 -07001688 }
Christopher Tateea6724a2016-02-18 18:39:19 -08001689 if (cb != null) {
1690 wallpaper.callbacks.register(cb);
1691 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001692 if (!wallpaper.cropFile.exists()) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001693 return null;
1694 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001695 return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001696 } catch (FileNotFoundException e) {
1697 /* Shouldn't happen as we check to see if the file exists */
Joe Onorato8a9b2202010-02-26 18:56:32 -08001698 Slog.w(TAG, "Error getting wallpaper", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001700 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 }
1703
Christopher Tatee409f0e2016-03-21 14:53:15 -07001704 @Override
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001705 public WallpaperInfo getWallpaperInfo(int userId) {
1706 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Christopher Tatef717b932017-09-11 15:52:54 -07001707 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null);
Dianne Hackborneb034652009-09-07 00:49:58 -07001708 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001709 WallpaperData wallpaper = mWallpaperMap.get(userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001710 if (wallpaper != null && wallpaper.connection != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001711 return wallpaper.connection.mInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -07001712 }
1713 return null;
1714 }
1715 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001716
Christopher Tatead3c2592016-01-20 18:13:17 -08001717 @Override
Christopher Tatee409f0e2016-03-21 14:53:15 -07001718 public int getWallpaperIdForUser(int which, int userId) {
1719 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1720 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
1721
Christopher Tateedf7d042016-03-29 18:24:25 -07001722 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001723 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
1724 }
1725
1726 final SparseArray<WallpaperData> map =
Christopher Tateedf7d042016-03-29 18:24:25 -07001727 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatee409f0e2016-03-21 14:53:15 -07001728 synchronized (mLock) {
1729 WallpaperData wallpaper = map.get(userId);
1730 if (wallpaper != null) {
1731 return wallpaper.wallpaperId;
1732 }
1733 }
1734 return -1;
1735 }
1736
1737 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001738 public void registerWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
1739 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1740 userId, true, true, "registerWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001741 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001742 RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
1743 mColorsChangedListeners.get(userId);
1744 if (userColorsChangedListeners == null) {
1745 userColorsChangedListeners = new RemoteCallbackList<>();
1746 mColorsChangedListeners.put(userId, userColorsChangedListeners);
1747 }
1748 userColorsChangedListeners.register(cb);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001749 }
1750 }
1751
1752 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001753 public void unregisterWallpaperColorsCallback(IWallpaperManagerCallback cb, int userId) {
1754 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1755 userId, true, true, "unregisterWallpaperColorsCallback", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001756 synchronized (mLock) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001757 final RemoteCallbackList<IWallpaperManagerCallback> userColorsChangedListeners =
1758 mColorsChangedListeners.get(userId);
1759 if (userColorsChangedListeners != null) {
1760 userColorsChangedListeners.unregister(cb);
1761 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001762 }
1763 }
1764
Lucas Dupin660d5732017-12-19 10:05:19 -08001765 public void setInAmbientMode(boolean inAmbienMode, boolean animated) {
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001766 final IWallpaperEngine engine;
1767 synchronized (mLock) {
1768 mInAmbientMode = inAmbienMode;
1769 final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
1770 if (data != null && data.connection != null && data.connection.mInfo != null
1771 && data.connection.mInfo.getSupportsAmbientMode()) {
1772 engine = data.connection.mEngine;
1773 } else {
1774 engine = null;
1775 }
1776 }
1777
1778 if (engine != null) {
1779 try {
Lucas Dupin660d5732017-12-19 10:05:19 -08001780 engine.setInAmbientMode(inAmbienMode, animated);
Lucas Dupin7517b5d2017-08-22 12:51:25 -07001781 } catch (RemoteException e) {
1782 // Cannot talk to wallpaper engine.
1783 }
1784 }
1785 }
1786
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001787 @Override
Christopher Tatebe132e62016-02-10 12:59:49 -08001788 public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
1789 checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
1790 synchronized (mLock) {
1791 mKeyguardListener = cb;
1792 }
1793 return true;
1794 }
1795
1796 @Override
Lucas Dupin50ba9912017-07-14 11:55:05 -07001797 public WallpaperColors getWallpaperColors(int which, int userId) throws RemoteException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001798 if (which != FLAG_LOCK && which != FLAG_SYSTEM) {
1799 throw new IllegalArgumentException("which should be either FLAG_LOCK or FLAG_SYSTEM");
1800 }
Lucas Dupin50ba9912017-07-14 11:55:05 -07001801 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1802 userId, false, true, "getWallpaperColors", null);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001803
1804 WallpaperData wallpaperData = null;
1805 boolean shouldExtract;
1806
1807 synchronized (mLock) {
1808 if (which == FLAG_LOCK) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001809 wallpaperData = mLockWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001810 }
1811
1812 // Try to get the system wallpaper anyway since it might
1813 // also be the lock screen wallpaper
1814 if (wallpaperData == null) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07001815 wallpaperData = mWallpaperMap.get(userId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001816 }
1817
1818 if (wallpaperData == null) {
1819 return null;
1820 }
1821 shouldExtract = wallpaperData.primaryColors == null;
1822 }
1823
1824 if (shouldExtract) {
1825 extractColors(wallpaperData);
1826 }
1827
1828 synchronized (mLock) {
1829 return wallpaperData.primaryColors;
1830 }
1831 }
1832
1833 @Override
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001834 public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Christopher Tated7faf532016-02-25 12:43:38 -08001835 Rect cropHint, boolean allowBackup, Bundle extras, int which,
Jorim Jaggi6c902d02016-08-18 10:44:54 -07001836 IWallpaperManagerCallback completion, int userId) {
1837 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
1838 false /* all */, true /* full */, "changing wallpaper", null /* pkg */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tatead3c2592016-01-20 18:13:17 -08001840
Christopher Tateedf7d042016-03-29 18:24:25 -07001841 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001842 final String msg = "Must specify a valid wallpaper category to set";
1843 Slog.e(TAG, msg);
1844 throw new IllegalArgumentException(msg);
Christopher Tatead3c2592016-01-20 18:13:17 -08001845 }
1846
Christopher Tate98d609c2016-05-18 17:31:58 -07001847 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001848 return null;
1849 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001850
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001851 // "null" means the no-op crop, preserving the full input image
1852 if (cropHint == null) {
1853 cropHint = new Rect(0, 0, 0, 0);
1854 } else {
1855 if (cropHint.isEmpty()
1856 || cropHint.left < 0
1857 || cropHint.top < 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001858 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001859 }
1860 }
1861
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001862 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001863 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
1864 WallpaperData wallpaper;
1865
Christopher Tate8347b632016-04-29 18:59:18 -07001866 /* If we're setting system but not lock, and lock is currently sharing the system
1867 * wallpaper, we need to migrate that image over to being lock-only before
1868 * the caller here writes new bitmap data.
1869 */
1870 if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
1871 if (DEBUG) {
1872 Slog.i(TAG, "Migrating system->lock to preserve");
1873 }
1874 migrateSystemToLockWallpaperLocked(userId);
1875 }
1876
Christopher Tatebe132e62016-02-10 12:59:49 -08001877 wallpaper = getWallpaperSafeLocked(userId, which);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001878 final long ident = Binder.clearCallingIdentity();
1879 try {
Christopher Tatead3c2592016-01-20 18:13:17 -08001880 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001881 if (pfd != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001882 wallpaper.imageWallpaperPending = true;
Christopher Tatebe132e62016-02-10 12:59:49 -08001883 wallpaper.whichPending = which;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001884 wallpaper.setComplete = completion;
1885 wallpaper.cropHint.set(cropHint);
Christopher Tatec613c632016-08-12 14:13:02 -07001886 wallpaper.allowBackup = allowBackup;
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001887 }
1888 return pfd;
1889 } finally {
1890 Binder.restoreCallingIdentity(ident);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 }
1893 }
1894
Christopher Tate8347b632016-04-29 18:59:18 -07001895 private void migrateSystemToLockWallpaperLocked(int userId) {
1896 WallpaperData sysWP = mWallpaperMap.get(userId);
1897 if (sysWP == null) {
1898 if (DEBUG) {
1899 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
1900 }
1901 return;
1902 }
1903
1904 // We know a-priori that there is no lock-only wallpaper currently
1905 WallpaperData lockWP = new WallpaperData(userId,
1906 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
1907 lockWP.wallpaperId = sysWP.wallpaperId;
1908 lockWP.cropHint.set(sysWP.cropHint);
1909 lockWP.width = sysWP.width;
1910 lockWP.height = sysWP.height;
Christopher Tateedd8dc82016-10-12 15:17:58 -07001911 lockWP.allowBackup = sysWP.allowBackup;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001912 lockWP.primaryColors = sysWP.primaryColors;
Christopher Tate8347b632016-04-29 18:59:18 -07001913
1914 // Migrate the bitmap files outright; no need to copy
1915 try {
1916 Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
1917 Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
1918 } catch (ErrnoException e) {
1919 Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
1920 lockWP.wallpaperFile.delete();
1921 lockWP.cropFile.delete();
1922 return;
1923 }
1924
1925 mLockWallpaperMap.put(userId, lockWP);
1926 }
1927
Christopher Tatead3c2592016-01-20 18:13:17 -08001928 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
1929 Bundle extras) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001930 if (name == null) name = "";
1931 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001932 File dir = getWallpaperDir(wallpaper.userId);
1933 if (!dir.exists()) {
1934 dir.mkdir();
Dianne Hackbornebac48c2011-11-29 18:01:50 -08001935 FileUtils.setPermissions(
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001936 dir.getPath(),
Dianne Hackbornebac48c2011-11-29 18:01:50 -08001937 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1938 -1, -1);
1939 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001940 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
Christopher Tate90f86ba2014-09-11 12:37:19 -07001941 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
Christopher Tatebe132e62016-02-10 12:59:49 -08001942 if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
rpcraig554cb0c2012-07-05 06:41:43 -04001943 return null;
1944 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001945 wallpaper.name = name;
Christopher Tatead3c2592016-01-20 18:13:17 -08001946 wallpaper.wallpaperId = makeWallpaperIdLocked();
1947 if (extras != null) {
1948 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
1949 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001950 // Nullify field to require new computation
1951 wallpaper.primaryColors = null;
Christopher Tatead3c2592016-01-20 18:13:17 -08001952 if (DEBUG) {
1953 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
Christopher Tatebe132e62016-02-10 12:59:49 -08001954 + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
Christopher Tatead3c2592016-01-20 18:13:17 -08001955 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001956 return fd;
1957 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001958 Slog.w(TAG, "Error setting wallpaper", e);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001959 }
1960 return null;
1961 }
1962
Christopher Tated57d17c2016-03-25 13:41:46 -07001963 @Override
Adrian Roos40ea0832016-07-14 14:19:55 -07001964 public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
1965 int userId) {
1966
Christopher Tate98d609c2016-05-18 17:31:58 -07001967 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001968 setWallpaperComponent(name, userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001969 }
1970 }
1971
1972 // ToDo: Remove this version of the function
Christopher Tated57d17c2016-03-25 13:41:46 -07001973 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001974 public void setWallpaperComponent(ComponentName name) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001975 setWallpaperComponent(name, UserHandle.getCallingUserId());
1976 }
1977
1978 private void setWallpaperComponent(ComponentName name, int userId) {
1979 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
1980 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001981 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
Adrian Roos40ea0832016-07-14 14:19:55 -07001982
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001983 int which = FLAG_SYSTEM;
1984 boolean shouldNotifyColors = false;
1985 WallpaperData wallpaper;
1986
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001987 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001988 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07001989 wallpaper = mWallpaperMap.get(userId);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001990 if (wallpaper == null) {
1991 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
1992 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001993 final long ident = Binder.clearCallingIdentity();
Christopher Tate7cd00102016-12-19 14:38:44 -08001994
1995 // Live wallpapers can't be specified for keyguard. If we're using a static
1996 // system+lock image currently, migrate the system wallpaper to be a lock-only
1997 // image as part of making a different live component active as the system
1998 // wallpaper.
1999 if (mImageWallpaper.equals(wallpaper.wallpaperComponent)) {
2000 if (mLockWallpaperMap.get(userId) == null) {
2001 // We're using the static imagery and there is no lock-specific image in place,
2002 // therefore it's a shared system+lock image that we need to migrate.
2003 migrateSystemToLockWallpaperLocked(userId);
2004 }
2005 }
2006
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002007 // New live wallpaper is also a lock wallpaper if nothing is set
2008 if (mLockWallpaperMap.get(userId) == null) {
2009 which |= FLAG_LOCK;
2010 }
2011
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002012 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002013 wallpaper.imageWallpaperPending = false;
Lucas Dupin50ba9912017-07-14 11:55:05 -07002014 boolean same = changingToSame(name, wallpaper);
Christopher Tated57d17c2016-03-25 13:41:46 -07002015 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
Lucas Dupin50ba9912017-07-14 11:55:05 -07002016 if (!same) {
2017 wallpaper.primaryColors = null;
2018 }
Christopher Tated57d17c2016-03-25 13:41:46 -07002019 wallpaper.wallpaperId = makeWallpaperIdLocked();
Sunny Goyal0572e182016-03-31 11:05:51 -07002020 notifyCallbacksLocked(wallpaper);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002021 shouldNotifyColors = true;
Christopher Tated57d17c2016-03-25 13:41:46 -07002022 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002023 } finally {
2024 Binder.restoreCallingIdentity(ident);
2025 }
2026 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002027
2028 if (shouldNotifyColors) {
2029 notifyWallpaperColorsChanged(wallpaper, which);
2030 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002031 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002032
Lucas Dupin50ba9912017-07-14 11:55:05 -07002033 private boolean changingToSame(ComponentName componentName, WallpaperData wallpaper) {
2034 if (wallpaper.connection != null) {
2035 if (wallpaper.wallpaperComponent == null) {
2036 if (componentName == null) {
2037 if (DEBUG) Slog.v(TAG, "changingToSame: still using default");
2038 // Still using default wallpaper.
2039 return true;
2040 }
2041 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
2042 // Changing to same wallpaper.
2043 if (DEBUG) Slog.v(TAG, "same wallpaper");
2044 return true;
2045 }
2046 }
2047 return false;
2048 }
2049
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002050 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002051 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002052 if (DEBUG_LIVE) {
2053 Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
2054 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002055 // Has the component changed?
Lucas Dupin50ba9912017-07-14 11:55:05 -07002056 if (!force && changingToSame(componentName, wallpaper)) {
2057 return true;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002058 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002059
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002060 try {
Mike Clerona428b2c2009-11-15 22:53:08 -08002061 if (componentName == null) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002062 componentName = mDefaultWallpaperComponent;
Mike Clerona428b2c2009-11-15 22:53:08 -08002063 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -08002064 // Fall back to static image wallpaper
Justin Koh29c30162014-09-05 17:10:10 -07002065 componentName = mImageWallpaper;
Mike Cleron322b6ee2009-11-12 07:45:47 -08002066 //clearWallpaperComponentLocked();
2067 //return;
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002068 if (DEBUG_LIVE) Slog.v(TAG, "No default component; using image wallpaper");
Mike Cleron322b6ee2009-11-12 07:45:47 -08002069 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002070 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002071 int serviceUserId = wallpaper.userId;
2072 ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
2073 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
Christopher Tate90952202013-09-08 13:01:28 -07002074 if (si == null) {
2075 // The wallpaper component we're trying to use doesn't exist
2076 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
2077 return false;
2078 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002079 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002080 String msg = "Selected service does not require "
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002081 + android.Manifest.permission.BIND_WALLPAPER
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002082 + ": " + componentName;
2083 if (fromUser) {
2084 throw new SecurityException(msg);
2085 }
2086 Slog.w(TAG, msg);
2087 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002088 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002089
Dianne Hackborneb034652009-09-07 00:49:58 -07002090 WallpaperInfo wi = null;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002091
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002092 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
Justin Koh29c30162014-09-05 17:10:10 -07002093 if (componentName != null && !componentName.equals(mImageWallpaper)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002094 // Make sure the selected service is actually a wallpaper service.
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002095 List<ResolveInfo> ris =
2096 mIPackageManager.queryIntentServices(intent,
2097 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
Jeff Sharkeyd5896632016-03-04 16:16:00 -07002098 PackageManager.GET_META_DATA, serviceUserId).getList();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002099 for (int i=0; i<ris.size(); i++) {
2100 ServiceInfo rsi = ris.get(i).serviceInfo;
2101 if (rsi.name.equals(si.name) &&
2102 rsi.packageName.equals(si.packageName)) {
Dianne Hackborneb034652009-09-07 00:49:58 -07002103 try {
2104 wi = new WallpaperInfo(mContext, ris.get(i));
2105 } catch (XmlPullParserException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002106 if (fromUser) {
2107 throw new IllegalArgumentException(e);
2108 }
2109 Slog.w(TAG, e);
2110 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002111 } catch (IOException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002112 if (fromUser) {
2113 throw new IllegalArgumentException(e);
2114 }
2115 Slog.w(TAG, e);
2116 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07002117 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002118 break;
2119 }
2120 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002121 if (wi == null) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002122 String msg = "Selected service is not a wallpaper: "
2123 + componentName;
2124 if (fromUser) {
2125 throw new SecurityException(msg);
2126 }
2127 Slog.w(TAG, msg);
2128 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002129 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002130 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002131
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002132 // Bind the service!
Joe Onorato8a9b2202010-02-26 18:56:32 -08002133 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002134 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002135 intent.setComponent(componentName);
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07002136 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
2137 com.android.internal.R.string.wallpaper_binding_label);
Dianne Hackborn41203752012-08-31 14:05:51 -07002138 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
Dianne Hackborneb034652009-09-07 00:49:58 -07002139 mContext, 0,
2140 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
2141 mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
Dianne Hackborn41203752012-08-31 14:05:51 -07002142 0, null, new UserHandle(serviceUserId)));
Dianne Hackbornc8230512013-07-13 21:32:12 -07002143 if (!mContext.bindServiceAsUser(intent, newConn,
Dianne Hackbornd69e4c12015-04-24 09:54:54 -07002144 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
2145 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
Amith Yamasani27b89e62013-01-16 12:30:11 -08002146 new UserHandle(serviceUserId))) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002147 String msg = "Unable to bind service: "
2148 + componentName;
2149 if (fromUser) {
2150 throw new IllegalArgumentException(msg);
2151 }
2152 Slog.w(TAG, msg);
2153 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002154 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002155 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
2156 detachWallpaperLocked(mLastWallpaper);
2157 }
2158 wallpaper.wallpaperComponent = componentName;
2159 wallpaper.connection = newConn;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002160 newConn.mReply = reply;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002161 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002162 if (wallpaper.userId == mCurrentUserId) {
2163 if (DEBUG)
2164 Slog.v(TAG, "Adding window token: " + newConn.mToken);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002165 mIWindowManager.addWindowToken(newConn.mToken, TYPE_WALLPAPER, DEFAULT_DISPLAY);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002166 mLastWallpaper = wallpaper;
2167 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07002168 } catch (RemoteException e) {
2169 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07002170 } catch (RemoteException e) {
2171 String msg = "Remote exception for " + componentName + "\n" + e;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002172 if (fromUser) {
2173 throw new IllegalArgumentException(msg);
2174 }
2175 Slog.w(TAG, msg);
2176 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002177 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07002178 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002179 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002180
2181 void detachWallpaperLocked(WallpaperData wallpaper) {
2182 if (wallpaper.connection != null) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002183 if (wallpaper.connection.mReply != null) {
2184 try {
2185 wallpaper.connection.mReply.sendResult(null);
2186 } catch (RemoteException e) {
2187 }
2188 wallpaper.connection.mReply = null;
2189 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002190 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002191 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002192 wallpaper.connection.mEngine.destroy();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002193 } catch (RemoteException e) {
2194 }
2195 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002196 mContext.unbindService(wallpaper.connection);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07002197 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002198 if (DEBUG)
2199 Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002200 mIWindowManager.removeWindowToken(wallpaper.connection.mToken, DEFAULT_DISPLAY);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07002201 } catch (RemoteException e) {
2202 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002203 wallpaper.connection.mService = null;
2204 wallpaper.connection.mEngine = null;
2205 wallpaper.connection = null;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002206 }
2207 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002208
2209 void clearWallpaperComponentLocked(WallpaperData wallpaper) {
2210 wallpaper.wallpaperComponent = null;
2211 detachWallpaperLocked(wallpaper);
2212 }
2213
2214 void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002215 try {
Dianne Hackborn3be63c02009-08-20 19:31:38 -07002216 conn.mService.attach(conn, conn.mToken,
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07002217 TYPE_WALLPAPER, false,
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002218 wallpaper.width, wallpaper.height, wallpaper.padding);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002219 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002220 Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002221 if (!wallpaper.wallpaperUpdating) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002222 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08002223 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002224 }
2225 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002226
2227 private void notifyCallbacksLocked(WallpaperData wallpaper) {
2228 final int n = wallpaper.callbacks.beginBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 for (int i = 0; i < n; i++) {
2230 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002231 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 } catch (RemoteException e) {
2233
2234 // The RemoteCallbackList will take care of removing
2235 // the dead object for us.
2236 }
2237 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002238 wallpaper.callbacks.finishBroadcast();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002241 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 }
2243
2244 private void checkPermission(String permission) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002245 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
2247 + ", must have permission " + permission);
2248 }
2249 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002250
Benjamin Franzf3ece362015-02-11 10:51:10 +00002251 /**
2252 * Certain user types do not support wallpapers (e.g. managed profiles). The check is
2253 * implemented through through the OP_WRITE_WALLPAPER AppOp.
2254 */
2255 public boolean isWallpaperSupported(String callingPackage) {
2256 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
2257 callingPackage) == AppOpsManager.MODE_ALLOWED;
2258 }
2259
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002260 @Override
Christopher Tate98d609c2016-05-18 17:31:58 -07002261 public boolean isSetWallpaperAllowed(String callingPackage) {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002262 final PackageManager pm = mContext.getPackageManager();
2263 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
2264 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
2265 if (!uidMatchPackage) {
2266 return false; // callingPackage was faked.
2267 }
2268
2269 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
2270 if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
2271 return true;
2272 }
2273 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
2274 return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
2275 }
2276
Christopher Tated7faf532016-02-25 12:43:38 -08002277 @Override
Christopher Tate61722662016-08-10 16:13:14 -07002278 public boolean isWallpaperBackupEligible(int which, int userId) {
Christopher Tated7faf532016-02-25 12:43:38 -08002279 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
2280 throw new SecurityException("Only the system may call isWallpaperBackupEligible");
2281 }
2282
Christopher Tate61722662016-08-10 16:13:14 -07002283 WallpaperData wallpaper = (which == FLAG_LOCK)
Christopher Tatef7d1b5d2016-08-19 11:21:07 -07002284 ? mLockWallpaperMap.get(userId)
2285 : mWallpaperMap.get(userId);
Christopher Tated7faf532016-02-25 12:43:38 -08002286 return (wallpaper != null) ? wallpaper.allowBackup : false;
2287 }
2288
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002289 private static JournaledFile makeJournaledFile(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07002290 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002291 return new JournaledFile(new File(base), new File(base + ".tmp"));
2292 }
2293
Christopher Tatedb27b842016-02-25 14:39:17 -08002294 private void saveSettingsLocked(int userId) {
2295 JournaledFile journal = makeJournaledFile(userId);
2296 FileOutputStream fstream = null;
2297 BufferedOutputStream stream = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002298 try {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002299 XmlSerializer out = new FastXmlSerializer();
Christopher Tatedb27b842016-02-25 14:39:17 -08002300 fstream = new FileOutputStream(journal.chooseForWrite(), false);
2301 stream = new BufferedOutputStream(fstream);
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002302 out.setOutput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002303 out.startDocument(null, true);
2304
Christopher Tatedb27b842016-02-25 14:39:17 -08002305 WallpaperData wallpaper;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002306
Christopher Tatedb27b842016-02-25 14:39:17 -08002307 wallpaper = mWallpaperMap.get(userId);
2308 if (wallpaper != null) {
2309 writeWallpaperAttributes(out, "wp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002310 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002311 wallpaper = mLockWallpaperMap.get(userId);
2312 if (wallpaper != null) {
2313 writeWallpaperAttributes(out, "kwp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002314 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002315
2316 out.endDocument();
Christopher Tatedb27b842016-02-25 14:39:17 -08002317
2318 stream.flush(); // also flushes fstream
2319 FileUtils.sync(fstream);
2320 stream.close(); // also closes fstream
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002321 journal.commit();
2322 } catch (IOException e) {
Christopher Tatead3c2592016-01-20 18:13:17 -08002323 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002324 journal.rollback();
2325 }
2326 }
2327
Christopher Tatedb27b842016-02-25 14:39:17 -08002328 private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
2329 throws IllegalArgumentException, IllegalStateException, IOException {
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002330 if (DEBUG) {
Christopher Tatef717b932017-09-11 15:52:54 -07002331 Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002332 }
Christopher Tatedb27b842016-02-25 14:39:17 -08002333 out.startTag(null, tag);
2334 out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
2335 out.attribute(null, "width", Integer.toString(wallpaper.width));
2336 out.attribute(null, "height", Integer.toString(wallpaper.height));
2337
2338 out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
2339 out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
2340 out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
2341 out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
2342
2343 if (wallpaper.padding.left != 0) {
2344 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
2345 }
2346 if (wallpaper.padding.top != 0) {
2347 out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
2348 }
2349 if (wallpaper.padding.right != 0) {
2350 out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
2351 }
2352 if (wallpaper.padding.bottom != 0) {
2353 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
2354 }
2355
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002356 if (wallpaper.primaryColors != null) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002357 int colorsCount = wallpaper.primaryColors.getMainColors().size();
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002358 out.attribute(null, "colorsCount", Integer.toString(colorsCount));
2359 if (colorsCount > 0) {
2360 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002361 final Color wc = wallpaper.primaryColors.getMainColors().get(i);
2362 out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002363 }
2364 }
Lucas Dupin75ec3792017-06-29 14:07:18 -07002365 out.attribute(null, "colorHints",
Lucas Dupin84b89d92017-05-09 12:16:19 -07002366 Integer.toString(wallpaper.primaryColors.getColorHints()));
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002367 }
2368
Christopher Tatedb27b842016-02-25 14:39:17 -08002369 out.attribute(null, "name", wallpaper.name);
2370 if (wallpaper.wallpaperComponent != null
2371 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
2372 out.attribute(null, "component",
2373 wallpaper.wallpaperComponent.flattenToShortString());
2374 }
Christopher Tated7faf532016-02-25 12:43:38 -08002375
2376 if (wallpaper.allowBackup) {
2377 out.attribute(null, "backup", "true");
2378 }
2379
Christopher Tatedb27b842016-02-25 14:39:17 -08002380 out.endTag(null, tag);
2381 }
2382
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002383 private void migrateFromOld() {
Christopher Tate9f224432017-08-01 16:32:49 -07002384 // Pre-N, what existed is the one we're now using as the display crop
2385 File preNWallpaper = new File(getWallpaperDir(0), WALLPAPER_CROP);
2386 // In the very-long-ago, imagery lived with the settings app
2387 File originalWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
2388 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
2389
2390 // Migrations from earlier wallpaper image storage schemas
2391 if (preNWallpaper.exists()) {
2392 if (!newWallpaper.exists()) {
2393 // we've got the 'wallpaper' crop file but not the nominal source image,
2394 // so do the simple "just take everything" straight copy of legacy data
2395 if (DEBUG) {
2396 Slog.i(TAG, "Migrating wallpaper schema");
2397 }
2398 FileUtils.copyFile(preNWallpaper, newWallpaper);
2399 } // else we're in the usual modern case: both source & crop exist
2400 } else if (originalWallpaper.exists()) {
2401 // VERY old schema; make sure things exist and are in the right place
2402 if (DEBUG) {
2403 Slog.i(TAG, "Migrating antique wallpaper schema");
2404 }
2405 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
2406 if (oldInfo.exists()) {
2407 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
2408 oldInfo.renameTo(newInfo);
2409 }
2410
2411 FileUtils.copyFile(originalWallpaper, preNWallpaper);
2412 originalWallpaper.renameTo(newWallpaper);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002413 }
2414 }
2415
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002416 private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
2417 String value = parser.getAttributeValue(null, name);
2418 if (value == null) {
2419 return defValue;
2420 }
2421 return Integer.parseInt(value);
2422 }
2423
Xiaohui Chenac531942015-05-13 13:20:52 -07002424 /**
2425 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could
2426 * happen during user switch. The async user switch observer may not have received
2427 * the event yet. We use this safe method when we don't care about this ordering and just
2428 * want to update the data. The data is going to be applied when the user switch observer
2429 * is eventually executed.
Christopher Tatef717b932017-09-11 15:52:54 -07002430 *
2431 * Important: this method loads settings to initialize the given user's wallpaper data if
2432 * there is no current in-memory state.
Xiaohui Chenac531942015-05-13 13:20:52 -07002433 */
Christopher Tatebe132e62016-02-10 12:59:49 -08002434 private WallpaperData getWallpaperSafeLocked(int userId, int which) {
2435 // We're setting either just system (work with the system wallpaper),
2436 // both (also work with the system wallpaper), or just the lock
2437 // wallpaper (update against the existing lock wallpaper if any).
2438 // Combined or just-system operations use the 'system' WallpaperData
2439 // for this use; lock-only operations use the dedicated one.
2440 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07002441 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatebe132e62016-02-10 12:59:49 -08002442 WallpaperData wallpaper = whichSet.get(userId);
Xiaohui Chenac531942015-05-13 13:20:52 -07002443 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002444 // common case, this is the first lookup post-boot of the system or
2445 // unified lock, so we bring up the saved state lazily now and recheck.
Christopher Tated7faf532016-02-25 12:43:38 -08002446 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08002447 wallpaper = whichSet.get(userId);
2448 // if it's still null here, this is a lock-only operation and there is not
2449 // yet a lock-only wallpaper set for this user, so we need to establish
2450 // it now.
2451 if (wallpaper == null) {
Christopher Tateedf7d042016-03-29 18:24:25 -07002452 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002453 wallpaper = new WallpaperData(userId,
2454 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2455 mLockWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002456 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08002457 } else {
2458 // sanity fallback: we're in bad shape, but establishing a known
2459 // valid system+lock WallpaperData will keep us from dying.
2460 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
2461 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
2462 mWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002463 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08002464 }
2465 }
Xiaohui Chenac531942015-05-13 13:20:52 -07002466 }
2467 return wallpaper;
2468 }
2469
Christopher Tated7faf532016-02-25 12:43:38 -08002470 private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002471 JournaledFile journal = makeJournaledFile(userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002472 FileInputStream stream = null;
2473 File file = journal.chooseForRead();
Christopher Tate9f224432017-08-01 16:32:49 -07002474
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002475 WallpaperData wallpaper = mWallpaperMap.get(userId);
2476 if (wallpaper == null) {
Christopher Tate9f224432017-08-01 16:32:49 -07002477 // Do this once per boot
2478 migrateFromOld();
2479
Christopher Tatebe132e62016-02-10 12:59:49 -08002480 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
Christopher Tated7faf532016-02-25 12:43:38 -08002481 wallpaper.allowBackup = true;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002482 mWallpaperMap.put(userId, wallpaper);
Christopher Tate41297ff2016-03-10 16:46:15 -08002483 if (!wallpaper.cropExists()) {
Christopher Tate2a6c55f2017-03-31 12:28:30 -07002484 if (wallpaper.sourceExists()) {
2485 generateCrop(wallpaper);
2486 } else {
2487 Slog.i(TAG, "No static wallpaper imagery; defaults will be shown");
2488 }
Christopher Tate41297ff2016-03-10 16:46:15 -08002489 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002490 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002491 boolean success = false;
2492 try {
2493 stream = new FileInputStream(file);
2494 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01002495 parser.setInput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002496
2497 int type;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002498 do {
2499 type = parser.next();
2500 if (type == XmlPullParser.START_TAG) {
2501 String tag = parser.getName();
2502 if ("wp".equals(tag)) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002503 // Common to system + lock wallpapers
Christopher Tated7faf532016-02-25 12:43:38 -08002504 parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
Christopher Tatead3c2592016-01-20 18:13:17 -08002505
Christopher Tatebe132e62016-02-10 12:59:49 -08002506 // A system wallpaper might also be a live wallpaper
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002507 String comp = parser.getAttributeValue(null, "component");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002508 wallpaper.nextWallpaperComponent = comp != null
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07002509 ? ComponentName.unflattenFromString(comp)
2510 : null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002511 if (wallpaper.nextWallpaperComponent == null
2512 || "android".equals(wallpaper.nextWallpaperComponent
2513 .getPackageName())) {
Justin Koh29c30162014-09-05 17:10:10 -07002514 wallpaper.nextWallpaperComponent = mImageWallpaper;
Dianne Hackborn9ea31632011-08-05 14:43:50 -07002515 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002516
Mike Clerona428b2c2009-11-15 22:53:08 -08002517 if (DEBUG) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002518 Slog.v(TAG, "mWidth:" + wallpaper.width);
2519 Slog.v(TAG, "mHeight:" + wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002520 Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002521 Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002522 Slog.v(TAG, "mName:" + wallpaper.name);
2523 Slog.v(TAG, "mNextWallpaperComponent:"
2524 + wallpaper.nextWallpaperComponent);
Mike Clerona428b2c2009-11-15 22:53:08 -08002525 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002526 } else if ("kwp".equals(tag)) {
2527 // keyguard-specific wallpaper for this user
2528 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2529 if (lockWallpaper == null) {
2530 lockWallpaper = new WallpaperData(userId,
2531 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
2532 mLockWallpaperMap.put(userId, lockWallpaper);
2533 }
Christopher Tated7faf532016-02-25 12:43:38 -08002534 parseWallpaperAttributes(parser, lockWallpaper, false);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002535 }
2536 }
2537 } while (type != XmlPullParser.END_DOCUMENT);
2538 success = true;
Dianne Hackborn13579ed2012-11-28 18:05:36 -08002539 } catch (FileNotFoundException e) {
2540 Slog.w(TAG, "no current wallpaper -- first boot?");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002541 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002542 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002543 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002544 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002545 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002546 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002547 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002548 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002549 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002550 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002551 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002552 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002553
2554 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002555 wallpaper.width = -1;
2556 wallpaper.height = -1;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002557 wallpaper.cropHint.set(0, 0, 0, 0);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002558 wallpaper.padding.set(0, 0, 0, 0);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002559 wallpaper.name = "";
Adrian Roosc28e3a92016-04-14 10:47:52 -07002560
2561 mLockWallpaperMap.remove(userId);
Christopher Tatead3c2592016-01-20 18:13:17 -08002562 } else {
2563 if (wallpaper.wallpaperId <= 0) {
2564 wallpaper.wallpaperId = makeWallpaperIdLocked();
2565 if (DEBUG) {
2566 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
2567 + "); now " + wallpaper.wallpaperId);
2568 }
2569 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002570 }
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002571
Adrian Roosc28e3a92016-04-14 10:47:52 -07002572 ensureSaneWallpaperData(wallpaper);
2573 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2574 if (lockWallpaper != null) {
2575 ensureSaneWallpaperData(lockWallpaper);
2576 }
2577 }
2578
2579 private void ensureSaneWallpaperData(WallpaperData wallpaper) {
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002580 // We always want to have some reasonable width hint.
John Spurlock7ea91ec2013-11-04 13:48:38 -05002581 int baseSize = getMaximumSizeDimension();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002582 if (wallpaper.width < baseSize) {
2583 wallpaper.width = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002584 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002585 if (wallpaper.height < baseSize) {
2586 wallpaper.height = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002587 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002588 // and crop, if not previously specified
2589 if (wallpaper.cropHint.width() <= 0
2590 || wallpaper.cropHint.height() <= 0) {
2591 wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
2592 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002593 }
2594
Christopher Tated7faf532016-02-25 12:43:38 -08002595 private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
2596 boolean keepDimensionHints) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002597 final String idString = parser.getAttributeValue(null, "id");
2598 if (idString != null) {
2599 final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
2600 if (id > mWallpaperId) {
2601 mWallpaperId = id;
2602 }
2603 } else {
2604 wallpaper.wallpaperId = makeWallpaperIdLocked();
2605 }
2606
Christopher Tated7faf532016-02-25 12:43:38 -08002607 if (!keepDimensionHints) {
2608 wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
2609 wallpaper.height = Integer.parseInt(parser
2610 .getAttributeValue(null, "height"));
2611 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002612 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
2613 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
2614 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
2615 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
2616 wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
2617 wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
2618 wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
2619 wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002620 int colorsCount = getAttributeInt(parser, "colorsCount", 0);
2621 if (colorsCount > 0) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002622 Color primary = null, secondary = null, tertiary = null;
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002623 for (int i = 0; i < colorsCount; i++) {
Lucas Dupin84b89d92017-05-09 12:16:19 -07002624 Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
2625 if (i == 0) {
2626 primary = color;
2627 } else if (i == 1) {
2628 secondary = color;
2629 } else if (i == 2) {
2630 tertiary = color;
2631 } else {
2632 break;
2633 }
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002634 }
Lucas Dupin84b89d92017-05-09 12:16:19 -07002635 int colorHints = getAttributeInt(parser, "colorHints", 0);
2636 wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints);
Lucas Dupinea1fb1e2017-04-05 17:39:44 -07002637 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002638 wallpaper.name = parser.getAttributeValue(null, "name");
Christopher Tated7faf532016-02-25 12:43:38 -08002639 wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
Christopher Tatebe132e62016-02-10 12:59:49 -08002640 }
2641
John Spurlock7ea91ec2013-11-04 13:48:38 -05002642 private int getMaximumSizeDimension() {
2643 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
2644 Display d = wm.getDefaultDisplay();
2645 return d.getMaximumSizeDimension();
2646 }
2647
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002648 // Called by SystemBackupAgent after files are restored to disk.
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08002649 public void settingsRestored() {
2650 // Verify caller is the system
2651 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2652 throw new RuntimeException("settingsRestored() can only be called from the system process");
2653 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002654 // TODO: If necessary, make it work for secondary users as well. This currently assumes
2655 // restores only to the primary user
Joe Onorato8a9b2202010-02-26 18:56:32 -08002656 if (DEBUG) Slog.v(TAG, "settingsRestored");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002657 WallpaperData wallpaper = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002658 boolean success = false;
2659 synchronized (mLock) {
Christopher Tated7faf532016-02-25 12:43:38 -08002660 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatedb27b842016-02-25 14:39:17 -08002661 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tatead3c2592016-01-20 18:13:17 -08002662 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
Christopher Tated7faf532016-02-25 12:43:38 -08002663 wallpaper.allowBackup = true; // by definition if it was restored
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002664 if (wallpaper.nextWallpaperComponent != null
Justin Koh29c30162014-09-05 17:10:10 -07002665 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002666 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002667 wallpaper, null)) {
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002668 // No such live wallpaper or other failure; fall back to the default
2669 // live wallpaper (since the profile being restored indicated that the
2670 // user had selected a live rather than static one).
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002671 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002672 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002673 success = true;
2674 } else {
Mike Clerona428b2c2009-11-15 22:53:08 -08002675 // If there's a wallpaper name, we use that. If that can't be loaded, then we
2676 // use the default.
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002677 if ("".equals(wallpaper.name)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002678 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
Mike Clerona428b2c2009-11-15 22:53:08 -08002679 success = true;
2680 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002681 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002682 success = restoreNamedResourceLocked(wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002683 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002684 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
2685 + " id=" + wallpaper.wallpaperId);
Mike Clerona428b2c2009-11-15 22:53:08 -08002686 if (success) {
Christopher Tate41297ff2016-03-10 16:46:15 -08002687 generateCrop(wallpaper); // based on the new image + metadata
2688 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002689 wallpaper, null);
Mike Clerona428b2c2009-11-15 22:53:08 -08002690 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002691 }
2692 }
2693
2694 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002695 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
2696 wallpaper.name = "";
Christopher Tatedb27b842016-02-25 14:39:17 -08002697 getWallpaperDir(UserHandle.USER_SYSTEM).delete();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002698 }
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002699
2700 synchronized (mLock) {
Christopher Tatedb27b842016-02-25 14:39:17 -08002701 saveSettingsLocked(UserHandle.USER_SYSTEM);
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002702 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002703 }
2704
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002705 // Restore the named resource bitmap to both source + crop files
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002706 boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
2707 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
2708 String resName = wallpaper.name.substring(4);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002709
2710 String pkg = null;
2711 int colon = resName.indexOf(':');
2712 if (colon > 0) {
2713 pkg = resName.substring(0, colon);
2714 }
2715
2716 String ident = null;
2717 int slash = resName.lastIndexOf('/');
2718 if (slash > 0) {
2719 ident = resName.substring(slash+1);
2720 }
2721
2722 String type = null;
2723 if (colon > 0 && slash > 0 && (slash-colon) > 1) {
2724 type = resName.substring(colon+1, slash);
2725 }
2726
2727 if (pkg != null && ident != null && type != null) {
2728 int resId = -1;
2729 InputStream res = null;
2730 FileOutputStream fos = null;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002731 FileOutputStream cos = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002732 try {
2733 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
2734 Resources r = c.getResources();
2735 resId = r.getIdentifier(resName, null, null);
2736 if (resId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002737 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002738 + " ident=" + ident);
2739 return false;
2740 }
2741
2742 res = r.openRawResource(resId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002743 if (wallpaper.wallpaperFile.exists()) {
2744 wallpaper.wallpaperFile.delete();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002745 wallpaper.cropFile.delete();
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07002746 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002747 fos = new FileOutputStream(wallpaper.wallpaperFile);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002748 cos = new FileOutputStream(wallpaper.cropFile);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002749
2750 byte[] buffer = new byte[32768];
2751 int amt;
2752 while ((amt=res.read(buffer)) > 0) {
2753 fos.write(buffer, 0, amt);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002754 cos.write(buffer, 0, amt);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002755 }
2756 // mWallpaperObserver will notice the close and send the change broadcast
2757
Joe Onorato8a9b2202010-02-26 18:56:32 -08002758 Slog.v(TAG, "Restored wallpaper: " + resName);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002759 return true;
2760 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002761 Slog.e(TAG, "Package name " + pkg + " not found");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002762 } catch (Resources.NotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002763 Slog.e(TAG, "Resource not found: " + resId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002764 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002765 Slog.e(TAG, "IOException while restoring wallpaper ", e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002766 } finally {
Christopher Tatead3c2592016-01-20 18:13:17 -08002767 IoUtils.closeQuietly(res);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002768 if (fos != null) {
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07002769 FileUtils.sync(fos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002770 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002771 if (cos != null) {
2772 FileUtils.sync(cos);
2773 }
2774 IoUtils.closeQuietly(fos);
2775 IoUtils.closeQuietly(cos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002776 }
2777 }
2778 }
2779 return false;
2780 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002781
Dianne Hackborneb034652009-09-07 00:49:58 -07002782 @Override
2783 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06002784 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Dianne Hackborneb034652009-09-07 00:49:58 -07002785
2786 synchronized (mLock) {
Adrian Roosc28e3a92016-04-14 10:47:52 -07002787 pw.println("System wallpaper state:");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002788 for (int i = 0; i < mWallpaperMap.size(); i++) {
2789 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
Christopher Tatead3c2592016-01-20 18:13:17 -08002790 pw.print(" User "); pw.print(wallpaper.userId);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002791 pw.print(": id="); pw.println(wallpaper.wallpaperId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002792 pw.print(" mWidth=");
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002793 pw.print(wallpaper.width);
2794 pw.print(" mHeight=");
2795 pw.println(wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002796 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002797 pw.print(" mPadding="); pw.println(wallpaper.padding);
2798 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01002799 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002800 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002801 if (wallpaper.connection != null) {
2802 WallpaperConnection conn = wallpaper.connection;
2803 pw.print(" Wallpaper connection ");
2804 pw.print(conn);
2805 pw.println(":");
2806 if (conn.mInfo != null) {
2807 pw.print(" mInfo.component=");
2808 pw.println(conn.mInfo.getComponent());
2809 }
2810 pw.print(" mToken=");
2811 pw.println(conn.mToken);
2812 pw.print(" mService=");
2813 pw.println(conn.mService);
2814 pw.print(" mEngine=");
2815 pw.println(conn.mEngine);
2816 pw.print(" mLastDiedTime=");
2817 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
2818 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002819 }
Adrian Roosc28e3a92016-04-14 10:47:52 -07002820 pw.println("Lock wallpaper state:");
2821 for (int i = 0; i < mLockWallpaperMap.size(); i++) {
2822 WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
2823 pw.print(" User "); pw.print(wallpaper.userId);
2824 pw.print(": id="); pw.println(wallpaper.wallpaperId);
2825 pw.print(" mWidth="); pw.print(wallpaper.width);
2826 pw.print(" mHeight="); pw.println(wallpaper.height);
2827 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
2828 pw.print(" mPadding="); pw.println(wallpaper.padding);
2829 pw.print(" mName="); pw.println(wallpaper.name);
Bryan Mawhinney0fa54f42017-07-06 17:09:37 +01002830 pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002831 }
2832
Dianne Hackborneb034652009-09-07 00:49:58 -07002833 }
2834 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835}