blob: 59070baa680bcbfc3b6b9cf4dca1b674f93a4559 [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;
Christopher Tate111bd4a2009-06-24 17:29:38 -070025
Christopher Tatee409f0e2016-03-21 14:53:15 -070026import android.app.ActivityManager;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -070027import android.app.ActivityManagerNative;
Amith Yamasani4e2820c2012-08-28 22:17:23 -070028import android.app.AppGlobals;
Benjamin Franzf3ece362015-02-11 10:51:10 +000029import android.app.AppOpsManager;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -070030import android.app.IUserSwitchObserver;
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070031import android.app.IWallpaperManager;
32import android.app.IWallpaperManagerCallback;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070033import android.app.PendingIntent;
Dianne Hackborneb034652009-09-07 00:49:58 -070034import android.app.WallpaperInfo;
Jeff Sharkey28f08772014-04-16 09:41:58 -070035import android.app.WallpaperManager;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +010036import android.app.admin.DevicePolicyManager;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080037import android.app.backup.WallpaperBackupHelper;
Amith Yamasani13593602012-03-22 16:16:17 -070038import android.content.BroadcastReceiver;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070039import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.Context;
41import android.content.Intent;
Amith Yamasani13593602012-03-22 16:16:17 -070042import android.content.IntentFilter;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070043import android.content.ServiceConnection;
Amith Yamasani4e2820c2012-08-28 22:17:23 -070044import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.content.pm.PackageManager;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060046import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070047import android.content.pm.ResolveInfo;
48import android.content.pm.ServiceInfo;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070049import android.content.pm.UserInfo;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070050import android.content.res.Resources;
Christopher Tate1e1e2e02016-01-25 15:34:36 -080051import android.graphics.Bitmap;
52import android.graphics.BitmapFactory;
53import android.graphics.BitmapRegionDecoder;
John Spurlock41f64642013-11-04 13:48:38 -050054import android.graphics.Point;
Dianne Hackborn067e5f62014-09-07 23:14:30 -070055import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Binder;
Dianne Hackborn284ac932009-08-28 10:34:25 -070057import android.os.Bundle;
Amith Yamasani13593602012-03-22 16:16:17 -070058import android.os.Environment;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060059import android.os.FileObserver;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070060import android.os.FileUtils;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070061import android.os.IBinder;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -070062import android.os.IRemoteCallback;
Christopher Tated7faf532016-02-25 12:43:38 -080063import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.os.ParcelFileDescriptor;
65import android.os.RemoteCallbackList;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060066import android.os.RemoteException;
rpcraig554cb0c2012-07-05 06:41:43 -040067import android.os.SELinux;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070068import android.os.ServiceManager;
Dianne Hackborn0cd48872009-08-13 18:51:59 -070069import android.os.SystemClock;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070070import android.os.UserHandle;
Amith Yamasani6474c4c2012-10-04 14:55:42 -070071import android.os.UserManager;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070072import android.service.wallpaper.IWallpaperConnection;
73import android.service.wallpaper.IWallpaperEngine;
74import android.service.wallpaper.IWallpaperService;
75import android.service.wallpaper.WallpaperService;
Christopher Tate8347b632016-04-29 18:59:18 -070076import android.system.ErrnoException;
77import android.system.Os;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -070078import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080079import android.util.Slog;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080080import android.util.SparseArray;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070081import android.util.Xml;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -070082import android.view.Display;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070083import android.view.IWindowManager;
84import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060086import com.android.internal.R;
87import com.android.internal.content.PackageMonitor;
Christopher Tate190e8532016-07-11 11:35:34 -070088import com.android.internal.os.BackgroundThread;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060089import com.android.internal.util.FastXmlSerializer;
90import com.android.internal.util.JournaledFile;
91import com.android.server.EventLogTags;
92import com.android.server.SystemService;
93
94import libcore.io.IoUtils;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070095
96import org.xmlpull.v1.XmlPullParser;
97import org.xmlpull.v1.XmlPullParserException;
98import org.xmlpull.v1.XmlSerializer;
99
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600100import java.io.BufferedOutputStream;
101import java.io.File;
102import java.io.FileDescriptor;
103import java.io.FileInputStream;
104import java.io.FileNotFoundException;
105import java.io.FileOutputStream;
106import java.io.IOException;
107import java.io.InputStream;
108import java.io.PrintWriter;
109import java.nio.charset.StandardCharsets;
110import java.util.Arrays;
111import java.util.List;
Christopher Tatead3c2592016-01-20 18:13:17 -0800112
Amith Yamasani09e9cdc2013-11-06 14:54:50 -0800113public class WallpaperManagerService extends IWallpaperManager.Stub {
114 static final String TAG = "WallpaperManagerService";
Joe Onorato7e1693a2016-02-01 17:45:03 -0800115 static final boolean DEBUG = false;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700116
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600117 public static class Lifecycle extends SystemService {
118 private WallpaperManagerService mService;
119
120 public Lifecycle(Context context) {
121 super(context);
122 }
123
124 @Override
125 public void onStart() {
126 mService = new WallpaperManagerService(getContext());
127 publishBinderService(Context.WALLPAPER_SERVICE, mService);
128 }
129
130 @Override
131 public void onBootPhase(int phase) {
132 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
133 mService.systemReady();
Jeff Sharkey383f9fe2016-04-13 16:08:15 -0600134 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
135 mService.switchUser(UserHandle.USER_SYSTEM, null);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600136 }
137 }
138
139 @Override
140 public void onUnlockUser(int userHandle) {
141 mService.onUnlockUser(userHandle);
142 }
143 }
144
Christopher Tatebe132e62016-02-10 12:59:49 -0800145 final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700147 /**
148 * Minimum time between crashes of a wallpaper service for us to consider
149 * restarting it vs. just reverting to the static wallpaper.
150 */
151 static final long MIN_WALLPAPER_CRASH_TIME = 10000;
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700152 static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800153 static final String WALLPAPER = "wallpaper_orig";
154 static final String WALLPAPER_CROP = "wallpaper";
Christopher Tatebe132e62016-02-10 12:59:49 -0800155 static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
156 static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800157 static final String WALLPAPER_INFO = "wallpaper_info.xml";
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700158
Christopher Tatebe132e62016-02-10 12:59:49 -0800159 // All the various per-user state files we need to be aware of
160 static final String[] sPerUserFiles = new String[] {
161 WALLPAPER, WALLPAPER_CROP,
162 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
163 WALLPAPER_INFO
164 };
165
Dianne Hackbornbce0cbb2012-10-05 11:06:53 -0700166 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
168 * that the wallpaper has changed. The CREATE is triggered when there is no
169 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
Christopher Tate190e8532016-07-11 11:35:34 -0700170 * every time the wallpaper is changed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 */
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800172 private class WallpaperObserver extends FileObserver {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700173
Christopher Tatebe132e62016-02-10 12:59:49 -0800174 final int mUserId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800175 final WallpaperData mWallpaper;
176 final File mWallpaperDir;
177 final File mWallpaperFile;
Christopher Tatebe132e62016-02-10 12:59:49 -0800178 final File mWallpaperLockFile;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800179
180 public WallpaperObserver(WallpaperData wallpaper) {
181 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
Christopher Tateda058e22014-10-08 14:51:09 -0700182 CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
Christopher Tatebe132e62016-02-10 12:59:49 -0800183 mUserId = wallpaper.userId;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800184 mWallpaperDir = getWallpaperDir(wallpaper.userId);
185 mWallpaper = wallpaper;
186 mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
Christopher Tatebe132e62016-02-10 12:59:49 -0800187 mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800188 }
189
Christopher Tatebe132e62016-02-10 12:59:49 -0800190 private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
191 WallpaperData wallpaper = null;
192 synchronized (mLock) {
193 if (lockChanged) {
194 wallpaper = mLockWallpaperMap.get(mUserId);
195 }
196 if (wallpaper == null) {
197 // no lock-specific wallpaper exists, or sys case, handled together
198 wallpaper = mWallpaperMap.get(mUserId);
199 }
200 }
201 return (wallpaper != null) ? wallpaper : mWallpaper;
202 }
203
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800204 @Override
205 public void onEvent(int event, String path) {
206 if (path == null) {
207 return;
208 }
Christopher Tated7faf532016-02-25 12:43:38 -0800209 final boolean moved = (event == MOVED_TO);
210 final boolean written = (event == CLOSE_WRITE || moved);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800211 final File changedFile = new File(mWallpaperDir, path);
212
Christopher Tatebe132e62016-02-10 12:59:49 -0800213 // System and system+lock changes happen on the system wallpaper input file;
214 // lock-only changes happen on the dedicated lock wallpaper input file
215 final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
216 final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
217 WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
218
219 if (DEBUG) {
220 Slog.v(TAG, "Wallpaper file change: evt=" + event
221 + " path=" + path
222 + " sys=" + sysWallpaperChanged
223 + " lock=" + lockWallpaperChanged
224 + " imagePending=" + wallpaper.imageWallpaperPending
225 + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
226 + " written=" + written);
227 }
Christopher Tate8347b632016-04-29 18:59:18 -0700228
229 if (moved && lockWallpaperChanged) {
230 // We just migrated sys -> lock to preserve imagery for an impending
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700231 // new system-only wallpaper. Tell keyguard about it and make sure it
232 // has the right SELinux label.
Christopher Tate8347b632016-04-29 18:59:18 -0700233 if (DEBUG) {
234 Slog.i(TAG, "Sys -> lock MOVED_TO");
235 }
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700236 SELinux.restorecon(changedFile);
Christopher Tate8347b632016-04-29 18:59:18 -0700237 notifyLockWallpaperChanged();
238 return;
239 }
240
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800241 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800242 if (sysWallpaperChanged || lockWallpaperChanged) {
243 notifyCallbacksLocked(wallpaper);
244 if (wallpaper.wallpaperComponent == null
Christopher Tateda058e22014-10-08 14:51:09 -0700245 || event != CLOSE_WRITE // includes the MOVED_TO case
Christopher Tatebe132e62016-02-10 12:59:49 -0800246 || wallpaper.imageWallpaperPending) {
Christopher Tateda058e22014-10-08 14:51:09 -0700247 if (written) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800248 // The image source has finished writing the source image,
249 // so we now produce the crop rect (in the background), and
250 // only publish the new displayable (sub)image as a result
251 // of that work.
Christopher Tatebe132e62016-02-10 12:59:49 -0800252 if (DEBUG) {
253 Slog.v(TAG, "Wallpaper written; generating crop");
254 }
Christopher Tated7faf532016-02-25 12:43:38 -0800255 if (moved) {
256 // This is a restore, so generate the crop using any just-restored new
257 // crop guidelines, making sure to preserve our local dimension hints.
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700258 // We also make sure to reapply the correct SELinux label.
Christopher Tated7faf532016-02-25 12:43:38 -0800259 if (DEBUG) {
260 Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
261 }
Christopher Tatefa7d97f2016-06-30 12:21:57 -0700262 SELinux.restorecon(changedFile);
Christopher Tated7faf532016-02-25 12:43:38 -0800263 loadSettingsLocked(wallpaper.userId, true);
264 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800265 generateCrop(wallpaper);
266 if (DEBUG) {
267 Slog.v(TAG, "Crop done; invoking completion callback");
268 }
269 wallpaper.imageWallpaperPending = false;
270 if (wallpaper.setComplete != null) {
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800271 try {
Christopher Tatebe132e62016-02-10 12:59:49 -0800272 wallpaper.setComplete.onWallpaperChanged();
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800273 } catch (RemoteException e) {
274 // if this fails we don't really care; the setting app may just
275 // have crashed and that sort of thing is a fact of life.
276 }
277 }
Christopher Tatebe132e62016-02-10 12:59:49 -0800278 if (sysWallpaperChanged) {
279 // If this was the system wallpaper, rebind...
280 bindWallpaperComponentLocked(mImageWallpaper, true,
281 false, wallpaper, null);
282 }
283 if (lockWallpaperChanged
Christopher Tateedf7d042016-03-29 18:24:25 -0700284 || (wallpaper.whichPending & FLAG_LOCK) != 0) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800285 if (DEBUG) {
Christopher Tatedb27b842016-02-25 14:39:17 -0800286 Slog.i(TAG, "Lock-relevant wallpaper changed");
Christopher Tatebe132e62016-02-10 12:59:49 -0800287 }
Christopher Tatedb27b842016-02-25 14:39:17 -0800288 // either a lock-only wallpaper commit or a system+lock event.
289 // if it's system-plus-lock we need to wipe the lock bookkeeping;
290 // we're falling back to displaying the system wallpaper there.
291 if (!lockWallpaperChanged) {
292 mLockWallpaperMap.remove(wallpaper.userId);
293 }
294 // and in any case, tell keyguard about it
Christopher Tate8347b632016-04-29 18:59:18 -0700295 notifyLockWallpaperChanged();
Christopher Tatebe132e62016-02-10 12:59:49 -0800296 }
Christopher Tatedb27b842016-02-25 14:39:17 -0800297 saveSettingsLocked(wallpaper.userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 }
300 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800301 }
302 }
303 }
304
Christopher Tate8347b632016-04-29 18:59:18 -0700305 void notifyLockWallpaperChanged() {
306 final IWallpaperManagerCallback cb = mKeyguardListener;
307 if (cb != null) {
308 try {
309 cb.onWallpaperChanged();
310 } catch (RemoteException e) {
311 // Oh well it went away; no big deal
312 }
313 }
314 }
315
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800316 /**
317 * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
318 * for display.
319 */
320 private void generateCrop(WallpaperData wallpaper) {
321 boolean success = false;
Christopher Tate1a96b632016-03-22 15:25:42 -0700322
323 Rect cropHint = new Rect(wallpaper.cropHint);
Christopher Tatebe132e62016-02-10 12:59:49 -0800324
325 if (DEBUG) {
326 Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
327 + Integer.toHexString(wallpaper.whichPending)
Christopher Tate1a96b632016-03-22 15:25:42 -0700328 + " to " + wallpaper.cropFile.getName()
329 + " crop=(" + cropHint.width() + 'x' + cropHint.height()
330 + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
Christopher Tatebe132e62016-02-10 12:59:49 -0800331 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800332
333 // Analyse the source; needed in multiple cases
334 BitmapFactory.Options options = new BitmapFactory.Options();
335 options.inJustDecodeBounds = true;
336 BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
Christopher Tate1a96b632016-03-22 15:25:42 -0700337 if (options.outWidth <= 0 || options.outHeight <= 0) {
Joe LaPennac298b162016-05-02 15:25:50 -0700338 Slog.w(TAG, "Invalid wallpaper data");
Christopher Tate1a96b632016-03-22 15:25:42 -0700339 success = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800340 } else {
Christopher Tate1a96b632016-03-22 15:25:42 -0700341 boolean needCrop = false;
342 boolean needScale = false;
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800343
Christopher Tate1a96b632016-03-22 15:25:42 -0700344 // Empty crop means use the full image
345 if (cropHint.isEmpty()) {
346 cropHint.left = cropHint.top = 0;
347 cropHint.right = options.outWidth;
348 cropHint.bottom = options.outHeight;
349 } else {
350 // force the crop rect to lie within the measured bounds
351 cropHint.offset(
352 (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
353 (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
354
355 // Don't bother cropping if what we're left with is identity
356 needCrop = (options.outHeight >= cropHint.height()
357 && options.outWidth >= cropHint.width());
358 }
359
360 // scale if the crop height winds up not matching the recommended metrics
361 needScale = (wallpaper.height != cropHint.height());
362
363 if (DEBUG) {
364 Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
365 Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
366 Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
367 Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
368 }
369
370 if (!needCrop && !needScale) {
371 // Simple case: the nominal crop fits what we want, so we take
372 // the whole thing and just copy the image file directly.
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800373 if (DEBUG) {
Christopher Tate1a96b632016-03-22 15:25:42 -0700374 Slog.v(TAG, "Null crop of new wallpaper; copying");
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800375 }
Christopher Tate1a96b632016-03-22 15:25:42 -0700376 success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
377 if (!success) {
378 wallpaper.cropFile.delete();
379 // TODO: fall back to default wallpaper in this case
380 }
381 } else {
382 // Fancy case: crop and scale. First, we decode and scale down if appropriate.
383 FileOutputStream f = null;
384 BufferedOutputStream bos = null;
385 try {
386 BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
387 wallpaper.wallpaperFile.getAbsolutePath(), false);
388
389 // This actually downsamples only by powers of two, but that's okay; we do
390 // a proper scaling blit later. This is to minimize transient RAM use.
391 // We calculate the largest power-of-two under the actual ratio rather than
392 // just let the decode take care of it because we also want to remap where the
393 // cropHint rectangle lies in the decoded [super]rect.
394 final BitmapFactory.Options scaler;
395 final int actualScale = cropHint.height() / wallpaper.height;
396 int scale = 1;
397 while (2*scale < actualScale) {
398 scale *= 2;
399 }
400 if (scale > 1) {
401 scaler = new BitmapFactory.Options();
402 scaler.inSampleSize = scale;
403 if (DEBUG) {
404 Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
405 }
406 } else {
407 scaler = null;
408 }
409 Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
410 decoder.recycle();
411
412 if (cropped == null) {
413 Slog.e(TAG, "Could not decode new wallpaper");
414 } else {
415 // We've got the extracted crop; now we want to scale it properly to
416 // the desired rectangle. That's a height-biased operation: make it
417 // fit the hinted height, and accept whatever width we end up with.
418 cropHint.offsetTo(0, 0);
419 cropHint.right /= scale; // adjust by downsampling factor
420 cropHint.bottom /= scale;
421 final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
422 if (DEBUG) {
423 Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
424 }
425 final int destWidth = (int)(cropHint.width() * heightR);
426 final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
427 destWidth, wallpaper.height, true);
428 if (DEBUG) {
429 Slog.v(TAG, "Final extract:");
430 Slog.v(TAG, " dims: w=" + wallpaper.width
431 + " h=" + wallpaper.height);
432 Slog.v(TAG, " out: w=" + finalCrop.getWidth()
433 + " h=" + finalCrop.getHeight());
434 }
435
436 f = new FileOutputStream(wallpaper.cropFile);
437 bos = new BufferedOutputStream(f, 32*1024);
Christopher Tatec484f542016-05-11 14:31:34 -0700438 finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
Christopher Tate1a96b632016-03-22 15:25:42 -0700439 bos.flush(); // don't rely on the implicit flush-at-close when noting success
440 success = true;
441 }
442 } catch (Exception e) {
443 if (DEBUG) {
444 Slog.e(TAG, "Error decoding crop", e);
445 }
446 } finally {
447 IoUtils.closeQuietly(bos);
448 IoUtils.closeQuietly(f);
449 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800450 }
451 }
452
453 if (!success) {
454 Slog.e(TAG, "Unable to apply new wallpaper");
455 wallpaper.cropFile.delete();
456 }
457
458 if (wallpaper.cropFile.exists()) {
459 boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
460 if (DEBUG) {
461 Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
462 }
463 }
464 }
465
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700466 final Context mContext;
467 final IWindowManager mIWindowManager;
Amith Yamasani4e2820c2012-08-28 22:17:23 -0700468 final IPackageManager mIPackageManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800469 final MyPackageMonitor mMonitor;
Benjamin Franzf3ece362015-02-11 10:51:10 +0000470 final AppOpsManager mAppOpsManager;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800471 WallpaperData mLastWallpaper;
Christopher Tatebe132e62016-02-10 12:59:49 -0800472 IWallpaperManagerCallback mKeyguardListener;
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600473 boolean mWaitingForUnlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474
Justin Koh29c30162014-09-05 17:10:10 -0700475 /**
Christopher Tatead3c2592016-01-20 18:13:17 -0800476 * ID of the current wallpaper, changed every time anything sets a wallpaper.
477 * This is used for external detection of wallpaper update activity.
478 */
479 int mWallpaperId;
480
481 /**
Justin Koh29c30162014-09-05 17:10:10 -0700482 * Name of the component used to display bitmap wallpapers from either the gallery or
483 * built-in wallpapers.
484 */
485 final ComponentName mImageWallpaper;
486
Christopher Tatebe132e62016-02-10 12:59:49 -0800487 final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
488 final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
Dianne Hackborn07213e62011-08-24 20:05:39 -0700489
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800490 int mCurrentUserId;
Dianne Hackborn07213e62011-08-24 20:05:39 -0700491
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800492 static class WallpaperData {
493
494 int userId;
495
Christopher Tatebe132e62016-02-10 12:59:49 -0800496 final File wallpaperFile; // source image
497 final File cropFile; // eventual destination
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800498
499 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800500 * True while the client is writing a new wallpaper
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800501 */
502 boolean imageWallpaperPending;
503
504 /**
Christopher Tatebe132e62016-02-10 12:59:49 -0800505 * Which new wallpapers are being written; mirrors the 'which'
506 * selector bit field to setWallpaper().
507 */
508 int whichPending;
509
510 /**
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800511 * Callback once the set + crop is finished
512 */
513 IWallpaperManagerCallback setComplete;
514
515 /**
Christopher Tated7faf532016-02-25 12:43:38 -0800516 * Is the OS allowed to back up this wallpaper imagery?
517 */
518 boolean allowBackup;
519
520 /**
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800521 * Resource name if using a picture from the wallpaper gallery
522 */
523 String name = "";
524
525 /**
526 * The component name of the currently set live wallpaper.
527 */
528 ComponentName wallpaperComponent;
529
530 /**
531 * The component name of the wallpaper that should be set next.
532 */
533 ComponentName nextWallpaperComponent;
534
Christopher Tatead3c2592016-01-20 18:13:17 -0800535 /**
536 * The ID of this wallpaper
537 */
538 int wallpaperId;
539
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800540 WallpaperConnection connection;
541 long lastDiedTime;
542 boolean wallpaperUpdating;
543 WallpaperObserver wallpaperObserver;
544
545 /**
546 * List of callbacks registered they should each be notified when the wallpaper is changed.
547 */
548 private RemoteCallbackList<IWallpaperManagerCallback> callbacks
549 = new RemoteCallbackList<IWallpaperManagerCallback>();
550
551 int width = -1;
552 int height = -1;
553
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800554 /**
555 * The crop hint supplied for displaying a subset of the source image
556 */
557 final Rect cropHint = new Rect(0, 0, 0, 0);
558
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700559 final Rect padding = new Rect(0, 0, 0, 0);
560
Christopher Tatebe132e62016-02-10 12:59:49 -0800561 WallpaperData(int userId, String inputFileName, String cropFileName) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800562 this.userId = userId;
Christopher Tatebe132e62016-02-10 12:59:49 -0800563 final File wallpaperDir = getWallpaperDir(userId);
564 wallpaperFile = new File(wallpaperDir, inputFileName);
565 cropFile = new File(wallpaperDir, cropFileName);
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800566 }
567
Christopher Tatebe132e62016-02-10 12:59:49 -0800568 // Called during initialization of a given user's wallpaper bookkeeping
Christopher Tate41297ff2016-03-10 16:46:15 -0800569 boolean cropExists() {
570 return cropFile.exists();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800571 }
572 }
573
Christopher Tatead3c2592016-01-20 18:13:17 -0800574 int makeWallpaperIdLocked() {
575 do {
576 ++mWallpaperId;
577 } while (mWallpaperId == 0);
578 return mWallpaperId;
579 }
580
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700581 class WallpaperConnection extends IWallpaperConnection.Stub
582 implements ServiceConnection {
Dianne Hackborneb034652009-09-07 00:49:58 -0700583 final WallpaperInfo mInfo;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700584 final Binder mToken = new Binder();
585 IWallpaperService mService;
586 IWallpaperEngine mEngine;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800587 WallpaperData mWallpaper;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700588 IRemoteCallback mReply;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589
Michael Wright5203a8b2013-10-03 14:16:42 -0700590 boolean mDimensionsChanged = false;
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700591 boolean mPaddingChanged = false;
Michael Wright5203a8b2013-10-03 14:16:42 -0700592
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800593 public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700594 mInfo = info;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800595 mWallpaper = wallpaper;
Dianne Hackborneb034652009-09-07 00:49:58 -0700596 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700597
598 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700599 public void onServiceConnected(ComponentName name, IBinder service) {
600 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800601 if (mWallpaper.connection == this) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700602 mService = IWallpaperService.Stub.asInterface(service);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800603 attachServiceLocked(this, mWallpaper);
Dianne Hackborneb034652009-09-07 00:49:58 -0700604 // XXX should probably do saveSettingsLocked() later
605 // when we have an engine, but I'm not sure about
606 // locking there and anyway we always need to be able to
607 // recover if there is something wrong.
Christopher Tatedb27b842016-02-25 14:39:17 -0800608 saveSettingsLocked(mWallpaper.userId);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700609 }
610 }
611 }
612
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700613 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700614 public void onServiceDisconnected(ComponentName name) {
615 synchronized (mLock) {
616 mService = null;
617 mEngine = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800618 if (mWallpaper.connection == this) {
619 Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
620 if (!mWallpaper.wallpaperUpdating
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800621 && mWallpaper.userId == mCurrentUserId) {
Selim Cinekebebadb2014-03-05 22:17:26 +0100622 // There is a race condition which causes
623 // {@link #mWallpaper.wallpaperUpdating} to be false even if it is
624 // currently updating since the broadcast notifying us is async.
625 // This race is overcome by the general rule that we only reset the
626 // wallpaper if its service was shut down twice
627 // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
628 if (mWallpaper.lastDiedTime != 0
629 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
630 > SystemClock.uptimeMillis()) {
631 Slog.w(TAG, "Reverting to built-in wallpaper!");
Christopher Tateedf7d042016-03-29 18:24:25 -0700632 clearWallpaperLocked(true, FLAG_SYSTEM, mWallpaper.userId, null);
Selim Cinekebebadb2014-03-05 22:17:26 +0100633 } else {
634 mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
635 }
Filip Gruszczynski5a589432014-10-14 12:06:06 -0700636 final String flattened = name.flattenToString();
Filip Gruszczynski5dcc3ac2014-10-13 15:51:39 -0700637 EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
Filip Gruszczynski5a589432014-10-14 12:06:06 -0700638 flattened.substring(0, Math.min(flattened.length(),
639 MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700640 }
641 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700642 }
643 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800644
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700645 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700646 public void attachEngine(IWallpaperEngine engine) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700647 synchronized (mLock) {
648 mEngine = engine;
Michael Wright5203a8b2013-10-03 14:16:42 -0700649 if (mDimensionsChanged) {
650 try {
651 mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
652 } catch (RemoteException e) {
653 Slog.w(TAG, "Failed to set wallpaper dimensions", e);
654 }
655 mDimensionsChanged = false;
656 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700657 if (mPaddingChanged) {
658 try {
659 mEngine.setDisplayPadding(mWallpaper.padding);
660 } catch (RemoteException e) {
661 Slog.w(TAG, "Failed to set wallpaper padding", e);
662 }
663 mPaddingChanged = false;
664 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700665 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700666 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800667
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700668 @Override
669 public void engineShown(IWallpaperEngine engine) {
670 synchronized (mLock) {
671 if (mReply != null) {
672 long ident = Binder.clearCallingIdentity();
673 try {
674 mReply.sendResult(null);
675 } catch (RemoteException e) {
676 Binder.restoreCallingIdentity(ident);
677 }
678 mReply = null;
679 }
680 }
681 }
682
683 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700684 public ParcelFileDescriptor setWallpaper(String name) {
685 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800686 if (mWallpaper.connection == this) {
Christopher Tatead3c2592016-01-20 18:13:17 -0800687 return updateWallpaperBitmapLocked(name, mWallpaper, null);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700688 }
689 return null;
690 }
691 }
692 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800693
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800694 class MyPackageMonitor extends PackageMonitor {
695 @Override
696 public void onPackageUpdateFinished(String packageName, int uid) {
697 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700698 if (mCurrentUserId != getChangingUserId()) {
699 return;
700 }
701 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
702 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800703 if (wallpaper.wallpaperComponent != null
704 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
705 wallpaper.wallpaperUpdating = false;
706 ComponentName comp = wallpaper.wallpaperComponent;
707 clearWallpaperComponentLocked(wallpaper);
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700708 if (!bindWallpaperComponentLocked(comp, false, false,
709 wallpaper, null)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800710 Slog.w(TAG, "Wallpaper no longer available; reverting to default");
Christopher Tateedf7d042016-03-29 18:24:25 -0700711 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800712 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700713 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800714 }
715 }
716 }
717
718 @Override
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700719 public void onPackageModified(String packageName) {
720 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700721 if (mCurrentUserId != getChangingUserId()) {
722 return;
723 }
724 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
725 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800726 if (wallpaper.wallpaperComponent == null
727 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700728 return;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800729 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700730 doPackagesChangedLocked(true, wallpaper);
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700731 }
732 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700733 }
734
735 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800736 public void onPackageUpdateStarted(String packageName, int uid) {
737 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700738 if (mCurrentUserId != getChangingUserId()) {
739 return;
740 }
741 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
742 if (wallpaper != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800743 if (wallpaper.wallpaperComponent != null
744 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
745 wallpaper.wallpaperUpdating = true;
746 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800747 }
748 }
749 }
750
751 @Override
752 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700753 synchronized (mLock) {
754 boolean changed = false;
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700755 if (mCurrentUserId != getChangingUserId()) {
756 return false;
757 }
758 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
759 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700760 boolean res = doPackagesChangedLocked(doit, wallpaper);
761 changed |= res;
762 }
763 return changed;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800764 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800765 }
766
767 @Override
768 public void onSomePackagesChanged() {
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700769 synchronized (mLock) {
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700770 if (mCurrentUserId != getChangingUserId()) {
771 return;
772 }
773 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
774 if (wallpaper != null) {
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700775 doPackagesChangedLocked(true, wallpaper);
776 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800777 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800778 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800779
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700780 boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800781 boolean changed = false;
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700782 if (wallpaper.wallpaperComponent != null) {
783 int change = isPackageDisappearing(wallpaper.wallpaperComponent
784 .getPackageName());
785 if (change == PACKAGE_PERMANENT_CHANGE
786 || change == PACKAGE_TEMPORARY_CHANGE) {
787 changed = true;
788 if (doit) {
789 Slog.w(TAG, "Wallpaper uninstalled, removing: "
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800790 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -0700791 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800792 }
793 }
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700794 }
795 if (wallpaper.nextWallpaperComponent != null) {
796 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
797 .getPackageName());
798 if (change == PACKAGE_PERMANENT_CHANGE
799 || change == PACKAGE_TEMPORARY_CHANGE) {
800 wallpaper.nextWallpaperComponent = null;
801 }
802 }
803 if (wallpaper.wallpaperComponent != null
804 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
805 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600806 mContext.getPackageManager().getServiceInfo(wallpaper.wallpaperComponent,
807 PackageManager.MATCH_DIRECT_BOOT_AWARE
808 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700809 } catch (NameNotFoundException e) {
810 Slog.w(TAG, "Wallpaper component gone, removing: "
811 + wallpaper.wallpaperComponent);
Christopher Tateedf7d042016-03-29 18:24:25 -0700812 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700813 }
814 }
815 if (wallpaper.nextWallpaperComponent != null
816 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
817 try {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600818 mContext.getPackageManager().getServiceInfo(wallpaper.nextWallpaperComponent,
819 PackageManager.MATCH_DIRECT_BOOT_AWARE
820 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700821 } catch (NameNotFoundException e) {
822 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800823 }
824 }
825 return changed;
826 }
827 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100828
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700829 public WallpaperManagerService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800830 if (DEBUG) Slog.v(TAG, "WallpaperService startup");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 mContext = context;
Justin Koh29c30162014-09-05 17:10:10 -0700832 mImageWallpaper = ComponentName.unflattenFromString(
833 context.getResources().getString(R.string.image_wallpaper_component));
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700834 mIWindowManager = IWindowManager.Stub.asInterface(
835 ServiceManager.getService(Context.WINDOW_SERVICE));
Amith Yamasani4e2820c2012-08-28 22:17:23 -0700836 mIPackageManager = AppGlobals.getPackageManager();
Benjamin Franzf3ece362015-02-11 10:51:10 +0000837 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800838 mMonitor = new MyPackageMonitor();
Dianne Hackbornc72fc672012-09-20 13:12:03 -0700839 mMonitor.register(context, null, UserHandle.ALL, true);
Xiaohui Chen233d94c2015-07-30 15:08:00 -0700840 getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
Christopher Tated7faf532016-02-25 12:43:38 -0800841 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +0100843
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800844 private static File getWallpaperDir(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -0700845 return Environment.getUserSystemDirectory(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800846 }
847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 @Override
849 protected void finalize() throws Throwable {
850 super.finalize();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800851 for (int i = 0; i < mWallpaperMap.size(); i++) {
852 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
853 wallpaper.wallpaperObserver.stopWatching();
854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
Amith Yamasani13593602012-03-22 16:16:17 -0700856
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600857 void systemReady() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800858 if (DEBUG) Slog.v(TAG, "systemReady");
Xiaohui Chen233d94c2015-07-30 15:08:00 -0700859 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tate2cdd3f22016-03-14 17:36:16 -0700860 // If we think we're going to be using the system image wallpaper imagery, make
861 // sure we have something to render
862 if (mImageWallpaper.equals(wallpaper.nextWallpaperComponent)) {
863 // No crop file? Make sure we've finished the processing sequence if necessary
864 if (!wallpaper.cropExists()) {
865 if (DEBUG) {
866 Slog.i(TAG, "No crop; regenerating from source");
867 }
868 generateCrop(wallpaper);
869 }
870 // Still nothing? Fall back to default.
871 if (!wallpaper.cropExists()) {
872 if (DEBUG) {
873 Slog.i(TAG, "Unable to regenerate crop; resetting");
874 }
Christopher Tateedf7d042016-03-29 18:24:25 -0700875 clearWallpaperLocked(false, FLAG_SYSTEM, UserHandle.USER_SYSTEM, null);
Christopher Tate2cdd3f22016-03-14 17:36:16 -0700876 }
877 } else {
878 if (DEBUG) {
879 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
880 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -0800881 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800882
Amith Yamasani13593602012-03-22 16:16:17 -0700883 IntentFilter userFilter = new IntentFilter();
Amith Yamasani13593602012-03-22 16:16:17 -0700884 userFilter.addAction(Intent.ACTION_USER_REMOVED);
885 mContext.registerReceiver(new BroadcastReceiver() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800886 @Override
Amith Yamasani13593602012-03-22 16:16:17 -0700887 public void onReceive(Context context, Intent intent) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600888 final String action = intent.getAction();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700889 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Amith Yamasani756901d2012-10-12 12:30:07 -0700890 onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
891 UserHandle.USER_NULL));
Amith Yamasani13593602012-03-22 16:16:17 -0700892 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800893 }
Amith Yamasani13593602012-03-22 16:16:17 -0700894 }, userFilter);
Amith Yamasani756901d2012-10-12 12:30:07 -0700895
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700896 try {
897 ActivityManagerNative.getDefault().registerUserSwitchObserver(
898 new IUserSwitchObserver.Stub() {
899 @Override
900 public void onUserSwitching(int newUserId, IRemoteCallback reply) {
901 switchUser(newUserId, reply);
902 }
903
904 @Override
905 public void onUserSwitchComplete(int newUserId) throws RemoteException {
906 }
Kenny Guy42979622015-04-13 18:03:05 +0000907
908 @Override
909 public void onForegroundProfileSwitch(int newProfileId) {
910 // Ignore.
911 }
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -0700912 }, TAG);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700913 } catch (RemoteException e) {
Fyodor Kupolov0b77ef92016-06-20 17:16:52 -0700914 e.rethrowAsRuntimeException();
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700915 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800916 }
917
Amith Yamasani09e9cdc2013-11-06 14:54:50 -0800918 /** Called by SystemBackupAgent */
919 public String getName() {
920 // Verify caller is the system
921 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
922 throw new RuntimeException("getName() can only be called from the system process");
923 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700924 synchronized (mLock) {
925 return mWallpaperMap.get(0).name;
926 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800927 }
928
Christopher Tatebe132e62016-02-10 12:59:49 -0800929 void stopObserver(WallpaperData wallpaper) {
930 if (wallpaper != null) {
931 if (wallpaper.wallpaperObserver != null) {
932 wallpaper.wallpaperObserver.stopWatching();
933 wallpaper.wallpaperObserver = null;
Amith Yamasani13593602012-03-22 16:16:17 -0700934 }
Amith Yamasani756901d2012-10-12 12:30:07 -0700935 }
936 }
937
Christopher Tatebe132e62016-02-10 12:59:49 -0800938 void stopObserversLocked(int userId) {
939 stopObserver(mWallpaperMap.get(userId));
940 stopObserver(mLockWallpaperMap.get(userId));
941 mWallpaperMap.remove(userId);
942 mLockWallpaperMap.remove(userId);
943 }
944
Christopher Tate190e8532016-07-11 11:35:34 -0700945 void onUnlockUser(final int userId) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600946 synchronized (mLock) {
947 if (mCurrentUserId == userId && mWaitingForUnlock) {
948 switchUser(userId, null);
Christopher Tate190e8532016-07-11 11:35:34 -0700949
950 // Make sure that the SELinux labeling of all the relevant files is correct.
951 // This corrects for mislabeling bugs that might have arisen from move-to
952 // operations involving the wallpaper files. This isn't timing-critical,
953 // so we do it in the background to avoid holding up the user unlock operation.
954 Runnable relabeler = new Runnable() {
955 @Override
956 public void run() {
957 final File wallpaperDir = getWallpaperDir(userId);
958 for (String filename : sPerUserFiles) {
959 File f = new File(wallpaperDir, filename);
960 if (f.exists()) {
961 SELinux.restorecon(f);
962 }
963 }
964 }
965 };
966 BackgroundThread.getHandler().post(relabeler);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600967 }
968 }
969 }
970
Amith Yamasani756901d2012-10-12 12:30:07 -0700971 void onRemoveUser(int userId) {
972 if (userId < 1) return;
Christopher Tatebe132e62016-02-10 12:59:49 -0800973
974 final File wallpaperDir = getWallpaperDir(userId);
Amith Yamasani756901d2012-10-12 12:30:07 -0700975 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -0800976 stopObserversLocked(userId);
977 for (String filename : sPerUserFiles) {
978 new File(wallpaperDir, filename).delete();
979 }
Amith Yamasani13593602012-03-22 16:16:17 -0700980 }
981 }
982
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700983 void switchUser(int userId, IRemoteCallback reply) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800984 synchronized (mLock) {
985 mCurrentUserId = userId;
Christopher Tateedf7d042016-03-29 18:24:25 -0700986 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Amith Yamasani6474c4c2012-10-04 14:55:42 -0700987 // Not started watching yet, in case wallpaper data was loaded for other reasons.
988 if (wallpaper.wallpaperObserver == null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800989 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
990 wallpaper.wallpaperObserver.startWatching();
991 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700992 switchWallpaper(wallpaper, reply);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800993 }
994 }
995
Dianne Hackborn5dc5a002012-09-15 19:33:48 -0700996 void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700997 synchronized (mLock) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600998 mWaitingForUnlock = false;
999 final ComponentName cname = wallpaper.wallpaperComponent != null ?
1000 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
1001 if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
1002 // We failed to bind the desired wallpaper, but that might
1003 // happen if the wallpaper isn't direct-boot aware
1004 ServiceInfo si = null;
1005 try {
1006 si = mIPackageManager.getServiceInfo(cname,
1007 PackageManager.MATCH_DIRECT_BOOT_UNAWARE, wallpaper.userId);
1008 } catch (RemoteException ignored) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001009 }
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001010
1011 if (si == null) {
1012 Slog.w(TAG, "Failure starting previous wallpaper; clearing");
1013 clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
1014 } else {
1015 Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
1016 // We might end up persisting the current wallpaper data
1017 // while locked, so pretend like the component was actually
1018 // bound into place
1019 wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
1020 final WallpaperData fallback = new WallpaperData(wallpaper.userId,
1021 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
Adrian Roosc28e3a92016-04-14 10:47:52 -07001022 ensureSaneWallpaperData(fallback);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -06001023 bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
1024 mWaitingForUnlock = true;
1025 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001026 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001027 }
1028 }
1029
Christopher Tatebe132e62016-02-10 12:59:49 -08001030 @Override
1031 public void clearWallpaper(String callingPackage, int which, int userId) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001032 if (DEBUG) Slog.v(TAG, "clearWallpaper");
Benjamin Franzf3ece362015-02-11 10:51:10 +00001033 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tate98d609c2016-05-18 17:31:58 -07001034 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001035 return;
1036 }
Christopher Tatee409f0e2016-03-21 14:53:15 -07001037 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1038 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001039
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001040 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001041 clearWallpaperLocked(false, which, userId, null);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001042 }
1043 }
1044
Christopher Tatebe132e62016-02-10 12:59:49 -08001045 void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
Christopher Tateedf7d042016-03-29 18:24:25 -07001046 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001047 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1048 }
1049
1050 WallpaperData wallpaper = null;
Christopher Tateedf7d042016-03-29 18:24:25 -07001051 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001052 wallpaper = mLockWallpaperMap.get(userId);
1053 if (wallpaper == null) {
1054 // It's already gone; we're done.
Christopher Tate79a24572016-03-02 14:42:44 -08001055 if (DEBUG) {
1056 Slog.i(TAG, "Lock wallpaper already cleared");
1057 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001058 return;
1059 }
1060 } else {
1061 wallpaper = mWallpaperMap.get(userId);
1062 if (wallpaper == null) {
1063 // Might need to bring it in the first time to establish our rewrite
Christopher Tated7faf532016-02-25 12:43:38 -08001064 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08001065 wallpaper = mWallpaperMap.get(userId);
1066 }
1067 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001068 if (wallpaper == null) {
1069 return;
1070 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001071
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001072 final long ident = Binder.clearCallingIdentity();
1073 try {
Christopher Tatebe132e62016-02-10 12:59:49 -08001074 if (wallpaper.wallpaperFile.exists()) {
1075 wallpaper.wallpaperFile.delete();
1076 wallpaper.cropFile.delete();
Christopher Tateedf7d042016-03-29 18:24:25 -07001077 if (which == FLAG_LOCK) {
Christopher Tate79a24572016-03-02 14:42:44 -08001078 mLockWallpaperMap.remove(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001079 final IWallpaperManagerCallback cb = mKeyguardListener;
1080 if (cb != null) {
Christopher Tate79a24572016-03-02 14:42:44 -08001081 if (DEBUG) {
1082 Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
1083 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001084 try {
1085 cb.onWallpaperChanged();
1086 } catch (RemoteException e) {
1087 // Oh well it went away; no big deal
1088 }
1089 }
Christopher Tate79a24572016-03-02 14:42:44 -08001090 saveSettingsLocked(userId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001091 return;
1092 }
1093 }
1094
Christopher Tateecd827a2014-09-05 17:42:34 -07001095 RuntimeException e = null;
1096 try {
1097 wallpaper.imageWallpaperPending = false;
1098 if (userId != mCurrentUserId) return;
1099 if (bindWallpaperComponentLocked(defaultFailed
1100 ? mImageWallpaper
1101 : null, true, false, wallpaper, reply)) {
1102 return;
1103 }
1104 } catch (IllegalArgumentException e1) {
1105 e = e1;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001106 }
Christopher Tateecd827a2014-09-05 17:42:34 -07001107
1108 // This can happen if the default wallpaper component doesn't
1109 // exist. This should be a system configuration problem, but
1110 // let's not let it crash the system and just live with no
1111 // wallpaper.
1112 Slog.e(TAG, "Default wallpaper component not found!", e);
1113 clearWallpaperComponentLocked(wallpaper);
1114 if (reply != null) {
1115 try {
1116 reply.sendResult(null);
1117 } catch (RemoteException e1) {
1118 }
1119 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001120 } finally {
1121 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 }
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001123 }
1124
1125 public boolean hasNamedWallpaper(String name) {
1126 synchronized (mLock) {
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001127 List<UserInfo> users;
1128 long ident = Binder.clearCallingIdentity();
1129 try {
1130 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
1131 } finally {
1132 Binder.restoreCallingIdentity(ident);
1133 }
1134 for (UserInfo user: users) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001135 // ignore managed profiles
1136 if (user.isManagedProfile()) {
1137 continue;
1138 }
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001139 WallpaperData wd = mWallpaperMap.get(user.id);
1140 if (wd == null) {
1141 // User hasn't started yet, so load her settings to peek at the wallpaper
Christopher Tated7faf532016-02-25 12:43:38 -08001142 loadSettingsLocked(user.id, false);
Amith Yamasani6474c4c2012-10-04 14:55:42 -07001143 wd = mWallpaperMap.get(user.id);
1144 }
1145 if (wd != null && name.equals(wd.name)) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001146 return true;
1147 }
1148 }
1149 }
1150 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 }
1152
John Spurlock41f64642013-11-04 13:48:38 -05001153 private Point getDefaultDisplaySize() {
1154 Point p = new Point();
John Spurlockd6e836c2013-11-18 14:14:49 -05001155 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1156 Display d = wm.getDefaultDisplay();
1157 d.getRealSize(p);
John Spurlock41f64642013-11-04 13:48:38 -05001158 return p;
1159 }
1160
Benjamin Franzf3ece362015-02-11 10:51:10 +00001161 public void setDimensionHints(int width, int height, String callingPackage)
1162 throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001164 if (!isWallpaperSupported(callingPackage)) {
1165 return;
1166 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001167 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001168 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001169 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001170 if (width <= 0 || height <= 0) {
1171 throw new IllegalArgumentException("width and height must be > 0");
1172 }
John Spurlock41f64642013-11-04 13:48:38 -05001173 // Make sure it is at least as large as the display.
1174 Point displaySize = getDefaultDisplaySize();
1175 width = Math.max(width, displaySize.x);
1176 height = Math.max(height, displaySize.y);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001177
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001178 if (width != wallpaper.width || height != wallpaper.height) {
1179 wallpaper.width = width;
1180 wallpaper.height = height;
Christopher Tatedb27b842016-02-25 14:39:17 -08001181 saveSettingsLocked(userId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001182 if (mCurrentUserId != userId) return; // Don't change the properties now
1183 if (wallpaper.connection != null) {
1184 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001185 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001186 wallpaper.connection.mEngine.setDesiredSize(
Dianne Hackborn284ac932009-08-28 10:34:25 -07001187 width, height);
1188 } catch (RemoteException e) {
1189 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001190 notifyCallbacksLocked(wallpaper);
Michael Wright5203a8b2013-10-03 14:16:42 -07001191 } else if (wallpaper.connection.mService != null) {
1192 // We've attached to the service but the engine hasn't attached back to us
1193 // yet. This means it will be created with the previous dimensions, so we
1194 // need to update it to the new dimensions once it attaches.
1195 wallpaper.connection.mDimensionsChanged = true;
Dianne Hackborn284ac932009-08-28 10:34:25 -07001196 }
1197 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 }
1200 }
1201
1202 public int getWidthHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001203 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001204 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001205 if (wallpaper != null) {
1206 return wallpaper.width;
1207 } else {
1208 return 0;
1209 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 }
1212
1213 public int getHeightHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001214 synchronized (mLock) {
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001215 WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
Benjamin Franzf3ece362015-02-11 10:51:10 +00001216 if (wallpaper != null) {
1217 return wallpaper.height;
1218 } else {
1219 return 0;
1220 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 }
1223
Benjamin Franzf3ece362015-02-11 10:51:10 +00001224 public void setDisplayPadding(Rect padding, String callingPackage) {
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001225 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001226 if (!isWallpaperSupported(callingPackage)) {
1227 return;
1228 }
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001229 synchronized (mLock) {
1230 int userId = UserHandle.getCallingUserId();
Christopher Tateedf7d042016-03-29 18:24:25 -07001231 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001232 if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
1233 throw new IllegalArgumentException("padding must be positive: " + padding);
1234 }
1235
1236 if (!padding.equals(wallpaper.padding)) {
1237 wallpaper.padding.set(padding);
Christopher Tatedb27b842016-02-25 14:39:17 -08001238 saveSettingsLocked(userId);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001239 if (mCurrentUserId != userId) return; // Don't change the properties now
1240 if (wallpaper.connection != null) {
1241 if (wallpaper.connection.mEngine != null) {
1242 try {
1243 wallpaper.connection.mEngine.setDisplayPadding(padding);
1244 } catch (RemoteException e) {
1245 }
1246 notifyCallbacksLocked(wallpaper);
1247 } else if (wallpaper.connection.mService != null) {
1248 // We've attached to the service but the engine hasn't attached back to us
1249 // yet. This means it will be created with the previous dimensions, so we
1250 // need to update it to the new dimensions once it attaches.
1251 wallpaper.connection.mPaddingChanged = true;
1252 }
1253 }
1254 }
1255 }
1256 }
1257
Yorke Leedcd93cc2016-01-08 14:12:55 -08001258 @Override
Christopher Tatebe132e62016-02-10 12:59:49 -08001259 public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which,
1260 Bundle outParams, int wallpaperUserId) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001261 wallpaperUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1262 Binder.getCallingUid(), wallpaperUserId, false, true, "getWallpaper", null);
Christopher Tatebe132e62016-02-10 12:59:49 -08001263
Christopher Tateedf7d042016-03-29 18:24:25 -07001264 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001265 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
1266 }
1267
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001268 synchronized (mLock) {
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001269 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07001270 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001271 WallpaperData wallpaper = whichSet.get(wallpaperUserId);
1272 if (wallpaper == null) {
1273 // common case, this is the first lookup post-boot of the system or
1274 // unified lock, so we bring up the saved state lazily now and recheck.
Christopher Tated7faf532016-02-25 12:43:38 -08001275 loadSettingsLocked(wallpaperUserId, false);
Vadim Tryshev8cde0792016-02-19 17:02:15 -08001276 wallpaper = whichSet.get(wallpaperUserId);
Christopher Tatebe132e62016-02-10 12:59:49 -08001277 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001278 return null;
1279 }
Benjamin Franzf3ece362015-02-11 10:51:10 +00001280 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001281 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -07001282 if (outParams != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001283 outParams.putInt("width", wallpaper.width);
1284 outParams.putInt("height", wallpaper.height);
Dianne Hackborn284ac932009-08-28 10:34:25 -07001285 }
Christopher Tateea6724a2016-02-18 18:39:19 -08001286 if (cb != null) {
1287 wallpaper.callbacks.register(cb);
1288 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001289 if (!wallpaper.cropFile.exists()) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001290 return null;
1291 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001292 return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001293 } catch (FileNotFoundException e) {
1294 /* Shouldn't happen as we check to see if the file exists */
Joe Onorato8a9b2202010-02-26 18:56:32 -08001295 Slog.w(TAG, "Error getting wallpaper", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001297 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 }
1300
Christopher Tatee409f0e2016-03-21 14:53:15 -07001301 @Override
Jorim Jaggie31f6b82016-07-01 16:15:09 -07001302 public WallpaperInfo getWallpaperInfo(int userId) {
1303 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1304 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
Dianne Hackborneb034652009-09-07 00:49:58 -07001305 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001306 WallpaperData wallpaper = mWallpaperMap.get(userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001307 if (wallpaper != null && wallpaper.connection != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001308 return wallpaper.connection.mInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -07001309 }
1310 return null;
1311 }
1312 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001313
Christopher Tatead3c2592016-01-20 18:13:17 -08001314 @Override
Christopher Tatee409f0e2016-03-21 14:53:15 -07001315 public int getWallpaperIdForUser(int which, int userId) {
1316 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1317 Binder.getCallingUid(), userId, false, true, "getWallpaperIdForUser", null);
1318
Christopher Tateedf7d042016-03-29 18:24:25 -07001319 if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
Christopher Tatee409f0e2016-03-21 14:53:15 -07001320 throw new IllegalArgumentException("Must specify exactly one kind of wallpaper");
1321 }
1322
1323 final SparseArray<WallpaperData> map =
Christopher Tateedf7d042016-03-29 18:24:25 -07001324 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatee409f0e2016-03-21 14:53:15 -07001325 synchronized (mLock) {
1326 WallpaperData wallpaper = map.get(userId);
1327 if (wallpaper != null) {
1328 return wallpaper.wallpaperId;
1329 }
1330 }
1331 return -1;
1332 }
1333
1334 @Override
Christopher Tatebe132e62016-02-10 12:59:49 -08001335 public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
1336 checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
1337 synchronized (mLock) {
1338 mKeyguardListener = cb;
1339 }
1340 return true;
1341 }
1342
1343 @Override
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001344 public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Christopher Tated7faf532016-02-25 12:43:38 -08001345 Rect cropHint, boolean allowBackup, Bundle extras, int which,
1346 IWallpaperManagerCallback completion) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Christopher Tatead3c2592016-01-20 18:13:17 -08001348
Christopher Tateedf7d042016-03-29 18:24:25 -07001349 if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001350 final String msg = "Must specify a valid wallpaper category to set";
1351 Slog.e(TAG, msg);
1352 throw new IllegalArgumentException(msg);
Christopher Tatead3c2592016-01-20 18:13:17 -08001353 }
1354
Christopher Tate98d609c2016-05-18 17:31:58 -07001355 if (!isWallpaperSupported(callingPackage) || !isSetWallpaperAllowed(callingPackage)) {
Benjamin Franzf3ece362015-02-11 10:51:10 +00001356 return null;
1357 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001358
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001359 // "null" means the no-op crop, preserving the full input image
1360 if (cropHint == null) {
1361 cropHint = new Rect(0, 0, 0, 0);
1362 } else {
1363 if (cropHint.isEmpty()
1364 || cropHint.left < 0
1365 || cropHint.top < 0) {
Christopher Tate98d609c2016-05-18 17:31:58 -07001366 throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001367 }
1368 }
1369
Christopher Tatebe132e62016-02-10 12:59:49 -08001370 final int userId = UserHandle.getCallingUserId();
1371
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001372 synchronized (mLock) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001373 if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
1374 WallpaperData wallpaper;
1375
Christopher Tate8347b632016-04-29 18:59:18 -07001376 /* If we're setting system but not lock, and lock is currently sharing the system
1377 * wallpaper, we need to migrate that image over to being lock-only before
1378 * the caller here writes new bitmap data.
1379 */
1380 if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
1381 if (DEBUG) {
1382 Slog.i(TAG, "Migrating system->lock to preserve");
1383 }
1384 migrateSystemToLockWallpaperLocked(userId);
1385 }
1386
Christopher Tatebe132e62016-02-10 12:59:49 -08001387 wallpaper = getWallpaperSafeLocked(userId, which);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001388 final long ident = Binder.clearCallingIdentity();
1389 try {
Christopher Tatead3c2592016-01-20 18:13:17 -08001390 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001391 if (pfd != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001392 wallpaper.imageWallpaperPending = true;
Christopher Tatebe132e62016-02-10 12:59:49 -08001393 wallpaper.whichPending = which;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001394 wallpaper.setComplete = completion;
1395 wallpaper.cropHint.set(cropHint);
Christopher Tated7faf532016-02-25 12:43:38 -08001396 if ((which & FLAG_SYSTEM) != 0) {
1397 wallpaper.allowBackup = allowBackup;
1398 }
Dianne Hackborn0cd48872009-08-13 18:51:59 -07001399 }
1400 return pfd;
1401 } finally {
1402 Binder.restoreCallingIdentity(ident);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 }
1405 }
1406
Christopher Tate8347b632016-04-29 18:59:18 -07001407 private void migrateSystemToLockWallpaperLocked(int userId) {
1408 WallpaperData sysWP = mWallpaperMap.get(userId);
1409 if (sysWP == null) {
1410 if (DEBUG) {
1411 Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
1412 }
1413 return;
1414 }
1415
1416 // We know a-priori that there is no lock-only wallpaper currently
1417 WallpaperData lockWP = new WallpaperData(userId,
1418 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
1419 lockWP.wallpaperId = sysWP.wallpaperId;
1420 lockWP.cropHint.set(sysWP.cropHint);
1421 lockWP.width = sysWP.width;
1422 lockWP.height = sysWP.height;
1423 lockWP.allowBackup = false;
1424
1425 // Migrate the bitmap files outright; no need to copy
1426 try {
1427 Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
1428 Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
1429 } catch (ErrnoException e) {
1430 Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
1431 lockWP.wallpaperFile.delete();
1432 lockWP.cropFile.delete();
1433 return;
1434 }
1435
1436 mLockWallpaperMap.put(userId, lockWP);
1437 }
1438
Christopher Tatead3c2592016-01-20 18:13:17 -08001439 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
1440 Bundle extras) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001441 if (name == null) name = "";
1442 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001443 File dir = getWallpaperDir(wallpaper.userId);
1444 if (!dir.exists()) {
1445 dir.mkdir();
Dianne Hackbornebac48c2011-11-29 18:01:50 -08001446 FileUtils.setPermissions(
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001447 dir.getPath(),
Dianne Hackbornebac48c2011-11-29 18:01:50 -08001448 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
1449 -1, -1);
1450 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001451 ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
Christopher Tate90f86ba2014-09-11 12:37:19 -07001452 MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
Christopher Tatebe132e62016-02-10 12:59:49 -08001453 if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
rpcraig554cb0c2012-07-05 06:41:43 -04001454 return null;
1455 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001456 wallpaper.name = name;
Christopher Tatead3c2592016-01-20 18:13:17 -08001457 wallpaper.wallpaperId = makeWallpaperIdLocked();
1458 if (extras != null) {
1459 extras.putInt(WallpaperManager.EXTRA_NEW_WALLPAPER_ID, wallpaper.wallpaperId);
1460 }
1461 if (DEBUG) {
1462 Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
Christopher Tatebe132e62016-02-10 12:59:49 -08001463 + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
Christopher Tatead3c2592016-01-20 18:13:17 -08001464 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001465 return fd;
1466 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001467 Slog.w(TAG, "Error setting wallpaper", e);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001468 }
1469 return null;
1470 }
1471
Christopher Tated57d17c2016-03-25 13:41:46 -07001472 @Override
Adrian Roos40ea0832016-07-14 14:19:55 -07001473 public void setWallpaperComponentChecked(ComponentName name, String callingPackage,
1474 int userId) {
1475
Christopher Tate98d609c2016-05-18 17:31:58 -07001476 if (isWallpaperSupported(callingPackage) && isSetWallpaperAllowed(callingPackage)) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001477 setWallpaperComponent(name, userId);
Benjamin Franzf3ece362015-02-11 10:51:10 +00001478 }
1479 }
1480
1481 // ToDo: Remove this version of the function
Christopher Tated57d17c2016-03-25 13:41:46 -07001482 @Override
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001483 public void setWallpaperComponent(ComponentName name) {
Adrian Roos40ea0832016-07-14 14:19:55 -07001484 setWallpaperComponent(name, UserHandle.getCallingUserId());
1485 }
1486
1487 private void setWallpaperComponent(ComponentName name, int userId) {
1488 userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
1489 false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001490 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
Adrian Roos40ea0832016-07-14 14:19:55 -07001491
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001492 synchronized (mLock) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001493 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001494 WallpaperData wallpaper = mWallpaperMap.get(userId);
1495 if (wallpaper == null) {
1496 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
1497 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001498 final long ident = Binder.clearCallingIdentity();
1499 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001500 wallpaper.imageWallpaperPending = false;
Christopher Tated57d17c2016-03-25 13:41:46 -07001501 if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
1502 wallpaper.wallpaperId = makeWallpaperIdLocked();
Sunny Goyal0572e182016-03-31 11:05:51 -07001503 notifyCallbacksLocked(wallpaper);
Christopher Tated57d17c2016-03-25 13:41:46 -07001504 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001505 } finally {
1506 Binder.restoreCallingIdentity(ident);
1507 }
1508 }
1509 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001510
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001511 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001512 boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001513 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001514 // Has the component changed?
Dianne Hackborn9ea31632011-08-05 14:43:50 -07001515 if (!force) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001516 if (wallpaper.connection != null) {
1517 if (wallpaper.wallpaperComponent == null) {
Dianne Hackborn9ea31632011-08-05 14:43:50 -07001518 if (componentName == null) {
1519 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
1520 // Still using default wallpaper.
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001521 return true;
Dianne Hackborn9ea31632011-08-05 14:43:50 -07001522 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001523 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
Dianne Hackborn9ea31632011-08-05 14:43:50 -07001524 // Changing to same wallpaper.
1525 if (DEBUG) Slog.v(TAG, "same wallpaper");
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001526 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001527 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001528 }
1529 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001530
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001531 try {
Mike Clerona428b2c2009-11-15 22:53:08 -08001532 if (componentName == null) {
Jeff Sharkey28f08772014-04-16 09:41:58 -07001533 componentName = WallpaperManager.getDefaultWallpaperComponent(mContext);
Mike Clerona428b2c2009-11-15 22:53:08 -08001534 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -08001535 // Fall back to static image wallpaper
Justin Koh29c30162014-09-05 17:10:10 -07001536 componentName = mImageWallpaper;
Mike Cleron322b6ee2009-11-12 07:45:47 -08001537 //clearWallpaperComponentLocked();
1538 //return;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001539 if (DEBUG) Slog.v(TAG, "Using image wallpaper");
Mike Cleron322b6ee2009-11-12 07:45:47 -08001540 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001541 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001542 int serviceUserId = wallpaper.userId;
1543 ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
1544 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
Christopher Tate90952202013-09-08 13:01:28 -07001545 if (si == null) {
1546 // The wallpaper component we're trying to use doesn't exist
1547 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
1548 return false;
1549 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001550 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001551 String msg = "Selected service does not require "
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001552 + android.Manifest.permission.BIND_WALLPAPER
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001553 + ": " + componentName;
1554 if (fromUser) {
1555 throw new SecurityException(msg);
1556 }
1557 Slog.w(TAG, msg);
1558 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001559 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001560
Dianne Hackborneb034652009-09-07 00:49:58 -07001561 WallpaperInfo wi = null;
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001562
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001563 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
Justin Koh29c30162014-09-05 17:10:10 -07001564 if (componentName != null && !componentName.equals(mImageWallpaper)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001565 // Make sure the selected service is actually a wallpaper service.
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001566 List<ResolveInfo> ris =
1567 mIPackageManager.queryIntentServices(intent,
1568 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
Jeff Sharkeyd5896632016-03-04 16:16:00 -07001569 PackageManager.GET_META_DATA, serviceUserId).getList();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001570 for (int i=0; i<ris.size(); i++) {
1571 ServiceInfo rsi = ris.get(i).serviceInfo;
1572 if (rsi.name.equals(si.name) &&
1573 rsi.packageName.equals(si.packageName)) {
Dianne Hackborneb034652009-09-07 00:49:58 -07001574 try {
1575 wi = new WallpaperInfo(mContext, ris.get(i));
1576 } catch (XmlPullParserException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001577 if (fromUser) {
1578 throw new IllegalArgumentException(e);
1579 }
1580 Slog.w(TAG, e);
1581 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07001582 } catch (IOException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001583 if (fromUser) {
1584 throw new IllegalArgumentException(e);
1585 }
1586 Slog.w(TAG, e);
1587 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -07001588 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001589 break;
1590 }
1591 }
Dianne Hackborneb034652009-09-07 00:49:58 -07001592 if (wi == null) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001593 String msg = "Selected service is not a wallpaper: "
1594 + componentName;
1595 if (fromUser) {
1596 throw new SecurityException(msg);
1597 }
1598 Slog.w(TAG, msg);
1599 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001600 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001601 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001602
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001603 // Bind the service!
Joe Onorato8a9b2202010-02-26 18:56:32 -08001604 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001605 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08001606 intent.setComponent(componentName);
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07001607 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1608 com.android.internal.R.string.wallpaper_binding_label);
Dianne Hackborn41203752012-08-31 14:05:51 -07001609 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
Dianne Hackborneb034652009-09-07 00:49:58 -07001610 mContext, 0,
1611 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
1612 mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
Dianne Hackborn41203752012-08-31 14:05:51 -07001613 0, null, new UserHandle(serviceUserId)));
Dianne Hackbornc8230512013-07-13 21:32:12 -07001614 if (!mContext.bindServiceAsUser(intent, newConn,
Dianne Hackbornd69e4c12015-04-24 09:54:54 -07001615 Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
1616 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
Amith Yamasani27b89e62013-01-16 12:30:11 -08001617 new UserHandle(serviceUserId))) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001618 String msg = "Unable to bind service: "
1619 + componentName;
1620 if (fromUser) {
1621 throw new IllegalArgumentException(msg);
1622 }
1623 Slog.w(TAG, msg);
1624 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001625 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001626 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
1627 detachWallpaperLocked(mLastWallpaper);
1628 }
1629 wallpaper.wallpaperComponent = componentName;
1630 wallpaper.connection = newConn;
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001631 newConn.mReply = reply;
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001632 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001633 if (wallpaper.userId == mCurrentUserId) {
1634 if (DEBUG)
1635 Slog.v(TAG, "Adding window token: " + newConn.mToken);
1636 mIWindowManager.addWindowToken(newConn.mToken,
1637 WindowManager.LayoutParams.TYPE_WALLPAPER);
1638 mLastWallpaper = wallpaper;
1639 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -07001640 } catch (RemoteException e) {
1641 }
Amith Yamasani4e2820c2012-08-28 22:17:23 -07001642 } catch (RemoteException e) {
1643 String msg = "Remote exception for " + componentName + "\n" + e;
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001644 if (fromUser) {
1645 throw new IllegalArgumentException(msg);
1646 }
1647 Slog.w(TAG, msg);
1648 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001649 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -07001650 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001651 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001652
1653 void detachWallpaperLocked(WallpaperData wallpaper) {
1654 if (wallpaper.connection != null) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001655 if (wallpaper.connection.mReply != null) {
1656 try {
1657 wallpaper.connection.mReply.sendResult(null);
1658 } catch (RemoteException e) {
1659 }
1660 wallpaper.connection.mReply = null;
1661 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001662 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001663 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001664 wallpaper.connection.mEngine.destroy();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001665 } catch (RemoteException e) {
1666 }
1667 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001668 mContext.unbindService(wallpaper.connection);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07001669 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001670 if (DEBUG)
1671 Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
1672 mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -07001673 } catch (RemoteException e) {
1674 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001675 wallpaper.connection.mService = null;
1676 wallpaper.connection.mEngine = null;
1677 wallpaper.connection = null;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001678 }
1679 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001680
1681 void clearWallpaperComponentLocked(WallpaperData wallpaper) {
1682 wallpaper.wallpaperComponent = null;
1683 detachWallpaperLocked(wallpaper);
1684 }
1685
1686 void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001687 try {
Dianne Hackborn3be63c02009-08-20 19:31:38 -07001688 conn.mService.attach(conn, conn.mToken,
1689 WindowManager.LayoutParams.TYPE_WALLPAPER, false,
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001690 wallpaper.width, wallpaper.height, wallpaper.padding);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001691 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001692 Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001693 if (!wallpaper.wallpaperUpdating) {
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07001694 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001695 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001696 }
1697 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001698
1699 private void notifyCallbacksLocked(WallpaperData wallpaper) {
1700 final int n = wallpaper.callbacks.beginBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 for (int i = 0; i < n; i++) {
1702 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001703 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 } catch (RemoteException e) {
1705
1706 // The RemoteCallbackList will take care of removing
1707 // the dead object for us.
1708 }
1709 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001710 wallpaper.callbacks.finishBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001712 mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714
1715 private void checkPermission(String permission) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001716 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
1718 + ", must have permission " + permission);
1719 }
1720 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001721
Benjamin Franzf3ece362015-02-11 10:51:10 +00001722 /**
1723 * Certain user types do not support wallpapers (e.g. managed profiles). The check is
1724 * implemented through through the OP_WRITE_WALLPAPER AppOp.
1725 */
1726 public boolean isWallpaperSupported(String callingPackage) {
1727 return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_WRITE_WALLPAPER, Binder.getCallingUid(),
1728 callingPackage) == AppOpsManager.MODE_ALLOWED;
1729 }
1730
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001731 @Override
Christopher Tate98d609c2016-05-18 17:31:58 -07001732 public boolean isSetWallpaperAllowed(String callingPackage) {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001733 final PackageManager pm = mContext.getPackageManager();
1734 String[] uidPackages = pm.getPackagesForUid(Binder.getCallingUid());
1735 boolean uidMatchPackage = Arrays.asList(uidPackages).contains(callingPackage);
1736 if (!uidMatchPackage) {
1737 return false; // callingPackage was faked.
1738 }
1739
1740 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
1741 if (dpm.isDeviceOwnerApp(callingPackage) || dpm.isProfileOwnerApp(callingPackage)) {
1742 return true;
1743 }
1744 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1745 return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
1746 }
1747
Christopher Tated7faf532016-02-25 12:43:38 -08001748 @Override
1749 public boolean isWallpaperBackupEligible(int userId) {
1750 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
1751 throw new SecurityException("Only the system may call isWallpaperBackupEligible");
1752 }
1753
1754 WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
1755 return (wallpaper != null) ? wallpaper.allowBackup : false;
1756 }
1757
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001758 private static JournaledFile makeJournaledFile(int userId) {
Amith Yamasani61f57372012-08-31 12:12:28 -07001759 final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001760 return new JournaledFile(new File(base), new File(base + ".tmp"));
1761 }
1762
Christopher Tatedb27b842016-02-25 14:39:17 -08001763 private void saveSettingsLocked(int userId) {
1764 JournaledFile journal = makeJournaledFile(userId);
1765 FileOutputStream fstream = null;
1766 BufferedOutputStream stream = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001767 try {
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001768 XmlSerializer out = new FastXmlSerializer();
Christopher Tatedb27b842016-02-25 14:39:17 -08001769 fstream = new FileOutputStream(journal.chooseForWrite(), false);
1770 stream = new BufferedOutputStream(fstream);
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001771 out.setOutput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001772 out.startDocument(null, true);
1773
Christopher Tatedb27b842016-02-25 14:39:17 -08001774 WallpaperData wallpaper;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001775
Christopher Tatedb27b842016-02-25 14:39:17 -08001776 wallpaper = mWallpaperMap.get(userId);
1777 if (wallpaper != null) {
1778 writeWallpaperAttributes(out, "wp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001779 }
Christopher Tatedb27b842016-02-25 14:39:17 -08001780 wallpaper = mLockWallpaperMap.get(userId);
1781 if (wallpaper != null) {
1782 writeWallpaperAttributes(out, "kwp", wallpaper);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001783 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001784
1785 out.endDocument();
Christopher Tatedb27b842016-02-25 14:39:17 -08001786
1787 stream.flush(); // also flushes fstream
1788 FileUtils.sync(fstream);
1789 stream.close(); // also closes fstream
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001790 journal.commit();
1791 } catch (IOException e) {
Christopher Tatead3c2592016-01-20 18:13:17 -08001792 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001793 journal.rollback();
1794 }
1795 }
1796
Christopher Tatedb27b842016-02-25 14:39:17 -08001797 private void writeWallpaperAttributes(XmlSerializer out, String tag, WallpaperData wallpaper)
1798 throws IllegalArgumentException, IllegalStateException, IOException {
1799 out.startTag(null, tag);
1800 out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
1801 out.attribute(null, "width", Integer.toString(wallpaper.width));
1802 out.attribute(null, "height", Integer.toString(wallpaper.height));
1803
1804 out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
1805 out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
1806 out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
1807 out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
1808
1809 if (wallpaper.padding.left != 0) {
1810 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
1811 }
1812 if (wallpaper.padding.top != 0) {
1813 out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
1814 }
1815 if (wallpaper.padding.right != 0) {
1816 out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
1817 }
1818 if (wallpaper.padding.bottom != 0) {
1819 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
1820 }
1821
1822 out.attribute(null, "name", wallpaper.name);
1823 if (wallpaper.wallpaperComponent != null
1824 && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
1825 out.attribute(null, "component",
1826 wallpaper.wallpaperComponent.flattenToShortString());
1827 }
Christopher Tated7faf532016-02-25 12:43:38 -08001828
1829 if (wallpaper.allowBackup) {
1830 out.attribute(null, "backup", "true");
1831 }
1832
Christopher Tatedb27b842016-02-25 14:39:17 -08001833 out.endTag(null, tag);
1834 }
1835
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001836 private void migrateFromOld() {
1837 File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
1838 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
1839 if (oldWallpaper.exists()) {
1840 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
1841 oldWallpaper.renameTo(newWallpaper);
1842 }
1843 if (oldInfo.exists()) {
1844 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
1845 oldInfo.renameTo(newInfo);
1846 }
1847 }
1848
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001849 private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
1850 String value = parser.getAttributeValue(null, name);
1851 if (value == null) {
1852 return defValue;
1853 }
1854 return Integer.parseInt(value);
1855 }
1856
Xiaohui Chenac531942015-05-13 13:20:52 -07001857 /**
1858 * Sometimes it is expected the wallpaper map may not have a user's data. E.g. This could
1859 * happen during user switch. The async user switch observer may not have received
1860 * the event yet. We use this safe method when we don't care about this ordering and just
1861 * want to update the data. The data is going to be applied when the user switch observer
1862 * is eventually executed.
1863 */
Christopher Tatebe132e62016-02-10 12:59:49 -08001864 private WallpaperData getWallpaperSafeLocked(int userId, int which) {
1865 // We're setting either just system (work with the system wallpaper),
1866 // both (also work with the system wallpaper), or just the lock
1867 // wallpaper (update against the existing lock wallpaper if any).
1868 // Combined or just-system operations use the 'system' WallpaperData
1869 // for this use; lock-only operations use the dedicated one.
1870 final SparseArray<WallpaperData> whichSet =
Christopher Tateedf7d042016-03-29 18:24:25 -07001871 (which == FLAG_LOCK) ? mLockWallpaperMap : mWallpaperMap;
Christopher Tatebe132e62016-02-10 12:59:49 -08001872 WallpaperData wallpaper = whichSet.get(userId);
Xiaohui Chenac531942015-05-13 13:20:52 -07001873 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001874 // common case, this is the first lookup post-boot of the system or
1875 // unified lock, so we bring up the saved state lazily now and recheck.
Christopher Tated7faf532016-02-25 12:43:38 -08001876 loadSettingsLocked(userId, false);
Christopher Tatebe132e62016-02-10 12:59:49 -08001877 wallpaper = whichSet.get(userId);
1878 // if it's still null here, this is a lock-only operation and there is not
1879 // yet a lock-only wallpaper set for this user, so we need to establish
1880 // it now.
1881 if (wallpaper == null) {
Christopher Tateedf7d042016-03-29 18:24:25 -07001882 if (which == FLAG_LOCK) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001883 wallpaper = new WallpaperData(userId,
1884 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
1885 mLockWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07001886 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08001887 } else {
1888 // sanity fallback: we're in bad shape, but establishing a known
1889 // valid system+lock WallpaperData will keep us from dying.
1890 Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
1891 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
1892 mWallpaperMap.put(userId, wallpaper);
Adrian Roosc28e3a92016-04-14 10:47:52 -07001893 ensureSaneWallpaperData(wallpaper);
Christopher Tatebe132e62016-02-10 12:59:49 -08001894 }
1895 }
Xiaohui Chenac531942015-05-13 13:20:52 -07001896 }
1897 return wallpaper;
1898 }
1899
Christopher Tated7faf532016-02-25 12:43:38 -08001900 private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001901 if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
Benjamin Franzf3ece362015-02-11 10:51:10 +00001902
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001903 JournaledFile journal = makeJournaledFile(userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001904 FileInputStream stream = null;
1905 File file = journal.chooseForRead();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001906 if (!file.exists()) {
1907 // This should only happen one time, when upgrading from a legacy system
1908 migrateFromOld();
1909 }
1910 WallpaperData wallpaper = mWallpaperMap.get(userId);
1911 if (wallpaper == null) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001912 wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
Christopher Tated7faf532016-02-25 12:43:38 -08001913 wallpaper.allowBackup = true;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001914 mWallpaperMap.put(userId, wallpaper);
Christopher Tate41297ff2016-03-10 16:46:15 -08001915 if (!wallpaper.cropExists()) {
1916 generateCrop(wallpaper);
1917 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001918 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001919 boolean success = false;
1920 try {
1921 stream = new FileInputStream(file);
1922 XmlPullParser parser = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001923 parser.setInput(stream, StandardCharsets.UTF_8.name());
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001924
1925 int type;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001926 do {
1927 type = parser.next();
1928 if (type == XmlPullParser.START_TAG) {
1929 String tag = parser.getName();
1930 if ("wp".equals(tag)) {
Christopher Tatebe132e62016-02-10 12:59:49 -08001931 // Common to system + lock wallpapers
Christopher Tated7faf532016-02-25 12:43:38 -08001932 parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
Christopher Tatead3c2592016-01-20 18:13:17 -08001933
Christopher Tatebe132e62016-02-10 12:59:49 -08001934 // A system wallpaper might also be a live wallpaper
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001935 String comp = parser.getAttributeValue(null, "component");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001936 wallpaper.nextWallpaperComponent = comp != null
Dianne Hackborn4c62fc02009-08-08 20:40:27 -07001937 ? ComponentName.unflattenFromString(comp)
1938 : null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001939 if (wallpaper.nextWallpaperComponent == null
1940 || "android".equals(wallpaper.nextWallpaperComponent
1941 .getPackageName())) {
Justin Koh29c30162014-09-05 17:10:10 -07001942 wallpaper.nextWallpaperComponent = mImageWallpaper;
Dianne Hackborn9ea31632011-08-05 14:43:50 -07001943 }
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01001944
Mike Clerona428b2c2009-11-15 22:53:08 -08001945 if (DEBUG) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001946 Slog.v(TAG, "mWidth:" + wallpaper.width);
1947 Slog.v(TAG, "mHeight:" + wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001948 Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001949 Slog.v(TAG, "mName:" + wallpaper.name);
1950 Slog.v(TAG, "mNextWallpaperComponent:"
1951 + wallpaper.nextWallpaperComponent);
Mike Clerona428b2c2009-11-15 22:53:08 -08001952 }
Christopher Tatebe132e62016-02-10 12:59:49 -08001953 } else if ("kwp".equals(tag)) {
1954 // keyguard-specific wallpaper for this user
1955 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
1956 if (lockWallpaper == null) {
1957 lockWallpaper = new WallpaperData(userId,
1958 WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
1959 mLockWallpaperMap.put(userId, lockWallpaper);
1960 }
Christopher Tated7faf532016-02-25 12:43:38 -08001961 parseWallpaperAttributes(parser, lockWallpaper, false);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001962 }
1963 }
1964 } while (type != XmlPullParser.END_DOCUMENT);
1965 success = true;
Dianne Hackborn13579ed2012-11-28 18:05:36 -08001966 } catch (FileNotFoundException e) {
1967 Slog.w(TAG, "no current wallpaper -- first boot?");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001968 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001969 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001970 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001971 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001972 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001973 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001974 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001975 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001976 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001977 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001978 }
Christopher Tatead3c2592016-01-20 18:13:17 -08001979 IoUtils.closeQuietly(stream);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001980
1981 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001982 wallpaper.width = -1;
1983 wallpaper.height = -1;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08001984 wallpaper.cropHint.set(0, 0, 0, 0);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07001985 wallpaper.padding.set(0, 0, 0, 0);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001986 wallpaper.name = "";
Adrian Roosc28e3a92016-04-14 10:47:52 -07001987
1988 mLockWallpaperMap.remove(userId);
Christopher Tatead3c2592016-01-20 18:13:17 -08001989 } else {
1990 if (wallpaper.wallpaperId <= 0) {
1991 wallpaper.wallpaperId = makeWallpaperIdLocked();
1992 if (DEBUG) {
1993 Slog.w(TAG, "Didn't set wallpaper id in loadSettingsLocked(" + userId
1994 + "); now " + wallpaper.wallpaperId);
1995 }
1996 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001997 }
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07001998
Adrian Roosc28e3a92016-04-14 10:47:52 -07001999 ensureSaneWallpaperData(wallpaper);
2000 WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
2001 if (lockWallpaper != null) {
2002 ensureSaneWallpaperData(lockWallpaper);
2003 }
2004 }
2005
2006 private void ensureSaneWallpaperData(WallpaperData wallpaper) {
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002007 // We always want to have some reasonable width hint.
John Spurlock7ea91ec2013-11-04 13:48:38 -05002008 int baseSize = getMaximumSizeDimension();
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002009 if (wallpaper.width < baseSize) {
2010 wallpaper.width = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002011 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002012 if (wallpaper.height < baseSize) {
2013 wallpaper.height = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07002014 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002015 // and crop, if not previously specified
2016 if (wallpaper.cropHint.width() <= 0
2017 || wallpaper.cropHint.height() <= 0) {
2018 wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
2019 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002020 }
2021
Christopher Tated7faf532016-02-25 12:43:38 -08002022 private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
2023 boolean keepDimensionHints) {
Christopher Tatebe132e62016-02-10 12:59:49 -08002024 final String idString = parser.getAttributeValue(null, "id");
2025 if (idString != null) {
2026 final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
2027 if (id > mWallpaperId) {
2028 mWallpaperId = id;
2029 }
2030 } else {
2031 wallpaper.wallpaperId = makeWallpaperIdLocked();
2032 }
2033
Christopher Tated7faf532016-02-25 12:43:38 -08002034 if (!keepDimensionHints) {
2035 wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
2036 wallpaper.height = Integer.parseInt(parser
2037 .getAttributeValue(null, "height"));
2038 }
Christopher Tatebe132e62016-02-10 12:59:49 -08002039 wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
2040 wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
2041 wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
2042 wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
2043 wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
2044 wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
2045 wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
2046 wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
2047 wallpaper.name = parser.getAttributeValue(null, "name");
Christopher Tated7faf532016-02-25 12:43:38 -08002048 wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
Christopher Tatebe132e62016-02-10 12:59:49 -08002049 }
2050
John Spurlock7ea91ec2013-11-04 13:48:38 -05002051 private int getMaximumSizeDimension() {
2052 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
2053 Display d = wm.getDefaultDisplay();
2054 return d.getMaximumSizeDimension();
2055 }
2056
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002057 // Called by SystemBackupAgent after files are restored to disk.
Amith Yamasani09e9cdc2013-11-06 14:54:50 -08002058 public void settingsRestored() {
2059 // Verify caller is the system
2060 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2061 throw new RuntimeException("settingsRestored() can only be called from the system process");
2062 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002063 // TODO: If necessary, make it work for secondary users as well. This currently assumes
2064 // restores only to the primary user
Joe Onorato8a9b2202010-02-26 18:56:32 -08002065 if (DEBUG) Slog.v(TAG, "settingsRestored");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002066 WallpaperData wallpaper = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002067 boolean success = false;
2068 synchronized (mLock) {
Christopher Tated7faf532016-02-25 12:43:38 -08002069 loadSettingsLocked(UserHandle.USER_SYSTEM, false);
Christopher Tatedb27b842016-02-25 14:39:17 -08002070 wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
Christopher Tatead3c2592016-01-20 18:13:17 -08002071 wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
Christopher Tated7faf532016-02-25 12:43:38 -08002072 wallpaper.allowBackup = true; // by definition if it was restored
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002073 if (wallpaper.nextWallpaperComponent != null
Justin Koh29c30162014-09-05 17:10:10 -07002074 && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002075 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002076 wallpaper, null)) {
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002077 // No such live wallpaper or other failure; fall back to the default
2078 // live wallpaper (since the profile being restored indicated that the
2079 // user had selected a live rather than static one).
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002080 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
Christopher Tatee3ab4d02009-12-16 14:03:31 -08002081 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002082 success = true;
2083 } else {
Mike Clerona428b2c2009-11-15 22:53:08 -08002084 // If there's a wallpaper name, we use that. If that can't be loaded, then we
2085 // use the default.
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002086 if ("".equals(wallpaper.name)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002087 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
Mike Clerona428b2c2009-11-15 22:53:08 -08002088 success = true;
2089 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002090 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002091 success = restoreNamedResourceLocked(wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08002092 }
Christopher Tatead3c2592016-01-20 18:13:17 -08002093 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
2094 + " id=" + wallpaper.wallpaperId);
Mike Clerona428b2c2009-11-15 22:53:08 -08002095 if (success) {
Christopher Tate41297ff2016-03-10 16:46:15 -08002096 generateCrop(wallpaper); // based on the new image + metadata
2097 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
Dianne Hackborn5dc5a002012-09-15 19:33:48 -07002098 wallpaper, null);
Mike Clerona428b2c2009-11-15 22:53:08 -08002099 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002100 }
2101 }
2102
2103 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002104 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
2105 wallpaper.name = "";
Christopher Tatedb27b842016-02-25 14:39:17 -08002106 getWallpaperDir(UserHandle.USER_SYSTEM).delete();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002107 }
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002108
2109 synchronized (mLock) {
Christopher Tatedb27b842016-02-25 14:39:17 -08002110 saveSettingsLocked(UserHandle.USER_SYSTEM);
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07002111 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002112 }
2113
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002114 // Restore the named resource bitmap to both source + crop files
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002115 boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
2116 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
2117 String resName = wallpaper.name.substring(4);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002118
2119 String pkg = null;
2120 int colon = resName.indexOf(':');
2121 if (colon > 0) {
2122 pkg = resName.substring(0, colon);
2123 }
2124
2125 String ident = null;
2126 int slash = resName.lastIndexOf('/');
2127 if (slash > 0) {
2128 ident = resName.substring(slash+1);
2129 }
2130
2131 String type = null;
2132 if (colon > 0 && slash > 0 && (slash-colon) > 1) {
2133 type = resName.substring(colon+1, slash);
2134 }
2135
2136 if (pkg != null && ident != null && type != null) {
2137 int resId = -1;
2138 InputStream res = null;
2139 FileOutputStream fos = null;
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002140 FileOutputStream cos = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002141 try {
2142 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
2143 Resources r = c.getResources();
2144 resId = r.getIdentifier(resName, null, null);
2145 if (resId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002146 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002147 + " ident=" + ident);
2148 return false;
2149 }
2150
2151 res = r.openRawResource(resId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002152 if (wallpaper.wallpaperFile.exists()) {
2153 wallpaper.wallpaperFile.delete();
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002154 wallpaper.cropFile.delete();
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07002155 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002156 fos = new FileOutputStream(wallpaper.wallpaperFile);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002157 cos = new FileOutputStream(wallpaper.cropFile);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002158
2159 byte[] buffer = new byte[32768];
2160 int amt;
2161 while ((amt=res.read(buffer)) > 0) {
2162 fos.write(buffer, 0, amt);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002163 cos.write(buffer, 0, amt);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002164 }
2165 // mWallpaperObserver will notice the close and send the change broadcast
2166
Joe Onorato8a9b2202010-02-26 18:56:32 -08002167 Slog.v(TAG, "Restored wallpaper: " + resName);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002168 return true;
2169 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002170 Slog.e(TAG, "Package name " + pkg + " not found");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002171 } catch (Resources.NotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002172 Slog.e(TAG, "Resource not found: " + resId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002173 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002174 Slog.e(TAG, "IOException while restoring wallpaper ", e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002175 } finally {
Christopher Tatead3c2592016-01-20 18:13:17 -08002176 IoUtils.closeQuietly(res);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002177 if (fos != null) {
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07002178 FileUtils.sync(fos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002179 }
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002180 if (cos != null) {
2181 FileUtils.sync(cos);
2182 }
2183 IoUtils.closeQuietly(fos);
2184 IoUtils.closeQuietly(cos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07002185 }
2186 }
2187 }
2188 return false;
2189 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002190
Dianne Hackborneb034652009-09-07 00:49:58 -07002191 @Override
2192 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2193 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2194 != PackageManager.PERMISSION_GRANTED) {
Oleksandr Peletskyif2519812016-01-26 20:16:06 +01002195
Dianne Hackborneb034652009-09-07 00:49:58 -07002196 pw.println("Permission Denial: can't dump wallpaper service from from pid="
2197 + Binder.getCallingPid()
2198 + ", uid=" + Binder.getCallingUid());
2199 return;
2200 }
2201
2202 synchronized (mLock) {
Adrian Roosc28e3a92016-04-14 10:47:52 -07002203 pw.println("System wallpaper state:");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002204 for (int i = 0; i < mWallpaperMap.size(); i++) {
2205 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
Christopher Tatead3c2592016-01-20 18:13:17 -08002206 pw.print(" User "); pw.print(wallpaper.userId);
Adrian Roosc28e3a92016-04-14 10:47:52 -07002207 pw.print(": id="); pw.println(wallpaper.wallpaperId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002208 pw.print(" mWidth=");
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002209 pw.print(wallpaper.width);
2210 pw.print(" mHeight=");
2211 pw.println(wallpaper.height);
Christopher Tate1e1e2e02016-01-25 15:34:36 -08002212 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
Dianne Hackborn067e5f62014-09-07 23:14:30 -07002213 pw.print(" mPadding="); pw.println(wallpaper.padding);
2214 pw.print(" mName="); pw.println(wallpaper.name);
2215 pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08002216 if (wallpaper.connection != null) {
2217 WallpaperConnection conn = wallpaper.connection;
2218 pw.print(" Wallpaper connection ");
2219 pw.print(conn);
2220 pw.println(":");
2221 if (conn.mInfo != null) {
2222 pw.print(" mInfo.component=");
2223 pw.println(conn.mInfo.getComponent());
2224 }
2225 pw.print(" mToken=");
2226 pw.println(conn.mToken);
2227 pw.print(" mService=");
2228 pw.println(conn.mService);
2229 pw.print(" mEngine=");
2230 pw.println(conn.mEngine);
2231 pw.print(" mLastDiedTime=");
2232 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
2233 }
Dianne Hackborneb034652009-09-07 00:49:58 -07002234 }
Adrian Roosc28e3a92016-04-14 10:47:52 -07002235 pw.println("Lock wallpaper state:");
2236 for (int i = 0; i < mLockWallpaperMap.size(); i++) {
2237 WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
2238 pw.print(" User "); pw.print(wallpaper.userId);
2239 pw.print(": id="); pw.println(wallpaper.wallpaperId);
2240 pw.print(" mWidth="); pw.print(wallpaper.width);
2241 pw.print(" mHeight="); pw.println(wallpaper.height);
2242 pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
2243 pw.print(" mPadding="); pw.println(wallpaper.padding);
2244 pw.print(" mName="); pw.println(wallpaper.name);
2245 }
2246
Dianne Hackborneb034652009-09-07 00:49:58 -07002247 }
2248 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002249}