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