OSDN Git Service

am fe5e7e92: Merge "docs: Fix issue with onCreate() method declaration in file backup...
[android-x86/frameworks-base.git] / services / core / java / com / android / server / wallpaper / WallpaperManagerService.java
1 /*
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
17 package com.android.server.wallpaper;
18
19 import static android.os.ParcelFileDescriptor.*;
20
21 import android.app.ActivityManagerNative;
22 import android.app.AppGlobals;
23 import android.app.IUserSwitchObserver;
24 import android.app.IWallpaperManager;
25 import android.app.IWallpaperManagerCallback;
26 import android.app.PendingIntent;
27 import android.app.WallpaperInfo;
28 import android.app.WallpaperManager;
29 import android.app.backup.BackupManager;
30 import android.app.backup.WallpaperBackupHelper;
31 import android.content.BroadcastReceiver;
32 import android.content.ComponentName;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.content.ServiceConnection;
37 import android.content.pm.IPackageManager;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.content.pm.ServiceInfo;
41 import android.content.pm.PackageManager.NameNotFoundException;
42 import android.content.pm.UserInfo;
43 import android.content.res.Resources;
44 import android.graphics.Point;
45 import android.graphics.Rect;
46 import android.os.Binder;
47 import android.os.Bundle;
48 import android.os.Environment;
49 import android.os.FileUtils;
50 import android.os.IBinder;
51 import android.os.IRemoteCallback;
52 import android.os.RemoteException;
53 import android.os.FileObserver;
54 import android.os.ParcelFileDescriptor;
55 import android.os.RemoteCallbackList;
56 import android.os.SELinux;
57 import android.os.ServiceManager;
58 import android.os.SystemClock;
59 import android.os.UserHandle;
60 import android.os.UserManager;
61 import android.service.wallpaper.IWallpaperConnection;
62 import android.service.wallpaper.IWallpaperEngine;
63 import android.service.wallpaper.IWallpaperService;
64 import android.service.wallpaper.WallpaperService;
65 import android.util.Slog;
66 import android.util.SparseArray;
67 import android.util.Xml;
68 import android.view.Display;
69 import android.view.IWindowManager;
70 import android.view.WindowManager;
71
72 import java.io.FileDescriptor;
73 import java.io.IOException;
74 import java.io.InputStream;
75 import java.io.File;
76 import java.io.FileNotFoundException;
77 import java.io.FileInputStream;
78 import java.io.FileOutputStream;
79 import java.io.PrintWriter;
80 import java.util.List;
81
82 import org.xmlpull.v1.XmlPullParser;
83 import org.xmlpull.v1.XmlPullParserException;
84 import org.xmlpull.v1.XmlSerializer;
85
86 import com.android.internal.content.PackageMonitor;
87 import com.android.internal.util.FastXmlSerializer;
88 import com.android.internal.util.JournaledFile;
89 import com.android.internal.R;
90
91 public class WallpaperManagerService extends IWallpaperManager.Stub {
92     static final String TAG = "WallpaperManagerService";
93     static final boolean DEBUG = false;
94
95     final Object mLock = new Object[0];
96
97     /**
98      * Minimum time between crashes of a wallpaper service for us to consider
99      * restarting it vs. just reverting to the static wallpaper.
100      */
101     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
102     static final String WALLPAPER = "wallpaper";
103     static final String WALLPAPER_INFO = "wallpaper_info.xml";
104
105     /**
106      * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
107      * that the wallpaper has changed. The CREATE is triggered when there is no
108      * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
109      * everytime the wallpaper is changed.
110      */
111     private class WallpaperObserver extends FileObserver {
112
113         final WallpaperData mWallpaper;
114         final File mWallpaperDir;
115         final File mWallpaperFile;
116
117         public WallpaperObserver(WallpaperData wallpaper) {
118             super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
119                     CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
120             mWallpaperDir = getWallpaperDir(wallpaper.userId);
121             mWallpaper = wallpaper;
122             mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
123         }
124
125         @Override
126         public void onEvent(int event, String path) {
127             if (path == null) {
128                 return;
129             }
130             synchronized (mLock) {
131                 // changing the wallpaper means we'll need to back up the new one
132                 long origId = Binder.clearCallingIdentity();
133                 BackupManager bm = new BackupManager(mContext);
134                 bm.dataChanged();
135                 Binder.restoreCallingIdentity(origId);
136
137                 File changedFile = new File(mWallpaperDir, path);
138                 if (mWallpaperFile.equals(changedFile)) {
139                     notifyCallbacksLocked(mWallpaper);
140                     final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
141                     if (mWallpaper.wallpaperComponent == null
142                             || event != CLOSE_WRITE // includes the MOVED_TO case
143                             || mWallpaper.imageWallpaperPending) {
144                         if (written) {
145                             mWallpaper.imageWallpaperPending = false;
146                         }
147                         bindWallpaperComponentLocked(mImageWallpaper, true,
148                                 false, mWallpaper, null);
149                         saveSettingsLocked(mWallpaper);
150                     }
151                 }
152             }
153         }
154     }
155
156     final Context mContext;
157     final IWindowManager mIWindowManager;
158     final IPackageManager mIPackageManager;
159     final MyPackageMonitor mMonitor;
160     WallpaperData mLastWallpaper;
161
162     /**
163      * Name of the component used to display bitmap wallpapers from either the gallery or
164      * built-in wallpapers.
165      */
166     final ComponentName mImageWallpaper;
167
168     SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
169
170     int mCurrentUserId;
171
172     static class WallpaperData {
173
174         int userId;
175
176         File wallpaperFile;
177
178         /**
179          * Client is currently writing a new image wallpaper.
180          */
181         boolean imageWallpaperPending;
182
183         /**
184          * Resource name if using a picture from the wallpaper gallery
185          */
186         String name = "";
187
188         /**
189          * The component name of the currently set live wallpaper.
190          */
191         ComponentName wallpaperComponent;
192
193         /**
194          * The component name of the wallpaper that should be set next.
195          */
196         ComponentName nextWallpaperComponent;
197
198         WallpaperConnection connection;
199         long lastDiedTime;
200         boolean wallpaperUpdating;
201         WallpaperObserver wallpaperObserver;
202
203         /**
204          * List of callbacks registered they should each be notified when the wallpaper is changed.
205          */
206         private RemoteCallbackList<IWallpaperManagerCallback> callbacks
207                 = new RemoteCallbackList<IWallpaperManagerCallback>();
208
209         int width = -1;
210         int height = -1;
211
212         final Rect padding = new Rect(0, 0, 0, 0);
213
214         WallpaperData(int userId) {
215             this.userId = userId;
216             wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
217         }
218     }
219
220     class WallpaperConnection extends IWallpaperConnection.Stub
221             implements ServiceConnection {
222         final WallpaperInfo mInfo;
223         final Binder mToken = new Binder();
224         IWallpaperService mService;
225         IWallpaperEngine mEngine;
226         WallpaperData mWallpaper;
227         IRemoteCallback mReply;
228
229         boolean mDimensionsChanged = false;
230         boolean mPaddingChanged = false;
231
232         public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
233             mInfo = info;
234             mWallpaper = wallpaper;
235         }
236
237         @Override
238         public void onServiceConnected(ComponentName name, IBinder service) {
239             synchronized (mLock) {
240                 if (mWallpaper.connection == this) {
241                     mService = IWallpaperService.Stub.asInterface(service);
242                     attachServiceLocked(this, mWallpaper);
243                     // XXX should probably do saveSettingsLocked() later
244                     // when we have an engine, but I'm not sure about
245                     // locking there and anyway we always need to be able to
246                     // recover if there is something wrong.
247                     saveSettingsLocked(mWallpaper);
248                 }
249             }
250         }
251
252         @Override
253         public void onServiceDisconnected(ComponentName name) {
254             synchronized (mLock) {
255                 mService = null;
256                 mEngine = null;
257                 if (mWallpaper.connection == this) {
258                     Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
259                     if (!mWallpaper.wallpaperUpdating
260                             && mWallpaper.userId == mCurrentUserId) {
261                         // There is a race condition which causes
262                         // {@link #mWallpaper.wallpaperUpdating} to be false even if it is
263                         // currently updating since the broadcast notifying us is async.
264                         // This race is overcome by the general rule that we only reset the
265                         // wallpaper if its service was shut down twice
266                         // during {@link #MIN_WALLPAPER_CRASH_TIME} millis.
267                         if (mWallpaper.lastDiedTime != 0
268                                 && mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
269                                     > SystemClock.uptimeMillis()) {
270                             Slog.w(TAG, "Reverting to built-in wallpaper!");
271                             clearWallpaperLocked(true, mWallpaper.userId, null);
272                         } else {
273                             mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
274                         }
275                     }
276                 }
277             }
278         }
279
280         @Override
281         public void attachEngine(IWallpaperEngine engine) {
282             synchronized (mLock) {
283                 mEngine = engine;
284                 if (mDimensionsChanged) {
285                     try {
286                         mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
287                     } catch (RemoteException e) {
288                         Slog.w(TAG, "Failed to set wallpaper dimensions", e);
289                     }
290                     mDimensionsChanged = false;
291                 }
292                 if (mPaddingChanged) {
293                     try {
294                         mEngine.setDisplayPadding(mWallpaper.padding);
295                     } catch (RemoteException e) {
296                         Slog.w(TAG, "Failed to set wallpaper padding", e);
297                     }
298                     mPaddingChanged = false;
299                 }
300             }
301         }
302
303         @Override
304         public void engineShown(IWallpaperEngine engine) {
305             synchronized (mLock) {
306                 if (mReply != null) {
307                     long ident = Binder.clearCallingIdentity();
308                     try {
309                         mReply.sendResult(null);
310                     } catch (RemoteException e) {
311                         Binder.restoreCallingIdentity(ident);
312                     }
313                     mReply = null;
314                 }
315             }
316         }
317
318         @Override
319         public ParcelFileDescriptor setWallpaper(String name) {
320             synchronized (mLock) {
321                 if (mWallpaper.connection == this) {
322                     return updateWallpaperBitmapLocked(name, mWallpaper);
323                 }
324                 return null;
325             }
326         }
327     }
328
329     class MyPackageMonitor extends PackageMonitor {
330         @Override
331         public void onPackageUpdateFinished(String packageName, int uid) {
332             synchronized (mLock) {
333                 if (mCurrentUserId != getChangingUserId()) {
334                     return;
335                 }
336                 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
337                 if (wallpaper != null) {
338                     if (wallpaper.wallpaperComponent != null
339                             && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
340                         wallpaper.wallpaperUpdating = false;
341                         ComponentName comp = wallpaper.wallpaperComponent;
342                         clearWallpaperComponentLocked(wallpaper);
343                         if (!bindWallpaperComponentLocked(comp, false, false,
344                                 wallpaper, null)) {
345                             Slog.w(TAG, "Wallpaper no longer available; reverting to default");
346                             clearWallpaperLocked(false, wallpaper.userId, null);
347                         }
348                     }
349                 }
350             }
351         }
352
353         @Override
354         public void onPackageModified(String packageName) {
355             synchronized (mLock) {
356                 if (mCurrentUserId != getChangingUserId()) {
357                     return;
358                 }
359                 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
360                 if (wallpaper != null) {
361                     if (wallpaper.wallpaperComponent == null
362                             || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
363                         return;
364                     }
365                     doPackagesChangedLocked(true, wallpaper);
366                 }
367             }
368         }
369
370         @Override
371         public void onPackageUpdateStarted(String packageName, int uid) {
372             synchronized (mLock) {
373                 if (mCurrentUserId != getChangingUserId()) {
374                     return;
375                 }
376                 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
377                 if (wallpaper != null) {
378                     if (wallpaper.wallpaperComponent != null
379                             && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
380                         wallpaper.wallpaperUpdating = true;
381                     }
382                 }
383             }
384         }
385
386         @Override
387         public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
388             synchronized (mLock) {
389                 boolean changed = false;
390                 if (mCurrentUserId != getChangingUserId()) {
391                     return false;
392                 }
393                 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
394                 if (wallpaper != null) {
395                     boolean res = doPackagesChangedLocked(doit, wallpaper);
396                     changed |= res;
397                 }
398                 return changed;
399             }
400         }
401
402         @Override
403         public void onSomePackagesChanged() {
404             synchronized (mLock) {
405                 if (mCurrentUserId != getChangingUserId()) {
406                     return;
407                 }
408                 WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
409                 if (wallpaper != null) {
410                     doPackagesChangedLocked(true, wallpaper);
411                 }
412             }
413         }
414
415         boolean doPackagesChangedLocked(boolean doit, WallpaperData wallpaper) {
416             boolean changed = false;
417             if (wallpaper.wallpaperComponent != null) {
418                 int change = isPackageDisappearing(wallpaper.wallpaperComponent
419                         .getPackageName());
420                 if (change == PACKAGE_PERMANENT_CHANGE
421                         || change == PACKAGE_TEMPORARY_CHANGE) {
422                     changed = true;
423                     if (doit) {
424                         Slog.w(TAG, "Wallpaper uninstalled, removing: "
425                                 + wallpaper.wallpaperComponent);
426                         clearWallpaperLocked(false, wallpaper.userId, null);
427                     }
428                 }
429             }
430             if (wallpaper.nextWallpaperComponent != null) {
431                 int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
432                         .getPackageName());
433                 if (change == PACKAGE_PERMANENT_CHANGE
434                         || change == PACKAGE_TEMPORARY_CHANGE) {
435                     wallpaper.nextWallpaperComponent = null;
436                 }
437             }
438             if (wallpaper.wallpaperComponent != null
439                     && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
440                 try {
441                     mContext.getPackageManager().getServiceInfo(
442                             wallpaper.wallpaperComponent, 0);
443                 } catch (NameNotFoundException e) {
444                     Slog.w(TAG, "Wallpaper component gone, removing: "
445                             + wallpaper.wallpaperComponent);
446                     clearWallpaperLocked(false, wallpaper.userId, null);
447                 }
448             }
449             if (wallpaper.nextWallpaperComponent != null
450                     && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
451                 try {
452                     mContext.getPackageManager().getServiceInfo(
453                             wallpaper.nextWallpaperComponent, 0);
454                 } catch (NameNotFoundException e) {
455                     wallpaper.nextWallpaperComponent = null;
456                 }
457             }
458             return changed;
459         }
460     }
461     
462     public WallpaperManagerService(Context context) {
463         if (DEBUG) Slog.v(TAG, "WallpaperService startup");
464         mContext = context;
465         mImageWallpaper = ComponentName.unflattenFromString(
466                 context.getResources().getString(R.string.image_wallpaper_component));
467         mIWindowManager = IWindowManager.Stub.asInterface(
468                 ServiceManager.getService(Context.WINDOW_SERVICE));
469         mIPackageManager = AppGlobals.getPackageManager();
470         mMonitor = new MyPackageMonitor();
471         mMonitor.register(context, null, UserHandle.ALL, true);
472         getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
473         loadSettingsLocked(UserHandle.USER_OWNER);
474     }
475     
476     private static File getWallpaperDir(int userId) {
477         return Environment.getUserSystemDirectory(userId);
478     }
479
480     @Override
481     protected void finalize() throws Throwable {
482         super.finalize();
483         for (int i = 0; i < mWallpaperMap.size(); i++) {
484             WallpaperData wallpaper = mWallpaperMap.valueAt(i);
485             wallpaper.wallpaperObserver.stopWatching();
486         }
487     }
488
489     public void systemRunning() {
490         if (DEBUG) Slog.v(TAG, "systemReady");
491         WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER);
492         switchWallpaper(wallpaper, null);
493         wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
494         wallpaper.wallpaperObserver.startWatching();
495
496         IntentFilter userFilter = new IntentFilter();
497         userFilter.addAction(Intent.ACTION_USER_REMOVED);
498         userFilter.addAction(Intent.ACTION_USER_STOPPING);
499         mContext.registerReceiver(new BroadcastReceiver() {
500             @Override
501             public void onReceive(Context context, Intent intent) {
502                 String action = intent.getAction();
503                 if (Intent.ACTION_USER_REMOVED.equals(action)) {
504                     onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
505                             UserHandle.USER_NULL));
506                 }
507                 // TODO: Race condition causing problems when cleaning up on stopping a user.
508                 // Comment this out for now.
509                 // else if (Intent.ACTION_USER_STOPPING.equals(action)) {
510                 //     onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
511                 //             UserHandle.USER_NULL));
512                 // }
513             }
514         }, userFilter);
515
516         try {
517             ActivityManagerNative.getDefault().registerUserSwitchObserver(
518                     new IUserSwitchObserver.Stub() {
519                         @Override
520                         public void onUserSwitching(int newUserId, IRemoteCallback reply) {
521                             switchUser(newUserId, reply);
522                         }
523
524                         @Override
525                         public void onUserSwitchComplete(int newUserId) throws RemoteException {
526                         }
527                     });
528         } catch (RemoteException e) {
529             // TODO Auto-generated catch block
530             e.printStackTrace();
531         }
532     }
533
534     /** Called by SystemBackupAgent */
535     public String getName() {
536         // Verify caller is the system
537         if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
538             throw new RuntimeException("getName() can only be called from the system process");
539         }
540         synchronized (mLock) {
541             return mWallpaperMap.get(0).name;
542         }
543     }
544
545     void onStoppingUser(int userId) {
546         if (userId < 1) return;
547         synchronized (mLock) {
548             WallpaperData wallpaper = mWallpaperMap.get(userId);
549             if (wallpaper != null) {
550                 if (wallpaper.wallpaperObserver != null) {
551                     wallpaper.wallpaperObserver.stopWatching();
552                     wallpaper.wallpaperObserver = null;
553                 }
554                 mWallpaperMap.remove(userId);
555             }
556         }
557     }
558
559     void onRemoveUser(int userId) {
560         if (userId < 1) return;
561         synchronized (mLock) {
562             onStoppingUser(userId);
563             File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
564             wallpaperFile.delete();
565             File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
566             wallpaperInfoFile.delete();
567         }
568     }
569
570     void switchUser(int userId, IRemoteCallback reply) {
571         synchronized (mLock) {
572             mCurrentUserId = userId;
573             WallpaperData wallpaper = mWallpaperMap.get(userId);
574             if (wallpaper == null) {
575                 wallpaper = new WallpaperData(userId);
576                 mWallpaperMap.put(userId, wallpaper);
577                 loadSettingsLocked(userId);
578             }
579             // Not started watching yet, in case wallpaper data was loaded for other reasons.
580             if (wallpaper.wallpaperObserver == null) {
581                 wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
582                 wallpaper.wallpaperObserver.startWatching();
583             }
584             switchWallpaper(wallpaper, reply);
585         }
586     }
587
588     void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
589         synchronized (mLock) {
590             RuntimeException e = null;
591             try {
592                 ComponentName cname = wallpaper.wallpaperComponent != null ?
593                         wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
594                 if (bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
595                     return;
596                 }
597             } catch (RuntimeException e1) {
598                 e = e1;
599             }
600             Slog.w(TAG, "Failure starting previous wallpaper", e);
601             clearWallpaperLocked(false, wallpaper.userId, reply);
602         }
603     }
604
605     public void clearWallpaper() {
606         if (DEBUG) Slog.v(TAG, "clearWallpaper");
607         synchronized (mLock) {
608             clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
609         }
610     }
611
612     void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
613         WallpaperData wallpaper = mWallpaperMap.get(userId);
614         File f = new File(getWallpaperDir(userId), WALLPAPER);
615         if (f.exists()) {
616             f.delete();
617         }
618         final long ident = Binder.clearCallingIdentity();
619         try {
620             RuntimeException e = null;
621             try {
622                 wallpaper.imageWallpaperPending = false;
623                 if (userId != mCurrentUserId) return;
624                 if (bindWallpaperComponentLocked(defaultFailed
625                         ? mImageWallpaper
626                                 : null, true, false, wallpaper, reply)) {
627                     return;
628                 }
629             } catch (IllegalArgumentException e1) {
630                 e = e1;
631             }
632
633             // This can happen if the default wallpaper component doesn't
634             // exist.  This should be a system configuration problem, but
635             // let's not let it crash the system and just live with no
636             // wallpaper.
637             Slog.e(TAG, "Default wallpaper component not found!", e);
638             clearWallpaperComponentLocked(wallpaper);
639             if (reply != null) {
640                 try {
641                     reply.sendResult(null);
642                 } catch (RemoteException e1) {
643                 }
644             }
645         } finally {
646             Binder.restoreCallingIdentity(ident);
647         }
648     }
649
650     public boolean hasNamedWallpaper(String name) {
651         synchronized (mLock) {
652             List<UserInfo> users;
653             long ident = Binder.clearCallingIdentity();
654             try {
655                 users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
656             } finally {
657                 Binder.restoreCallingIdentity(ident);
658             }
659             for (UserInfo user: users) {
660                 WallpaperData wd = mWallpaperMap.get(user.id);
661                 if (wd == null) {
662                     // User hasn't started yet, so load her settings to peek at the wallpaper
663                     loadSettingsLocked(user.id);
664                     wd = mWallpaperMap.get(user.id);
665                 }
666                 if (wd != null && name.equals(wd.name)) {
667                     return true;
668                 }
669             }
670         }
671         return false;
672     }
673
674     private Point getDefaultDisplaySize() {
675         Point p = new Point();
676         WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
677         Display d = wm.getDefaultDisplay();
678         d.getRealSize(p);
679         return p;
680     }
681
682     public void setDimensionHints(int width, int height) throws RemoteException {
683         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
684         synchronized (mLock) {
685             int userId = UserHandle.getCallingUserId();
686             WallpaperData wallpaper = mWallpaperMap.get(userId);
687             if (wallpaper == null) {
688                 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
689             }
690             if (width <= 0 || height <= 0) {
691                 throw new IllegalArgumentException("width and height must be > 0");
692             }
693             // Make sure it is at least as large as the display.
694             Point displaySize = getDefaultDisplaySize();
695             width = Math.max(width, displaySize.x);
696             height = Math.max(height, displaySize.y);
697
698             if (width != wallpaper.width || height != wallpaper.height) {
699                 wallpaper.width = width;
700                 wallpaper.height = height;
701                 saveSettingsLocked(wallpaper);
702                 if (mCurrentUserId != userId) return; // Don't change the properties now
703                 if (wallpaper.connection != null) {
704                     if (wallpaper.connection.mEngine != null) {
705                         try {
706                             wallpaper.connection.mEngine.setDesiredSize(
707                                     width, height);
708                         } catch (RemoteException e) {
709                         }
710                         notifyCallbacksLocked(wallpaper);
711                     } else if (wallpaper.connection.mService != null) {
712                         // We've attached to the service but the engine hasn't attached back to us
713                         // yet. This means it will be created with the previous dimensions, so we
714                         // need to update it to the new dimensions once it attaches.
715                         wallpaper.connection.mDimensionsChanged = true;
716                     }
717                 }
718             }
719         }
720     }
721
722     public int getWidthHint() throws RemoteException {
723         synchronized (mLock) {
724             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
725             return wallpaper.width;
726         }
727     }
728
729     public int getHeightHint() throws RemoteException {
730         synchronized (mLock) {
731             WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
732             return wallpaper.height;
733         }
734     }
735
736     public void setDisplayPadding(Rect padding) {
737         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
738         synchronized (mLock) {
739             int userId = UserHandle.getCallingUserId();
740             WallpaperData wallpaper = mWallpaperMap.get(userId);
741             if (wallpaper == null) {
742                 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
743             }
744             if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
745                 throw new IllegalArgumentException("padding must be positive: " + padding);
746             }
747
748             if (!padding.equals(wallpaper.padding)) {
749                 wallpaper.padding.set(padding);
750                 saveSettingsLocked(wallpaper);
751                 if (mCurrentUserId != userId) return; // Don't change the properties now
752                 if (wallpaper.connection != null) {
753                     if (wallpaper.connection.mEngine != null) {
754                         try {
755                             wallpaper.connection.mEngine.setDisplayPadding(padding);
756                         } catch (RemoteException e) {
757                         }
758                         notifyCallbacksLocked(wallpaper);
759                     } else if (wallpaper.connection.mService != null) {
760                         // We've attached to the service but the engine hasn't attached back to us
761                         // yet. This means it will be created with the previous dimensions, so we
762                         // need to update it to the new dimensions once it attaches.
763                         wallpaper.connection.mPaddingChanged = true;
764                     }
765                 }
766             }
767         }
768     }
769
770     public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
771             Bundle outParams) {
772         synchronized (mLock) {
773             // This returns the current user's wallpaper, if called by a system service. Else it
774             // returns the wallpaper for the calling user.
775             int callingUid = Binder.getCallingUid();
776             int wallpaperUserId = 0;
777             if (callingUid == android.os.Process.SYSTEM_UID) {
778                 wallpaperUserId = mCurrentUserId;
779             } else {
780                 wallpaperUserId = UserHandle.getUserId(callingUid);
781             }
782             WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
783             try {
784                 if (outParams != null) {
785                     outParams.putInt("width", wallpaper.width);
786                     outParams.putInt("height", wallpaper.height);
787                 }
788                 wallpaper.callbacks.register(cb);
789                 File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
790                 if (!f.exists()) {
791                     return null;
792                 }
793                 return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
794             } catch (FileNotFoundException e) {
795                 /* Shouldn't happen as we check to see if the file exists */
796                 Slog.w(TAG, "Error getting wallpaper", e);
797             }
798             return null;
799         }
800     }
801
802     public WallpaperInfo getWallpaperInfo() {
803         int userId = UserHandle.getCallingUserId();
804         synchronized (mLock) {
805             WallpaperData wallpaper = mWallpaperMap.get(userId);
806             if (wallpaper.connection != null) {
807                 return wallpaper.connection.mInfo;
808             }
809             return null;
810         }
811     }
812
813     public ParcelFileDescriptor setWallpaper(String name) {
814         checkPermission(android.Manifest.permission.SET_WALLPAPER);
815         synchronized (mLock) {
816             if (DEBUG) Slog.v(TAG, "setWallpaper");
817             int userId = UserHandle.getCallingUserId();
818             WallpaperData wallpaper = mWallpaperMap.get(userId);
819             if (wallpaper == null) {
820                 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
821             }
822             final long ident = Binder.clearCallingIdentity();
823             try {
824                 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
825                 if (pfd != null) {
826                     wallpaper.imageWallpaperPending = true;
827                 }
828                 return pfd;
829             } finally {
830                 Binder.restoreCallingIdentity(ident);
831             }
832         }
833     }
834
835     ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
836         if (name == null) name = "";
837         try {
838             File dir = getWallpaperDir(wallpaper.userId);
839             if (!dir.exists()) {
840                 dir.mkdir();
841                 FileUtils.setPermissions(
842                         dir.getPath(),
843                         FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
844                         -1, -1);
845             }
846             File file = new File(dir, WALLPAPER);
847             ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
848                     MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
849             if (!SELinux.restorecon(file)) {
850                 return null;
851             }
852             wallpaper.name = name;
853             return fd;
854         } catch (FileNotFoundException e) {
855             Slog.w(TAG, "Error setting wallpaper", e);
856         }
857         return null;
858     }
859
860     public void setWallpaperComponent(ComponentName name) {
861         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
862         synchronized (mLock) {
863             if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
864             int userId = UserHandle.getCallingUserId();
865             WallpaperData wallpaper = mWallpaperMap.get(userId);
866             if (wallpaper == null) {
867                 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
868             }
869             final long ident = Binder.clearCallingIdentity();
870             try {
871                 wallpaper.imageWallpaperPending = false;
872                 bindWallpaperComponentLocked(name, false, true, wallpaper, null);
873             } finally {
874                 Binder.restoreCallingIdentity(ident);
875             }
876         }
877     }
878     
879     boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
880             boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
881         if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
882         // Has the component changed?
883         if (!force) {
884             if (wallpaper.connection != null) {
885                 if (wallpaper.wallpaperComponent == null) {
886                     if (componentName == null) {
887                         if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
888                         // Still using default wallpaper.
889                         return true;
890                     }
891                 } else if (wallpaper.wallpaperComponent.equals(componentName)) {
892                     // Changing to same wallpaper.
893                     if (DEBUG) Slog.v(TAG, "same wallpaper");
894                     return true;
895                 }
896             }
897         }
898         
899         try {
900             if (componentName == null) {
901                 componentName = WallpaperManager.getDefaultWallpaperComponent(mContext);
902                 if (componentName == null) {
903                     // Fall back to static image wallpaper
904                     componentName = mImageWallpaper;
905                     //clearWallpaperComponentLocked();
906                     //return;
907                     if (DEBUG) Slog.v(TAG, "Using image wallpaper");
908                 }
909             }
910             int serviceUserId = wallpaper.userId;
911             ServiceInfo si = mIPackageManager.getServiceInfo(componentName,
912                     PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId);
913             if (si == null) {
914                 // The wallpaper component we're trying to use doesn't exist
915                 Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");
916                 return false;
917             }
918             if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {
919                 String msg = "Selected service does not require "
920                         + android.Manifest.permission.BIND_WALLPAPER
921                         + ": " + componentName;
922                 if (fromUser) {
923                     throw new SecurityException(msg);
924                 }
925                 Slog.w(TAG, msg);
926                 return false;
927             }
928             
929             WallpaperInfo wi = null;
930             
931             Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
932             if (componentName != null && !componentName.equals(mImageWallpaper)) {
933                 // Make sure the selected service is actually a wallpaper service.
934                 List<ResolveInfo> ris =
935                         mIPackageManager.queryIntentServices(intent,
936                                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
937                                 PackageManager.GET_META_DATA, serviceUserId);
938                 for (int i=0; i<ris.size(); i++) {
939                     ServiceInfo rsi = ris.get(i).serviceInfo;
940                     if (rsi.name.equals(si.name) &&
941                             rsi.packageName.equals(si.packageName)) {
942                         try {
943                             wi = new WallpaperInfo(mContext, ris.get(i));
944                         } catch (XmlPullParserException e) {
945                             if (fromUser) {
946                                 throw new IllegalArgumentException(e);
947                             }
948                             Slog.w(TAG, e);
949                             return false;
950                         } catch (IOException e) {
951                             if (fromUser) {
952                                 throw new IllegalArgumentException(e);
953                             }
954                             Slog.w(TAG, e);
955                             return false;
956                         }
957                         break;
958                     }
959                 }
960                 if (wi == null) {
961                     String msg = "Selected service is not a wallpaper: "
962                             + componentName;
963                     if (fromUser) {
964                         throw new SecurityException(msg);
965                     }
966                     Slog.w(TAG, msg);
967                     return false;
968                 }
969             }
970             
971             // Bind the service!
972             if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
973             WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
974             intent.setComponent(componentName);
975             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
976                     com.android.internal.R.string.wallpaper_binding_label);
977             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
978                     mContext, 0,
979                     Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
980                             mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
981                     0, null, new UserHandle(serviceUserId)));
982             if (!mContext.bindServiceAsUser(intent, newConn,
983                     Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI,
984                     new UserHandle(serviceUserId))) {
985                 String msg = "Unable to bind service: "
986                         + componentName;
987                 if (fromUser) {
988                     throw new IllegalArgumentException(msg);
989                 }
990                 Slog.w(TAG, msg);
991                 return false;
992             }
993             if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
994                 detachWallpaperLocked(mLastWallpaper);
995             }
996             wallpaper.wallpaperComponent = componentName;
997             wallpaper.connection = newConn;
998             newConn.mReply = reply;
999             try {
1000                 if (wallpaper.userId == mCurrentUserId) {
1001                     if (DEBUG)
1002                         Slog.v(TAG, "Adding window token: " + newConn.mToken);
1003                     mIWindowManager.addWindowToken(newConn.mToken,
1004                             WindowManager.LayoutParams.TYPE_WALLPAPER);
1005                     mLastWallpaper = wallpaper;
1006                 }
1007             } catch (RemoteException e) {
1008             }
1009         } catch (RemoteException e) {
1010             String msg = "Remote exception for " + componentName + "\n" + e;
1011             if (fromUser) {
1012                 throw new IllegalArgumentException(msg);
1013             }
1014             Slog.w(TAG, msg);
1015             return false;
1016         }
1017         return true;
1018     }
1019
1020     void detachWallpaperLocked(WallpaperData wallpaper) {
1021         if (wallpaper.connection != null) {
1022             if (wallpaper.connection.mReply != null) {
1023                 try {
1024                     wallpaper.connection.mReply.sendResult(null);
1025                 } catch (RemoteException e) {
1026                 }
1027                 wallpaper.connection.mReply = null;
1028             }
1029             if (wallpaper.connection.mEngine != null) {
1030                 try {
1031                     wallpaper.connection.mEngine.destroy();
1032                 } catch (RemoteException e) {
1033                 }
1034             }
1035             mContext.unbindService(wallpaper.connection);
1036             try {
1037                 if (DEBUG)
1038                     Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
1039                 mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
1040             } catch (RemoteException e) {
1041             }
1042             wallpaper.connection.mService = null;
1043             wallpaper.connection.mEngine = null;
1044             wallpaper.connection = null;
1045         }
1046     }
1047
1048     void clearWallpaperComponentLocked(WallpaperData wallpaper) {
1049         wallpaper.wallpaperComponent = null;
1050         detachWallpaperLocked(wallpaper);
1051     }
1052
1053     void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
1054         try {
1055             conn.mService.attach(conn, conn.mToken,
1056                     WindowManager.LayoutParams.TYPE_WALLPAPER, false,
1057                     wallpaper.width, wallpaper.height, wallpaper.padding);
1058         } catch (RemoteException e) {
1059             Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
1060             if (!wallpaper.wallpaperUpdating) {
1061                 bindWallpaperComponentLocked(null, false, false, wallpaper, null);
1062             }
1063         }
1064     }
1065
1066     private void notifyCallbacksLocked(WallpaperData wallpaper) {
1067         final int n = wallpaper.callbacks.beginBroadcast();
1068         for (int i = 0; i < n; i++) {
1069             try {
1070                 wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
1071             } catch (RemoteException e) {
1072
1073                 // The RemoteCallbackList will take care of removing
1074                 // the dead object for us.
1075             }
1076         }
1077         wallpaper.callbacks.finishBroadcast();
1078         final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
1079         mContext.sendBroadcastAsUser(intent, new UserHandle(mCurrentUserId));
1080     }
1081
1082     private void checkPermission(String permission) {
1083         if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) {
1084             throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
1085                     + ", must have permission " + permission);
1086         }
1087     }
1088
1089     private static JournaledFile makeJournaledFile(int userId) {
1090         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
1091         return new JournaledFile(new File(base), new File(base + ".tmp"));
1092     }
1093
1094     private void saveSettingsLocked(WallpaperData wallpaper) {
1095         JournaledFile journal = makeJournaledFile(wallpaper.userId);
1096         FileOutputStream stream = null;
1097         try {
1098             stream = new FileOutputStream(journal.chooseForWrite(), false);
1099             XmlSerializer out = new FastXmlSerializer();
1100             out.setOutput(stream, "utf-8");
1101             out.startDocument(null, true);
1102
1103             out.startTag(null, "wp");
1104             out.attribute(null, "width", Integer.toString(wallpaper.width));
1105             out.attribute(null, "height", Integer.toString(wallpaper.height));
1106             if (wallpaper.padding.left != 0) {
1107                 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
1108             }
1109             if (wallpaper.padding.top != 0) {
1110                 out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
1111             }
1112             if (wallpaper.padding.right != 0) {
1113                 out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
1114             }
1115             if (wallpaper.padding.bottom != 0) {
1116                 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
1117             }
1118             out.attribute(null, "name", wallpaper.name);
1119             if (wallpaper.wallpaperComponent != null
1120                     && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
1121                 out.attribute(null, "component",
1122                         wallpaper.wallpaperComponent.flattenToShortString());
1123             }
1124             out.endTag(null, "wp");
1125
1126             out.endDocument();
1127             stream.close();
1128             journal.commit();
1129         } catch (IOException e) {
1130             try {
1131                 if (stream != null) {
1132                     stream.close();
1133                 }
1134             } catch (IOException ex) {
1135                 // Ignore
1136             }
1137             journal.rollback();
1138         }
1139     }
1140
1141     private void migrateFromOld() {
1142         File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
1143         File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
1144         if (oldWallpaper.exists()) {
1145             File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
1146             oldWallpaper.renameTo(newWallpaper);
1147         }
1148         if (oldInfo.exists()) {
1149             File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
1150             oldInfo.renameTo(newInfo);
1151         }
1152     }
1153
1154     private int getAttributeInt(XmlPullParser parser, String name, int defValue) {
1155         String value = parser.getAttributeValue(null, name);
1156         if (value == null) {
1157             return defValue;
1158         }
1159         return Integer.parseInt(value);
1160     }
1161
1162     private void loadSettingsLocked(int userId) {
1163         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
1164         
1165         JournaledFile journal = makeJournaledFile(userId);
1166         FileInputStream stream = null;
1167         File file = journal.chooseForRead();
1168         if (!file.exists()) {
1169             // This should only happen one time, when upgrading from a legacy system
1170             migrateFromOld();
1171         }
1172         WallpaperData wallpaper = mWallpaperMap.get(userId);
1173         if (wallpaper == null) {
1174             wallpaper = new WallpaperData(userId);
1175             mWallpaperMap.put(userId, wallpaper);
1176         }
1177         boolean success = false;
1178         try {
1179             stream = new FileInputStream(file);
1180             XmlPullParser parser = Xml.newPullParser();
1181             parser.setInput(stream, null);
1182
1183             int type;
1184             do {
1185                 type = parser.next();
1186                 if (type == XmlPullParser.START_TAG) {
1187                     String tag = parser.getName();
1188                     if ("wp".equals(tag)) {
1189                         wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
1190                         wallpaper.height = Integer.parseInt(parser
1191                                 .getAttributeValue(null, "height"));
1192                         wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
1193                         wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
1194                         wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
1195                         wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
1196                         wallpaper.name = parser.getAttributeValue(null, "name");
1197                         String comp = parser.getAttributeValue(null, "component");
1198                         wallpaper.nextWallpaperComponent = comp != null
1199                                 ? ComponentName.unflattenFromString(comp)
1200                                 : null;
1201                         if (wallpaper.nextWallpaperComponent == null
1202                                 || "android".equals(wallpaper.nextWallpaperComponent
1203                                         .getPackageName())) {
1204                             wallpaper.nextWallpaperComponent = mImageWallpaper;
1205                         }
1206                           
1207                         if (DEBUG) {
1208                             Slog.v(TAG, "mWidth:" + wallpaper.width);
1209                             Slog.v(TAG, "mHeight:" + wallpaper.height);
1210                             Slog.v(TAG, "mName:" + wallpaper.name);
1211                             Slog.v(TAG, "mNextWallpaperComponent:"
1212                                     + wallpaper.nextWallpaperComponent);
1213                         }
1214                     }
1215                 }
1216             } while (type != XmlPullParser.END_DOCUMENT);
1217             success = true;
1218         } catch (FileNotFoundException e) {
1219             Slog.w(TAG, "no current wallpaper -- first boot?");
1220         } catch (NullPointerException e) {
1221             Slog.w(TAG, "failed parsing " + file + " " + e);
1222         } catch (NumberFormatException e) {
1223             Slog.w(TAG, "failed parsing " + file + " " + e);
1224         } catch (XmlPullParserException e) {
1225             Slog.w(TAG, "failed parsing " + file + " " + e);
1226         } catch (IOException e) {
1227             Slog.w(TAG, "failed parsing " + file + " " + e);
1228         } catch (IndexOutOfBoundsException e) {
1229             Slog.w(TAG, "failed parsing " + file + " " + e);
1230         }
1231         try {
1232             if (stream != null) {
1233                 stream.close();
1234             }
1235         } catch (IOException e) {
1236             // Ignore
1237         }
1238
1239         if (!success) {
1240             wallpaper.width = -1;
1241             wallpaper.height = -1;
1242             wallpaper.padding.set(0, 0, 0, 0);
1243             wallpaper.name = "";
1244         }
1245
1246         // We always want to have some reasonable width hint.
1247         int baseSize = getMaximumSizeDimension();
1248         if (wallpaper.width < baseSize) {
1249             wallpaper.width = baseSize;
1250         }
1251         if (wallpaper.height < baseSize) {
1252             wallpaper.height = baseSize;
1253         }
1254     }
1255
1256     private int getMaximumSizeDimension() {
1257         WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
1258         Display d = wm.getDefaultDisplay();
1259         return d.getMaximumSizeDimension();
1260     }
1261
1262     // Called by SystemBackupAgent after files are restored to disk.
1263     public void settingsRestored() {
1264         // Verify caller is the system
1265         if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
1266             throw new RuntimeException("settingsRestored() can only be called from the system process");
1267         }
1268         // TODO: If necessary, make it work for secondary users as well. This currently assumes
1269         // restores only to the primary user
1270         if (DEBUG) Slog.v(TAG, "settingsRestored");
1271         WallpaperData wallpaper = null;
1272         boolean success = false;
1273         synchronized (mLock) {
1274             loadSettingsLocked(0);
1275             wallpaper = mWallpaperMap.get(0);
1276             if (wallpaper.nextWallpaperComponent != null
1277                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
1278                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
1279                         wallpaper, null)) {
1280                     // No such live wallpaper or other failure; fall back to the default
1281                     // live wallpaper (since the profile being restored indicated that the
1282                     // user had selected a live rather than static one).
1283                     bindWallpaperComponentLocked(null, false, false, wallpaper, null);
1284                 }
1285                 success = true;
1286             } else {
1287                 // If there's a wallpaper name, we use that.  If that can't be loaded, then we
1288                 // use the default.
1289                 if ("".equals(wallpaper.name)) {
1290                     if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
1291                     success = true;
1292                 } else {
1293                     if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
1294                     success = restoreNamedResourceLocked(wallpaper);
1295                 }
1296                 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
1297                 if (success) {
1298                     bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
1299                             wallpaper, null);
1300                 }
1301             }
1302         }
1303
1304         if (!success) {
1305             Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
1306             wallpaper.name = "";
1307             getWallpaperDir(0).delete();
1308         }
1309
1310         synchronized (mLock) {
1311             saveSettingsLocked(wallpaper);
1312         }
1313     }
1314
1315     boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
1316         if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
1317             String resName = wallpaper.name.substring(4);
1318
1319             String pkg = null;
1320             int colon = resName.indexOf(':');
1321             if (colon > 0) {
1322                 pkg = resName.substring(0, colon);
1323             }
1324
1325             String ident = null;
1326             int slash = resName.lastIndexOf('/');
1327             if (slash > 0) {
1328                 ident = resName.substring(slash+1);
1329             }
1330
1331             String type = null;
1332             if (colon > 0 && slash > 0 && (slash-colon) > 1) {
1333                 type = resName.substring(colon+1, slash);
1334             }
1335
1336             if (pkg != null && ident != null && type != null) {
1337                 int resId = -1;
1338                 InputStream res = null;
1339                 FileOutputStream fos = null;
1340                 try {
1341                     Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
1342                     Resources r = c.getResources();
1343                     resId = r.getIdentifier(resName, null, null);
1344                     if (resId == 0) {
1345                         Slog.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type
1346                                 + " ident=" + ident);
1347                         return false;
1348                     }
1349
1350                     res = r.openRawResource(resId);
1351                     if (wallpaper.wallpaperFile.exists()) {
1352                         wallpaper.wallpaperFile.delete();
1353                     }
1354                     fos = new FileOutputStream(wallpaper.wallpaperFile);
1355
1356                     byte[] buffer = new byte[32768];
1357                     int amt;
1358                     while ((amt=res.read(buffer)) > 0) {
1359                         fos.write(buffer, 0, amt);
1360                     }
1361                     // mWallpaperObserver will notice the close and send the change broadcast
1362
1363                     Slog.v(TAG, "Restored wallpaper: " + resName);
1364                     return true;
1365                 } catch (NameNotFoundException e) {
1366                     Slog.e(TAG, "Package name " + pkg + " not found");
1367                 } catch (Resources.NotFoundException e) {
1368                     Slog.e(TAG, "Resource not found: " + resId);
1369                 } catch (IOException e) {
1370                     Slog.e(TAG, "IOException while restoring wallpaper ", e);
1371                 } finally {
1372                     if (res != null) {
1373                         try {
1374                             res.close();
1375                         } catch (IOException ex) {}
1376                     }
1377                     if (fos != null) {
1378                         FileUtils.sync(fos);
1379                         try {
1380                             fos.close();
1381                         } catch (IOException ex) {}
1382                     }
1383                 }
1384             }
1385         }
1386         return false;
1387     }
1388
1389     @Override
1390     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1391         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1392                 != PackageManager.PERMISSION_GRANTED) {
1393             
1394             pw.println("Permission Denial: can't dump wallpaper service from from pid="
1395                     + Binder.getCallingPid()
1396                     + ", uid=" + Binder.getCallingUid());
1397             return;
1398         }
1399
1400         synchronized (mLock) {
1401             pw.println("Current Wallpaper Service state:");
1402             for (int i = 0; i < mWallpaperMap.size(); i++) {
1403                 WallpaperData wallpaper = mWallpaperMap.valueAt(i);
1404                 pw.println(" User " + wallpaper.userId + ":");
1405                 pw.print("  mWidth=");
1406                     pw.print(wallpaper.width);
1407                     pw.print(" mHeight=");
1408                     pw.println(wallpaper.height);
1409                 pw.print("  mPadding="); pw.println(wallpaper.padding);
1410                 pw.print("  mName=");  pw.println(wallpaper.name);
1411                 pw.print("  mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
1412                 if (wallpaper.connection != null) {
1413                     WallpaperConnection conn = wallpaper.connection;
1414                     pw.print("  Wallpaper connection ");
1415                     pw.print(conn);
1416                     pw.println(":");
1417                     if (conn.mInfo != null) {
1418                         pw.print("    mInfo.component=");
1419                         pw.println(conn.mInfo.getComponent());
1420                     }
1421                     pw.print("    mToken=");
1422                     pw.println(conn.mToken);
1423                     pw.print("    mService=");
1424                     pw.println(conn.mService);
1425                     pw.print("    mEngine=");
1426                     pw.println(conn.mEngine);
1427                     pw.print("    mLastDiedTime=");
1428                     pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
1429                 }
1430             }
1431         }
1432     }
1433 }