blob: 8ee12bc5c42ee09da068f3496d2468ca66ba2b81 [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
17package com.android.server;
18
19import static android.os.FileObserver.*;
20import static android.os.ParcelFileDescriptor.*;
Christopher Tate111bd4a2009-06-24 17:29:38 -070021
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070022import android.app.IWallpaperManager;
23import android.app.IWallpaperManagerCallback;
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070024import android.app.PendingIntent;
Dianne Hackborneb034652009-09-07 00:49:58 -070025import android.app.WallpaperInfo;
Christopher Tate45281862010-03-05 15:46:30 -080026import android.app.backup.BackupManager;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080027import android.app.backup.WallpaperBackupHelper;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070028import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.content.Context;
30import android.content.Intent;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070031import android.content.ServiceConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.pm.PackageManager;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070033import android.content.pm.ResolveInfo;
34import android.content.pm.ServiceInfo;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070035import android.content.pm.PackageManager.NameNotFoundException;
36import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.Binder;
Dianne Hackborn284ac932009-08-28 10:34:25 -070038import android.os.Bundle;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070039import android.os.FileUtils;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070040import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.RemoteException;
42import android.os.FileObserver;
43import android.os.ParcelFileDescriptor;
44import android.os.RemoteCallbackList;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070045import android.os.ServiceManager;
Dianne Hackborn0cd48872009-08-13 18:51:59 -070046import android.os.SystemClock;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080047import android.os.UserId;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070048import android.service.wallpaper.IWallpaperConnection;
49import android.service.wallpaper.IWallpaperEngine;
50import android.service.wallpaper.IWallpaperService;
51import android.service.wallpaper.WallpaperService;
Joe Onorato8a9b2202010-02-26 18:56:32 -080052import android.util.Slog;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080053import android.util.SparseArray;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070054import android.util.Xml;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -070055import android.view.Display;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070056import android.view.IWindowManager;
57import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Dianne Hackborneb034652009-09-07 00:49:58 -070059import java.io.FileDescriptor;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070060import java.io.IOException;
61import java.io.InputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import java.io.File;
63import java.io.FileNotFoundException;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070064import java.io.FileInputStream;
65import java.io.FileOutputStream;
Dianne Hackborneb034652009-09-07 00:49:58 -070066import java.io.PrintWriter;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070067import java.util.List;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070068
69import org.xmlpull.v1.XmlPullParser;
70import org.xmlpull.v1.XmlPullParserException;
71import org.xmlpull.v1.XmlSerializer;
72
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080073import com.android.internal.content.PackageMonitor;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080074import com.android.internal.util.FastXmlSerializer;
Dianne Hackborn1afd1c92010-03-18 22:47:17 -070075import com.android.internal.util.JournaledFile;
Amith Yamasani37ce3a82012-02-06 12:04:42 -080076import com.android.server.am.ActivityManagerService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
Dianne Hackborn8cc6a502009-08-05 21:29:42 -070078class WallpaperManagerService extends IWallpaperManager.Stub {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -070079 static final String TAG = "WallpaperService";
Dianne Hackborncbf15042009-08-18 18:29:09 -070080 static final boolean DEBUG = false;
Joe Onorato9bb8fd72009-07-28 18:24:51 -070081
Romain Guy407ec782011-08-24 17:06:58 -070082 final Object mLock = new Object[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
Dianne Hackborn0cd48872009-08-13 18:51:59 -070084 /**
85 * Minimum time between crashes of a wallpaper service for us to consider
86 * restarting it vs. just reverting to the static wallpaper.
87 */
88 static final long MIN_WALLPAPER_CRASH_TIME = 10000;
89
Amith Yamasani37ce3a82012-02-06 12:04:42 -080090 static final File WALLPAPER_BASE_DIR = new File("/data/system/users");
Dianne Hackborn0cd48872009-08-13 18:51:59 -070091 static final String WALLPAPER = "wallpaper";
Amith Yamasani37ce3a82012-02-06 12:04:42 -080092 static final String WALLPAPER_INFO = "wallpaper_info.xml";
Joe Onorato9bb8fd72009-07-28 18:24:51 -070093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 /**
95 * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
96 * that the wallpaper has changed. The CREATE is triggered when there is no
97 * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
98 * everytime the wallpaper is changed.
99 */
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800100 private class WallpaperObserver extends FileObserver {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700101
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800102 final WallpaperData mWallpaper;
103 final File mWallpaperDir;
104 final File mWallpaperFile;
105
106 public WallpaperObserver(WallpaperData wallpaper) {
107 super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
108 CLOSE_WRITE | DELETE | DELETE_SELF);
109 mWallpaperDir = getWallpaperDir(wallpaper.userId);
110 mWallpaper = wallpaper;
111 mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
112 }
113
114 @Override
115 public void onEvent(int event, String path) {
116 if (path == null) {
117 return;
118 }
119 synchronized (mLock) {
120 // changing the wallpaper means we'll need to back up the new one
121 long origId = Binder.clearCallingIdentity();
122 BackupManager bm = new BackupManager(mContext);
123 bm.dataChanged();
124 Binder.restoreCallingIdentity(origId);
125
126 File changedFile = new File(mWallpaperDir, path);
127 if (mWallpaperFile.equals(changedFile)) {
128 notifyCallbacksLocked(mWallpaper);
129 if (mWallpaper.wallpaperComponent == null || event != CLOSE_WRITE
130 || mWallpaper.imageWallpaperPending) {
131 if (event == CLOSE_WRITE) {
132 mWallpaper.imageWallpaperPending = false;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700133 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800134 bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
135 false, mWallpaper);
136 saveSettingsLocked(mWallpaper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 }
138 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800139 }
140 }
141 }
142
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700143 final Context mContext;
144 final IWindowManager mIWindowManager;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800145 final MyPackageMonitor mMonitor;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800146 WallpaperData mLastWallpaper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800148 SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
Dianne Hackborn07213e62011-08-24 20:05:39 -0700149
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800150 int mCurrentUserId;
Dianne Hackborn07213e62011-08-24 20:05:39 -0700151
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800152 static class WallpaperData {
153
154 int userId;
155
156 File wallpaperFile;
157
158 /**
159 * Client is currently writing a new image wallpaper.
160 */
161 boolean imageWallpaperPending;
162
163 /**
164 * Resource name if using a picture from the wallpaper gallery
165 */
166 String name = "";
167
168 /**
169 * The component name of the currently set live wallpaper.
170 */
171 ComponentName wallpaperComponent;
172
173 /**
174 * The component name of the wallpaper that should be set next.
175 */
176 ComponentName nextWallpaperComponent;
177
178 /**
179 * Name of the component used to display bitmap wallpapers from either the gallery or
180 * built-in wallpapers.
181 */
182 ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
183 "com.android.systemui.ImageWallpaper");
184
185 WallpaperConnection connection;
186 long lastDiedTime;
187 boolean wallpaperUpdating;
188 WallpaperObserver wallpaperObserver;
189
190 /**
191 * List of callbacks registered they should each be notified when the wallpaper is changed.
192 */
193 private RemoteCallbackList<IWallpaperManagerCallback> callbacks
194 = new RemoteCallbackList<IWallpaperManagerCallback>();
195
196 int width = -1;
197 int height = -1;
198
199 WallpaperData(int userId) {
200 this.userId = userId;
201 wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
202 }
203 }
204
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700205 class WallpaperConnection extends IWallpaperConnection.Stub
206 implements ServiceConnection {
Dianne Hackborneb034652009-09-07 00:49:58 -0700207 final WallpaperInfo mInfo;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700208 final Binder mToken = new Binder();
209 IWallpaperService mService;
210 IWallpaperEngine mEngine;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800211 WallpaperData mWallpaper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800213 public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700214 mInfo = info;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800215 mWallpaper = wallpaper;
Dianne Hackborneb034652009-09-07 00:49:58 -0700216 }
217
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700218 public void onServiceConnected(ComponentName name, IBinder service) {
219 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800220 if (mWallpaper.connection == this) {
221 mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700222 mService = IWallpaperService.Stub.asInterface(service);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800223 attachServiceLocked(this, mWallpaper);
Dianne Hackborneb034652009-09-07 00:49:58 -0700224 // XXX should probably do saveSettingsLocked() later
225 // when we have an engine, but I'm not sure about
226 // locking there and anyway we always need to be able to
227 // recover if there is something wrong.
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800228 saveSettingsLocked(mWallpaper);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700229 }
230 }
231 }
232
233 public void onServiceDisconnected(ComponentName name) {
234 synchronized (mLock) {
235 mService = null;
236 mEngine = null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800237 if (mWallpaper.connection == this) {
238 Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
239 if (!mWallpaper.wallpaperUpdating
240 && (mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME)
241 > SystemClock.uptimeMillis()
242 && mWallpaper.userId == mCurrentUserId) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800243 Slog.w(TAG, "Reverting to built-in wallpaper!");
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800244 clearWallpaperLocked(true, mWallpaper.userId);
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700245 }
246 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700247 }
248 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800249
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700250 public void attachEngine(IWallpaperEngine engine) {
251 mEngine = engine;
252 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800253
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700254 public ParcelFileDescriptor setWallpaper(String name) {
255 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800256 if (mWallpaper.connection == this) {
257 return updateWallpaperBitmapLocked(name, mWallpaper);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700258 }
259 return null;
260 }
261 }
262 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800263
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800264 class MyPackageMonitor extends PackageMonitor {
265 @Override
266 public void onPackageUpdateFinished(String packageName, int uid) {
267 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800268 for (int i = 0; i < mWallpaperMap.size(); i++) {
269 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
270 if (wallpaper.wallpaperComponent != null
271 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
272 wallpaper.wallpaperUpdating = false;
273 ComponentName comp = wallpaper.wallpaperComponent;
274 clearWallpaperComponentLocked(wallpaper);
275 // Do this only for the current user's wallpaper
276 if (wallpaper.userId == mCurrentUserId
277 && !bindWallpaperComponentLocked(comp, false, false, wallpaper)) {
278 Slog.w(TAG, "Wallpaper no longer available; reverting to default");
279 clearWallpaperLocked(false, wallpaper.userId);
280 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700281 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800282 }
283 }
284 }
285
286 @Override
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700287 public void onPackageModified(String packageName) {
288 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800289 for (int i = 0; i < mWallpaperMap.size(); i++) {
290 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
291 if (wallpaper.wallpaperComponent == null
292 || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
293 continue;
294 }
295 doPackagesChanged(true, wallpaper);
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700296 }
297 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700298 }
299
300 @Override
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800301 public void onPackageUpdateStarted(String packageName, int uid) {
302 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800303 for (int i = 0; i < mWallpaperMap.size(); i++) {
304 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
305 if (wallpaper.wallpaperComponent != null
306 && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
307 wallpaper.wallpaperUpdating = true;
308 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800309 }
310 }
311 }
312
313 @Override
314 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800315 boolean changed = false;
316 for (int i = 0; i < mWallpaperMap.size(); i++) {
317 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
318 boolean res = doPackagesChanged(doit, wallpaper);
319 changed |= res;
320 }
321 return changed;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800322 }
323
324 @Override
325 public void onSomePackagesChanged() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800326 for (int i = 0; i < mWallpaperMap.size(); i++) {
327 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
328 doPackagesChanged(true, wallpaper);
329 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800330 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800331
332 boolean doPackagesChanged(boolean doit, WallpaperData wallpaper) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800333 boolean changed = false;
334 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800335 if (wallpaper.wallpaperComponent != null) {
336 int change = isPackageDisappearing(wallpaper.wallpaperComponent
337 .getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800338 if (change == PACKAGE_PERMANENT_CHANGE
339 || change == PACKAGE_TEMPORARY_CHANGE) {
340 changed = true;
341 if (doit) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800342 Slog.w(TAG, "Wallpaper uninstalled, removing: "
343 + wallpaper.wallpaperComponent);
344 clearWallpaperLocked(false, wallpaper.userId);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800345 }
346 }
347 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800348 if (wallpaper.nextWallpaperComponent != null) {
349 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
350 .getPackageName());
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800351 if (change == PACKAGE_PERMANENT_CHANGE
352 || change == PACKAGE_TEMPORARY_CHANGE) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800353 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800354 }
355 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800356 if (wallpaper.wallpaperComponent != null
357 && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800358 try {
359 mContext.getPackageManager().getServiceInfo(
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800360 wallpaper.wallpaperComponent, 0);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800361 } catch (NameNotFoundException e) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800362 Slog.w(TAG, "Wallpaper component gone, removing: "
363 + wallpaper.wallpaperComponent);
364 clearWallpaperLocked(false, wallpaper.userId);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800365 }
366 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800367 if (wallpaper.nextWallpaperComponent != null
368 && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800369 try {
370 mContext.getPackageManager().getServiceInfo(
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800371 wallpaper.nextWallpaperComponent, 0);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800372 } catch (NameNotFoundException e) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800373 wallpaper.nextWallpaperComponent = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800374 }
375 }
376 }
377 return changed;
378 }
379 }
380
Dianne Hackborn8cc6a502009-08-05 21:29:42 -0700381 public WallpaperManagerService(Context context) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800382 if (DEBUG) Slog.v(TAG, "WallpaperService startup");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 mContext = context;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700384 mIWindowManager = IWindowManager.Stub.asInterface(
385 ServiceManager.getService(Context.WINDOW_SERVICE));
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800386 mMonitor = new MyPackageMonitor();
387 mMonitor.register(context, true);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800388 WALLPAPER_BASE_DIR.mkdirs();
389 loadSettingsLocked(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
391
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800392 private static File getWallpaperDir(int userId) {
393 return new File(WALLPAPER_BASE_DIR + "/" + userId);
394 }
395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 @Override
397 protected void finalize() throws Throwable {
398 super.finalize();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800399 for (int i = 0; i < mWallpaperMap.size(); i++) {
400 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
401 wallpaper.wallpaperObserver.stopWatching();
402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700405 public void systemReady() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800406 if (DEBUG) Slog.v(TAG, "systemReady");
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800407 WallpaperData wallpaper = mWallpaperMap.get(0);
408 switchWallpaper(wallpaper);
409 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
410 wallpaper.wallpaperObserver.startWatching();
411 ActivityManagerService ams = (ActivityManagerService) ServiceManager
412 .getService(Context.ACTIVITY_SERVICE);
413 ams.addUserListener(new ActivityManagerService.UserListener() {
414
415 @Override
416 public void onUserChanged(int userId) {
417 switchUser(userId);
418 }
419
420 @Override
421 public void onUserAdded(int userId) {
422 }
423
424 @Override
425 public void onUserRemoved(int userId) {
426 }
427
428 @Override
429 public void onUserLoggedOut(int userId) {
430 }
431
432 });
433 }
434
435 String getName() {
436 return mWallpaperMap.get(0).name;
437 }
438
439 void switchUser(int userId) {
440 synchronized (mLock) {
441 mCurrentUserId = userId;
442 WallpaperData wallpaper = mWallpaperMap.get(userId);
443 if (wallpaper == null) {
444 wallpaper = new WallpaperData(userId);
445 mWallpaperMap.put(userId, wallpaper);
446 loadSettingsLocked(userId);
447 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
448 wallpaper.wallpaperObserver.startWatching();
449 }
450 switchWallpaper(wallpaper);
451 }
452 }
453
454 void switchWallpaper(WallpaperData wallpaper) {
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700455 synchronized (mLock) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700456 RuntimeException e = null;
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700457 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800458 ComponentName cname = wallpaper.wallpaperComponent != null ?
459 wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
460 if (bindWallpaperComponentLocked(cname, true, false, wallpaper)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700461 return;
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700462 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700463 } catch (RuntimeException e1) {
464 e = e1;
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700465 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700466 Slog.w(TAG, "Failure starting previous wallpaper", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800467 clearWallpaperLocked(false, wallpaper.userId);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800468 }
469 }
470
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800471 public void clearWallpaper() {
472 if (DEBUG) Slog.v(TAG, "clearWallpaper");
473 synchronized (mLock) {
474 clearWallpaperLocked(false, UserId.getCallingUserId());
475 }
476 }
477
478 void clearWallpaperLocked(boolean defaultFailed, int userId) {
479 WallpaperData wallpaper = mWallpaperMap.get(userId);
480 File f = new File(getWallpaperDir(userId), WALLPAPER);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800481 if (f.exists()) {
482 f.delete();
483 }
484 final long ident = Binder.clearCallingIdentity();
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700485 RuntimeException e = null;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800486 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800487 wallpaper.imageWallpaperPending = false;
488 if (userId != mCurrentUserId) return;
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700489 if (bindWallpaperComponentLocked(defaultFailed
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800490 ? wallpaper.imageWallpaperComponent
491 : null, true, false, wallpaper)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700492 return;
493 }
494 } catch (IllegalArgumentException e1) {
495 e = e1;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800496 } finally {
497 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700499
500 // This can happen if the default wallpaper component doesn't
501 // exist. This should be a system configuration problem, but
502 // let's not let it crash the system and just live with no
503 // wallpaper.
504 Slog.e(TAG, "Default wallpaper component not found!", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800505 clearWallpaperComponentLocked(wallpaper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
507
508 public void setDimensionHints(int width, int height) throws RemoteException {
509 checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
510
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800511 int userId = UserId.getCallingUserId();
512 WallpaperData wallpaper = mWallpaperMap.get(userId);
513 if (wallpaper == null) {
514 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 if (width <= 0 || height <= 0) {
517 throw new IllegalArgumentException("width and height must be > 0");
518 }
519
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700520 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800521 if (width != wallpaper.width || height != wallpaper.height) {
522 wallpaper.width = width;
523 wallpaper.height = height;
524 saveSettingsLocked(wallpaper);
525 if (mCurrentUserId != userId) return; // Don't change the properties now
526 if (wallpaper.connection != null) {
527 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700528 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800529 wallpaper.connection.mEngine.setDesiredSize(
Dianne Hackborn284ac932009-08-28 10:34:25 -0700530 width, height);
531 } catch (RemoteException e) {
532 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800533 notifyCallbacksLocked(wallpaper);
Dianne Hackborn284ac932009-08-28 10:34:25 -0700534 }
535 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
538 }
539
540 public int getWidthHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700541 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800542 WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
543 return wallpaper.width;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700544 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 }
546
547 public int getHeightHint() throws RemoteException {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700548 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800549 WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
550 return wallpaper.height;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 }
553
Dianne Hackborn284ac932009-08-28 10:34:25 -0700554 public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
555 Bundle outParams) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700556 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800557 // This returns the current user's wallpaper, if called by a system service. Else it
558 // returns the wallpaper for the calling user.
559 int callingUid = Binder.getCallingUid();
560 int wallpaperUserId = 0;
561 if (callingUid == android.os.Process.SYSTEM_UID) {
562 wallpaperUserId = mCurrentUserId;
563 } else {
564 wallpaperUserId = UserId.getUserId(callingUid);
565 }
566 WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700567 try {
Dianne Hackborn284ac932009-08-28 10:34:25 -0700568 if (outParams != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800569 outParams.putInt("width", wallpaper.width);
570 outParams.putInt("height", wallpaper.height);
Dianne Hackborn284ac932009-08-28 10:34:25 -0700571 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800572 wallpaper.callbacks.register(cb);
573 File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700574 if (!f.exists()) {
575 return null;
576 }
577 return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
578 } catch (FileNotFoundException e) {
579 /* Shouldn't happen as we check to see if the file exists */
Joe Onorato8a9b2202010-02-26 18:56:32 -0800580 Slog.w(TAG, "Error getting wallpaper", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700582 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 }
585
Dianne Hackborneb034652009-09-07 00:49:58 -0700586 public WallpaperInfo getWallpaperInfo() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800587 int userId = UserId.getCallingUserId();
Dianne Hackborneb034652009-09-07 00:49:58 -0700588 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800589 WallpaperData wallpaper = mWallpaperMap.get(userId);
590 if (wallpaper.connection != null) {
591 return wallpaper.connection.mInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700592 }
593 return null;
594 }
595 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800596
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700597 public ParcelFileDescriptor setWallpaper(String name) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800598 if (DEBUG) Slog.v(TAG, "setWallpaper");
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800599 int userId = UserId.getCallingUserId();
600 WallpaperData wallpaper = mWallpaperMap.get(userId);
601 if (wallpaper == null) {
602 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 checkPermission(android.Manifest.permission.SET_WALLPAPER);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700605 synchronized (mLock) {
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700606 final long ident = Binder.clearCallingIdentity();
607 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800608 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700609 if (pfd != null) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800610 wallpaper.imageWallpaperPending = true;
Dianne Hackborn0cd48872009-08-13 18:51:59 -0700611 }
612 return pfd;
613 } finally {
614 Binder.restoreCallingIdentity(ident);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 }
617 }
618
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800619 ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700620 if (name == null) name = "";
621 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800622 File dir = getWallpaperDir(wallpaper.userId);
623 if (!dir.exists()) {
624 dir.mkdir();
Dianne Hackbornebac48c2011-11-29 18:01:50 -0800625 FileUtils.setPermissions(
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800626 dir.getPath(),
Dianne Hackbornebac48c2011-11-29 18:01:50 -0800627 FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
628 -1, -1);
629 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800630 ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700631 MODE_CREATE|MODE_READ_WRITE);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800632 wallpaper.name = name;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700633 return fd;
634 } catch (FileNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800635 Slog.w(TAG, "Error setting wallpaper", e);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700636 }
637 return null;
638 }
639
640 public void setWallpaperComponent(ComponentName name) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800641 if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800642 int userId = UserId.getCallingUserId();
643 WallpaperData wallpaper = mWallpaperMap.get(userId);
644 if (wallpaper == null) {
645 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
646 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700647 checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
648 synchronized (mLock) {
649 final long ident = Binder.clearCallingIdentity();
650 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800651 wallpaper.imageWallpaperPending = false;
652 bindWallpaperComponentLocked(name, false, true, wallpaper);
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700653 } finally {
654 Binder.restoreCallingIdentity(ident);
655 }
656 }
657 }
658
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800659 boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
660 boolean fromUser, WallpaperData wallpaper) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800661 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700662 // Has the component changed?
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700663 if (!force) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800664 if (wallpaper.connection != null) {
665 if (wallpaper.wallpaperComponent == null) {
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700666 if (componentName == null) {
667 if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
668 // Still using default wallpaper.
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700669 return true;
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700670 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800671 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700672 // Changing to same wallpaper.
673 if (DEBUG) Slog.v(TAG, "same wallpaper");
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700674 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700675 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700676 }
677 }
678
679 try {
Mike Clerona428b2c2009-11-15 22:53:08 -0800680 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -0800681 String defaultComponent =
682 mContext.getString(com.android.internal.R.string.default_wallpaper_component);
Mike Clerona428b2c2009-11-15 22:53:08 -0800683 if (defaultComponent != null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -0800684 // See if there is a default wallpaper component specified
Mike Clerona428b2c2009-11-15 22:53:08 -0800685 componentName = ComponentName.unflattenFromString(defaultComponent);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800686 if (DEBUG) Slog.v(TAG, "Use default component wallpaper:" + componentName);
Mike Cleron322b6ee2009-11-12 07:45:47 -0800687 }
Mike Clerona428b2c2009-11-15 22:53:08 -0800688 if (componentName == null) {
Mike Cleron322b6ee2009-11-12 07:45:47 -0800689 // Fall back to static image wallpaper
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800690 componentName = wallpaper.imageWallpaperComponent;
Mike Cleron322b6ee2009-11-12 07:45:47 -0800691 //clearWallpaperComponentLocked();
692 //return;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800693 if (DEBUG) Slog.v(TAG, "Using image wallpaper");
Mike Cleron322b6ee2009-11-12 07:45:47 -0800694 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700695 }
Mike Clerona428b2c2009-11-15 22:53:08 -0800696 ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700697 PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS);
698 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700699 String msg = "Selected service does not require "
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700700 + android.Manifest.permission.BIND_WALLPAPER
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700701 + ": " + componentName;
702 if (fromUser) {
703 throw new SecurityException(msg);
704 }
705 Slog.w(TAG, msg);
706 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700707 }
708
Dianne Hackborneb034652009-09-07 00:49:58 -0700709 WallpaperInfo wi = null;
710
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700711 Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800712 if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700713 // Make sure the selected service is actually a wallpaper service.
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700714 List<ResolveInfo> ris = mContext.getPackageManager()
Dianne Hackborneb034652009-09-07 00:49:58 -0700715 .queryIntentServices(intent, PackageManager.GET_META_DATA);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700716 for (int i=0; i<ris.size(); i++) {
717 ServiceInfo rsi = ris.get(i).serviceInfo;
718 if (rsi.name.equals(si.name) &&
719 rsi.packageName.equals(si.packageName)) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700720 try {
721 wi = new WallpaperInfo(mContext, ris.get(i));
722 } catch (XmlPullParserException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700723 if (fromUser) {
724 throw new IllegalArgumentException(e);
725 }
726 Slog.w(TAG, e);
727 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -0700728 } catch (IOException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700729 if (fromUser) {
730 throw new IllegalArgumentException(e);
731 }
732 Slog.w(TAG, e);
733 return false;
Dianne Hackborneb034652009-09-07 00:49:58 -0700734 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700735 break;
736 }
737 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700738 if (wi == null) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700739 String msg = "Selected service is not a wallpaper: "
740 + componentName;
741 if (fromUser) {
742 throw new SecurityException(msg);
743 }
744 Slog.w(TAG, msg);
745 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700746 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700747 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700748
749 // Bind the service!
Joe Onorato8a9b2202010-02-26 18:56:32 -0800750 if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800751 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -0800752 intent.setComponent(componentName);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800753 int serviceUserId = wallpaper.userId;
754 // Because the image wallpaper is running in the system ui
755 if (componentName.equals(wallpaper.imageWallpaperComponent)) {
756 serviceUserId = 0;
757 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -0700758 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
759 com.android.internal.R.string.wallpaper_binding_label);
760 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
Dianne Hackborneb034652009-09-07 00:49:58 -0700761 mContext, 0,
762 Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
763 mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
764 0));
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800765 if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE, serviceUserId)) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700766 String msg = "Unable to bind service: "
767 + componentName;
768 if (fromUser) {
769 throw new IllegalArgumentException(msg);
770 }
771 Slog.w(TAG, msg);
772 return false;
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700773 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800774 if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
775 detachWallpaperLocked(mLastWallpaper);
776 }
777 wallpaper.wallpaperComponent = componentName;
778 wallpaper.connection = newConn;
779 wallpaper.lastDiedTime = SystemClock.uptimeMillis();
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700780 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800781 if (wallpaper.userId == mCurrentUserId) {
782 if (DEBUG)
783 Slog.v(TAG, "Adding window token: " + newConn.mToken);
784 mIWindowManager.addWindowToken(newConn.mToken,
785 WindowManager.LayoutParams.TYPE_WALLPAPER);
786 mLastWallpaper = wallpaper;
787 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700788 } catch (RemoteException e) {
789 }
Dianne Hackbornf21adf62009-08-13 10:20:21 -0700790 } catch (PackageManager.NameNotFoundException e) {
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700791 String msg = "Unknown component " + componentName;
792 if (fromUser) {
793 throw new IllegalArgumentException(msg);
794 }
795 Slog.w(TAG, msg);
796 return false;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700797 }
Dianne Hackborn80b902f2011-09-15 15:15:27 -0700798 return true;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700799 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800800
801 void detachWallpaperLocked(WallpaperData wallpaper) {
802 if (wallpaper.connection != null) {
803 if (wallpaper.connection.mEngine != null) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700804 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800805 wallpaper.connection.mEngine.destroy();
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700806 } catch (RemoteException e) {
807 }
808 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800809 mContext.unbindService(wallpaper.connection);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -0700810 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800811 if (DEBUG)
812 Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
813 mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
Dianne Hackborne9e9bca2009-08-18 15:08:22 -0700814 } catch (RemoteException e) {
815 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800816 wallpaper.connection.mService = null;
817 wallpaper.connection.mEngine = null;
818 wallpaper.connection = null;
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700819 }
820 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800821
822 void clearWallpaperComponentLocked(WallpaperData wallpaper) {
823 wallpaper.wallpaperComponent = null;
824 detachWallpaperLocked(wallpaper);
825 }
826
827 void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700828 try {
Dianne Hackborn3be63c02009-08-20 19:31:38 -0700829 conn.mService.attach(conn, conn.mToken,
830 WindowManager.LayoutParams.TYPE_WALLPAPER, false,
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800831 wallpaper.width, wallpaper.height);
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700832 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800833 Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800834 if (!wallpaper.wallpaperUpdating) {
835 bindWallpaperComponentLocked(null, false, false, wallpaper);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800836 }
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700837 }
838 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800839
840 private void notifyCallbacksLocked(WallpaperData wallpaper) {
841 final int n = wallpaper.callbacks.beginBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 for (int i = 0; i < n; i++) {
843 try {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800844 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 } catch (RemoteException e) {
846
847 // The RemoteCallbackList will take care of removing
848 // the dead object for us.
849 }
850 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800851 wallpaper.callbacks.finishBroadcast();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
853 mContext.sendBroadcast(intent);
854 }
855
856 private void checkPermission(String permission) {
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700857 if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
859 + ", must have permission " + permission);
860 }
861 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700862
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800863 private static JournaledFile makeJournaledFile(int userId) {
864 final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700865 return new JournaledFile(new File(base), new File(base + ".tmp"));
866 }
867
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800868 private void saveSettingsLocked(WallpaperData wallpaper) {
869 JournaledFile journal = makeJournaledFile(wallpaper.userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700870 FileOutputStream stream = null;
871 try {
872 stream = new FileOutputStream(journal.chooseForWrite(), false);
873 XmlSerializer out = new FastXmlSerializer();
874 out.setOutput(stream, "utf-8");
875 out.startDocument(null, true);
876
877 out.startTag(null, "wp");
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800878 out.attribute(null, "width", Integer.toString(wallpaper.width));
879 out.attribute(null, "height", Integer.toString(wallpaper.height));
880 out.attribute(null, "name", wallpaper.name);
881 if (wallpaper.wallpaperComponent != null
882 && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700883 out.attribute(null, "component",
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800884 wallpaper.wallpaperComponent.flattenToShortString());
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700885 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700886 out.endTag(null, "wp");
887
888 out.endDocument();
889 stream.close();
890 journal.commit();
891 } catch (IOException e) {
892 try {
893 if (stream != null) {
894 stream.close();
895 }
896 } catch (IOException ex) {
897 // Ignore
898 }
899 journal.rollback();
900 }
901 }
902
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800903 private void migrateFromOld() {
904 File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
905 File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
906 if (oldWallpaper.exists()) {
907 File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
908 oldWallpaper.renameTo(newWallpaper);
909 }
910 if (oldInfo.exists()) {
911 File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
912 oldInfo.renameTo(newInfo);
913 }
914 }
915
916 private void loadSettingsLocked(int userId) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800917 if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
Mike Clerona428b2c2009-11-15 22:53:08 -0800918
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800919 JournaledFile journal = makeJournaledFile(userId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700920 FileInputStream stream = null;
921 File file = journal.chooseForRead();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800922 if (!file.exists()) {
923 // This should only happen one time, when upgrading from a legacy system
924 migrateFromOld();
925 }
926 WallpaperData wallpaper = mWallpaperMap.get(userId);
927 if (wallpaper == null) {
928 wallpaper = new WallpaperData(userId);
929 mWallpaperMap.put(userId, wallpaper);
930 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700931 boolean success = false;
932 try {
933 stream = new FileInputStream(file);
934 XmlPullParser parser = Xml.newPullParser();
935 parser.setInput(stream, null);
936
937 int type;
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700938 do {
939 type = parser.next();
940 if (type == XmlPullParser.START_TAG) {
941 String tag = parser.getName();
942 if ("wp".equals(tag)) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800943 wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
944 wallpaper.height = Integer.parseInt(parser
945 .getAttributeValue(null, "height"));
946 wallpaper.name = parser.getAttributeValue(null, "name");
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700947 String comp = parser.getAttributeValue(null, "component");
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800948 wallpaper.nextWallpaperComponent = comp != null
Dianne Hackborn4c62fc02009-08-08 20:40:27 -0700949 ? ComponentName.unflattenFromString(comp)
950 : null;
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800951 if (wallpaper.nextWallpaperComponent == null
952 || "android".equals(wallpaper.nextWallpaperComponent
953 .getPackageName())) {
954 wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
Dianne Hackborn9ea31632011-08-05 14:43:50 -0700955 }
Mike Clerona428b2c2009-11-15 22:53:08 -0800956
957 if (DEBUG) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800958 Slog.v(TAG, "mWidth:" + wallpaper.width);
959 Slog.v(TAG, "mHeight:" + wallpaper.height);
960 Slog.v(TAG, "mName:" + wallpaper.name);
961 Slog.v(TAG, "mNextWallpaperComponent:"
962 + wallpaper.nextWallpaperComponent);
Mike Clerona428b2c2009-11-15 22:53:08 -0800963 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700964 }
965 }
966 } while (type != XmlPullParser.END_DOCUMENT);
967 success = true;
968 } catch (NullPointerException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800969 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700970 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800971 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700972 } catch (XmlPullParserException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800973 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700974 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800975 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700976 } catch (IndexOutOfBoundsException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800977 Slog.w(TAG, "failed parsing " + file + " " + e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700978 }
979 try {
980 if (stream != null) {
981 stream.close();
982 }
983 } catch (IOException e) {
984 // Ignore
985 }
986
987 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800988 wallpaper.width = -1;
989 wallpaper.height = -1;
990 wallpaper.name = "";
Joe Onorato9bb8fd72009-07-28 18:24:51 -0700991 }
Dianne Hackborn44bc17c2011-04-20 18:18:51 -0700992
993 // We always want to have some reasonable width hint.
994 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
995 Display d = wm.getDefaultDisplay();
996 int baseSize = d.getMaximumSizeDimension();
Amith Yamasani37ce3a82012-02-06 12:04:42 -0800997 if (wallpaper.width < baseSize) {
998 wallpaper.width = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -0700999 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001000 if (wallpaper.height < baseSize) {
1001 wallpaper.height = baseSize;
Dianne Hackborn44bc17c2011-04-20 18:18:51 -07001002 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001003 }
1004
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07001005 // Called by SystemBackupAgent after files are restored to disk.
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001006 void settingsRestored() {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001007 // TODO: If necessary, make it work for secondary users as well. This currently assumes
1008 // restores only to the primary user
Joe Onorato8a9b2202010-02-26 18:56:32 -08001009 if (DEBUG) Slog.v(TAG, "settingsRestored");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001010 WallpaperData wallpaper = null;
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001011 boolean success = false;
1012 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001013 loadSettingsLocked(0);
1014 wallpaper = mWallpaperMap.get(0);
1015 if (wallpaper.nextWallpaperComponent != null
1016 && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
1017 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
1018 wallpaper)) {
Christopher Tatee3ab4d02009-12-16 14:03:31 -08001019 // No such live wallpaper or other failure; fall back to the default
1020 // live wallpaper (since the profile being restored indicated that the
1021 // user had selected a live rather than static one).
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001022 bindWallpaperComponentLocked(null, false, false, wallpaper);
Christopher Tatee3ab4d02009-12-16 14:03:31 -08001023 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001024 success = true;
1025 } else {
Mike Clerona428b2c2009-11-15 22:53:08 -08001026 // If there's a wallpaper name, we use that. If that can't be loaded, then we
1027 // use the default.
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001028 if ("".equals(wallpaper.name)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001029 if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
Mike Clerona428b2c2009-11-15 22:53:08 -08001030 success = true;
1031 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001032 if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001033 success = restoreNamedResourceLocked(wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08001034 }
Joe Onorato8a9b2202010-02-26 18:56:32 -08001035 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
Mike Clerona428b2c2009-11-15 22:53:08 -08001036 if (success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001037 bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
1038 wallpaper);
Mike Clerona428b2c2009-11-15 22:53:08 -08001039 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001040 }
1041 }
1042
1043 if (!success) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001044 Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
1045 wallpaper.name = "";
1046 getWallpaperDir(0).delete();
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001047 }
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07001048
1049 synchronized (mLock) {
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001050 saveSettingsLocked(wallpaper);
Brad Fitzpatrick194b19a2010-09-14 11:30:29 -07001051 }
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001052 }
1053
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001054 boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
1055 if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
1056 String resName = wallpaper.name.substring(4);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001057
1058 String pkg = null;
1059 int colon = resName.indexOf(':');
1060 if (colon > 0) {
1061 pkg = resName.substring(0, colon);
1062 }
1063
1064 String ident = null;
1065 int slash = resName.lastIndexOf('/');
1066 if (slash > 0) {
1067 ident = resName.substring(slash+1);
1068 }
1069
1070 String type = null;
1071 if (colon > 0 && slash > 0 && (slash-colon) > 1) {
1072 type = resName.substring(colon+1, slash);
1073 }
1074
1075 if (pkg != null && ident != null && type != null) {
1076 int resId = -1;
1077 InputStream res = null;
1078 FileOutputStream fos = null;
1079 try {
1080 Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
1081 Resources r = c.getResources();
1082 resId = r.getIdentifier(resName, null, null);
1083 if (resId == 0) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001084 Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001085 + " ident=" + ident);
1086 return false;
1087 }
1088
1089 res = r.openRawResource(resId);
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001090 if (wallpaper.wallpaperFile.exists()) {
1091 wallpaper.wallpaperFile.delete();
Dianne Hackborn1afd1c92010-03-18 22:47:17 -07001092 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001093 fos = new FileOutputStream(wallpaper.wallpaperFile);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001094
1095 byte[] buffer = new byte[32768];
1096 int amt;
1097 while ((amt=res.read(buffer)) > 0) {
1098 fos.write(buffer, 0, amt);
1099 }
1100 // mWallpaperObserver will notice the close and send the change broadcast
1101
Joe Onorato8a9b2202010-02-26 18:56:32 -08001102 Slog.v(TAG, "Restored wallpaper: " + resName);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001103 return true;
1104 } catch (NameNotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001105 Slog.e(TAG, "Package name " + pkg + " not found");
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001106 } catch (Resources.NotFoundException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001107 Slog.e(TAG, "Resource not found: " + resId);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001108 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001109 Slog.e(TAG, "IOException while restoring wallpaper ", e);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001110 } finally {
1111 if (res != null) {
1112 try {
1113 res.close();
1114 } catch (IOException ex) {}
1115 }
1116 if (fos != null) {
Dianne Hackborn8bdf5932010-10-15 12:54:40 -07001117 FileUtils.sync(fos);
Joe Onorato9bb8fd72009-07-28 18:24:51 -07001118 try {
1119 fos.close();
1120 } catch (IOException ex) {}
1121 }
1122 }
1123 }
1124 }
1125 return false;
1126 }
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001127
Dianne Hackborneb034652009-09-07 00:49:58 -07001128 @Override
1129 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1130 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1131 != PackageManager.PERMISSION_GRANTED) {
1132
1133 pw.println("Permission Denial: can't dump wallpaper service from from pid="
1134 + Binder.getCallingPid()
1135 + ", uid=" + Binder.getCallingUid());
1136 return;
1137 }
1138
1139 synchronized (mLock) {
1140 pw.println("Current Wallpaper Service state:");
Amith Yamasani37ce3a82012-02-06 12:04:42 -08001141 for (int i = 0; i < mWallpaperMap.size(); i++) {
1142 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
1143 pw.println(" User " + wallpaper.userId + ":");
1144 pw.print(" mWidth=");
1145 pw.print(wallpaper.width);
1146 pw.print(" mHeight=");
1147 pw.println(wallpaper.height);
1148 pw.print(" mName=");
1149 pw.println(wallpaper.name);
1150 pw.print(" mWallpaperComponent=");
1151 pw.println(wallpaper.wallpaperComponent);
1152 if (wallpaper.connection != null) {
1153 WallpaperConnection conn = wallpaper.connection;
1154 pw.print(" Wallpaper connection ");
1155 pw.print(conn);
1156 pw.println(":");
1157 if (conn.mInfo != null) {
1158 pw.print(" mInfo.component=");
1159 pw.println(conn.mInfo.getComponent());
1160 }
1161 pw.print(" mToken=");
1162 pw.println(conn.mToken);
1163 pw.print(" mService=");
1164 pw.println(conn.mService);
1165 pw.print(" mEngine=");
1166 pw.println(conn.mEngine);
1167 pw.print(" mLastDiedTime=");
1168 pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
1169 }
Dianne Hackborneb034652009-09-07 00:49:58 -07001170 }
1171 }
1172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173}