diff options
-rw-r--r-- | core/java/android/app/ApplicationContext.java | 11 | ||||
-rw-r--r-- | core/java/android/app/IWallpaperService.aidl | 2 | ||||
-rw-r--r-- | core/java/android/backup/BackupDataInput.java | 7 | ||||
-rw-r--r-- | core/java/android/os/FileObserver.java | 39 | ||||
-rw-r--r-- | core/java/com/android/internal/backup/SystemBackupAgent.java | 35 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | libs/utils/BackupData.cpp | 7 | ||||
-rw-r--r-- | services/java/com/android/server/JournaledFile.java | 107 | ||||
-rw-r--r-- | services/java/com/android/server/SystemBackupAgent.java | 67 | ||||
-rw-r--r-- | services/java/com/android/server/WallpaperService.java | 328 |
10 files changed, 473 insertions, 132 deletions
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 1e4ab68..b095e30 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -578,7 +578,7 @@ class ApplicationContext extends Context { @Override public void setWallpaper(Bitmap bitmap) throws IOException { try { - ParcelFileDescriptor fd = getWallpaperService().setWallpaper(); + ParcelFileDescriptor fd = getWallpaperService().setWallpaper(null); if (fd == null) { return; } @@ -598,7 +598,7 @@ class ApplicationContext extends Context { @Override public void setWallpaper(InputStream data) throws IOException { try { - ParcelFileDescriptor fd = getWallpaperService().setWallpaper(); + ParcelFileDescriptor fd = getWallpaperService().setWallpaper(null); if (fd == null) { return; } @@ -627,13 +627,16 @@ class ApplicationContext extends Context { @Override public void clearWallpaper() throws IOException { try { + Resources resources = getResources(); /* Set the wallpaper to the default values */ - ParcelFileDescriptor fd = getWallpaperService().setWallpaper(); + ParcelFileDescriptor fd = getWallpaperService().setWallpaper( + "res:" + resources.getResourceName( + com.android.internal.R.drawable.default_wallpaper)); if (fd != null) { FileOutputStream fos = null; try { fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - setWallpaper(getResources().openRawResource( + setWallpaper(resources.openRawResource( com.android.internal.R.drawable.default_wallpaper), fos); } finally { diff --git a/core/java/android/app/IWallpaperService.aidl b/core/java/android/app/IWallpaperService.aidl index a332b1a..281a060 100644 --- a/core/java/android/app/IWallpaperService.aidl +++ b/core/java/android/app/IWallpaperService.aidl @@ -25,7 +25,7 @@ interface IWallpaperService { /** * Set the wallpaper. */ - ParcelFileDescriptor setWallpaper(); + ParcelFileDescriptor setWallpaper(String name); /** * Get the wallpaper. diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java index 69c206c..e67b0be 100644 --- a/core/java/android/backup/BackupDataInput.java +++ b/core/java/android/backup/BackupDataInput.java @@ -97,12 +97,7 @@ public class BackupDataInput { public void skipEntityData() throws IOException { if (mHeaderReady) { - int result = skipEntityData_native(mBackupReader); - if (result >= 0) { - return; - } else { - throw new IOException("result=0x" + Integer.toHexString(result)); - } + skipEntityData_native(mBackupReader); } else { throw new IllegalStateException("mHeaderReady=false"); } diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java index d9804ea..38d252e 100644 --- a/core/java/android/os/FileObserver.java +++ b/core/java/android/os/FileObserver.java @@ -25,22 +25,35 @@ import java.util.ArrayList; import java.util.HashMap; public abstract class FileObserver { - public static final int ACCESS = 0x00000001; /* File was accessed */ - public static final int MODIFY = 0x00000002; /* File was modified */ - public static final int ATTRIB = 0x00000004; /* Metadata changed */ - public static final int CLOSE_WRITE = 0x00000008; /* Writtable file was closed */ - public static final int CLOSE_NOWRITE = 0x00000010; /* Unwrittable file closed */ - public static final int OPEN = 0x00000020; /* File was opened */ - public static final int MOVED_FROM = 0x00000040; /* File was moved from X */ - public static final int MOVED_TO = 0x00000080; /* File was moved to Y */ - public static final int CREATE = 0x00000100; /* Subfile was created */ - public static final int DELETE = 0x00000200; /* Subfile was deleted */ - public static final int DELETE_SELF = 0x00000400; /* Self was deleted */ - public static final int MOVE_SELF = 0x00000800; /* Self was moved */ + /** File was accessed */ + public static final int ACCESS = 0x00000001; + /** File was modified */ + public static final int MODIFY = 0x00000002; + /** Metadata changed */ + public static final int ATTRIB = 0x00000004; + /** Writable file was closed */ + public static final int CLOSE_WRITE = 0x00000008; + /** Unwrittable file closed */ + public static final int CLOSE_NOWRITE = 0x00000010; + /** File was opened */ + public static final int OPEN = 0x00000020; + /** File was moved from X */ + public static final int MOVED_FROM = 0x00000040; + /** File was moved to Y */ + public static final int MOVED_TO = 0x00000080; + /** Subfile was created */ + public static final int CREATE = 0x00000100; + /** Subfile was deleted */ + public static final int DELETE = 0x00000200; + /** Self was deleted */ + public static final int DELETE_SELF = 0x00000400; + /** Self was moved */ + public static final int MOVE_SELF = 0x00000800; + public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE | CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE | DELETE_SELF | MOVE_SELF; - + private static final String LOG_TAG = "FileObserver"; private static class ObserverThread extends Thread { diff --git a/core/java/com/android/internal/backup/SystemBackupAgent.java b/core/java/com/android/internal/backup/SystemBackupAgent.java deleted file mode 100644 index 6b396d7..0000000 --- a/core/java/com/android/internal/backup/SystemBackupAgent.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.backup; - -import android.backup.AbsoluteFileBackupHelper; -import android.backup.BackupHelperAgent; - -/** - * Backup agent for various system-managed data - */ -public class SystemBackupAgent extends BackupHelperAgent { - // the set of files that we back up whole, as absolute paths - String[] mFiles = { - /* WallpaperService.WALLPAPER_FILE */ - "/data/data/com.android.settings/files/wallpaper", - }; - - public void onCreate() { - addHelper("system_files", new AbsoluteFileBackupHelper(this, mFiles)); - } -} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6ad2441..1cd04f1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1087,7 +1087,7 @@ android:hasCode="false" android:label="@string/android_system_label" android:allowClearUserData="false" - android:backupAgent="com.android.internal.backup.SystemBackupAgent" + android:backupAgent="com.android.server.SystemBackupAgent" android:icon="@drawable/ic_launcher_android"> <activity android:name="com.android.internal.app.ChooserActivity" android:theme="@style/Theme.Dialog.Alert" diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp index c51d989..0cef35a 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -193,6 +193,7 @@ BackupDataReader::Status() if ((actual) != (expected)) { \ if ((actual) == 0) { \ m_status = EIO; \ + m_done = true; \ } else { \ m_status = errno; \ } \ @@ -222,7 +223,7 @@ BackupDataReader::ReadNextHeader(bool* done, int* type) amt = skip_padding(); if (amt == EIO) { - *done = true; + *done = m_done = true; return NO_ERROR; } else if (amt != NO_ERROR) { @@ -338,6 +339,10 @@ BackupDataReader::ReadEntityData(void* data, size_t size) m_status = errno; return -1; } + if (amt == 0) { + m_status = EIO; + m_done = true; + } m_pos += amt; return amt; } diff --git a/services/java/com/android/server/JournaledFile.java b/services/java/com/android/server/JournaledFile.java new file mode 100644 index 0000000..3d1f52d --- /dev/null +++ b/services/java/com/android/server/JournaledFile.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import java.io.File; +import java.io.IOException; + +public class JournaledFile { + File mReal; + File mTemp; + boolean mWriting; + + public JournaledFile(File real, File temp) { + mReal = real; + mTemp = temp; + } + + /** Returns the file for you to read. + * @more + * Prefers the real file. If it doesn't exist, uses the temp one, and then copies + * it to the real one. If there is both a real file and a temp one, assumes that the + * temp one isn't fully written and deletes it. + */ + public File chooseForRead() { + File result; + if (mReal.exists()) { + result = mReal; + if (mTemp.exists()) { + mTemp.delete(); + } + } else if (mTemp.exists()) { + result = mTemp; + mTemp.renameTo(mReal); + } else { + return mReal; + } + return result; + } + + /** + * Returns a file for you to write. + * @more + * If a write is already happening, throws. In other words, you must provide your + * own locking. + * <p> + * Call {@link #commit} to commit the changes, or {@link #rollback} to forget the changes. + */ + public File chooseForWrite() { + if (mWriting) { + throw new IllegalStateException("uncommitted write already in progress"); + } + if (!mReal.exists()) { + // If the real one doesn't exist, it's either because this is the first time + // or because something went wrong while copying them. In this case, we can't + // trust anything that's in temp. In order to have the chooseForRead code not + // use the temporary one until it's fully written, create an empty file + // for real, which will we'll shortly delete. + try { + mReal.createNewFile(); + } catch (IOException e) { + // Ignore + } + } + + if (mTemp.exists()) { + mTemp.delete(); + } + mWriting = true; + return mTemp; + } + + /** + * Commit changes. + */ + public void commit() { + if (!mWriting) { + throw new IllegalStateException("no file to commit"); + } + mWriting = false; + mTemp.renameTo(mReal); + } + + /** + * Roll back changes. + */ + public void rollback() { + if (!mWriting) { + throw new IllegalStateException("no file to roll back"); + } + mWriting = false; + mTemp.delete(); + } +} diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java new file mode 100644 index 0000000..b681961 --- /dev/null +++ b/services/java/com/android/server/SystemBackupAgent.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.backup.AbsoluteFileBackupHelper; +import android.backup.BackupDataInput; +import android.backup.BackupDataInputStream; +import android.backup.BackupDataOutput; +import android.backup.BackupHelper; +import android.backup.BackupHelperAgent; +import android.content.Context; +import android.os.ParcelFileDescriptor; +import android.os.ServiceManager; +import android.os.SystemService; +import android.util.Log; + +import java.io.File; +import java.io.IOException; + +/** + * Backup agent for various system-managed data + */ +public class SystemBackupAgent extends BackupHelperAgent { + private static final String TAG = "SystemBackupAgent"; + + private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper"; + private static final String WALLPAPER_INFO = "/data/system/wallpaper_info.xml"; + + @Override + public void onCreate() { + addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this, + new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO })); + } + + @Override + public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) + throws IOException { + boolean success = false; + try { + super.onRestore(data, appVersionCode, newState); + + WallpaperService wallpaper = (WallpaperService)ServiceManager.getService( + Context.WALLPAPER_SERVICE); + wallpaper.settingsRestored(); + } catch (IOException ex) { + // If there was a failure, delete everything for the wallpaper, this is too aggresive, + // but this is hopefully a rare failure. + Log.d(TAG, "restore failed", ex); + (new File(WALLPAPER_IMAGE)).delete(); + (new File(WALLPAPER_INFO)).delete(); + } + } +} diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java index d921baf..11981df 100644 --- a/services/java/com/android/server/WallpaperService.java +++ b/services/java/com/android/server/WallpaperService.java @@ -24,8 +24,9 @@ import android.app.IWallpaperServiceCallback; import android.backup.BackupManager; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; import android.os.Binder; import android.os.RemoteException; import android.os.FileObserver; @@ -33,30 +34,38 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.util.Config; import android.util.Log; +import android.util.Xml; +import java.io.IOException; +import java.io.InputStream; import java.io.File; import java.io.FileNotFoundException; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import com.android.internal.util.FastXmlSerializer; class WallpaperService extends IWallpaperService.Stub { - private static final String TAG = WallpaperService.class.getSimpleName(); + private static final String TAG = "WallpaperService"; + + private Object mLock = new Object(); private static final File WALLPAPER_DIR = new File( "/data/data/com.android.settings/files"); private static final String WALLPAPER = "wallpaper"; private static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER); - private static final String PREFERENCES = "wallpaper-hints"; - - private static final String HINT_WIDTH = "hintWidth"; - private static final String HINT_HEIGHT = "hintHeight"; - /** * List of callbacks registered they should each be notified * when the wallpaper is changed. */ private final RemoteCallbackList<IWallpaperServiceCallback> mCallbacks = new RemoteCallbackList<IWallpaperServiceCallback>(); - + /** * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks * that the wallpaper has changed. The CREATE is triggered when there is no @@ -64,16 +73,24 @@ class WallpaperService extends IWallpaperService.Stub { * everytime the wallpaper is changed. */ private final FileObserver mWallpaperObserver = new FileObserver( - WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE) { + WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) { @Override public void onEvent(int event, String path) { - if (path == null) { - return; - } + synchronized (mLock) { + if (path == null) { + return; + } + + // changing the wallpaper means we'll need to back up the new one + long origId = Binder.clearCallingIdentity(); + BackupManager bm = new BackupManager(mContext); + bm.dataChanged(); + Binder.restoreCallingIdentity(origId); - File changedFile = new File(WALLPAPER_DIR, path); - if (WALLPAPER_FILE.equals(changedFile)) { - notifyCallbacks(); + File changedFile = new File(WALLPAPER_DIR, path); + if (WALLPAPER_FILE.equals(changedFile)) { + notifyCallbacksLocked(); + } } } }; @@ -82,17 +99,16 @@ class WallpaperService extends IWallpaperService.Stub { private int mWidth = -1; private int mHeight = -1; + private String mName = ""; public WallpaperService(Context context) { if (Config.LOGD) Log.d(TAG, "WallpaperService startup"); mContext = context; - createFilesDir(); + if (!WALLPAPER_DIR.exists()) { + WALLPAPER_DIR.mkdirs(); + } mWallpaperObserver.startWatching(); - - SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES, - Context.MODE_PRIVATE); - mWidth = preferences.getInt(HINT_WIDTH, -1); - mHeight = preferences.getInt(HINT_HEIGHT, -1); + loadSettingsLocked(); } @Override @@ -102,9 +118,11 @@ class WallpaperService extends IWallpaperService.Stub { } public void clearWallpaper() { - File f = WALLPAPER_FILE; - if (f.exists()) { - f.delete(); + synchronized (mLock) { + File f = WALLPAPER_FILE; + if (f.exists()) { + f.delete(); + } } } @@ -115,70 +133,62 @@ class WallpaperService extends IWallpaperService.Stub { throw new IllegalArgumentException("width and height must be > 0"); } - if (width != mWidth || height != mHeight) { - mWidth = width; - mHeight = height; - - SharedPreferences preferences = mContext.getSharedPreferences(PREFERENCES, - Context.MODE_PRIVATE); - - final SharedPreferences.Editor editor = preferences.edit(); - editor.putInt(HINT_WIDTH, width); - editor.putInt(HINT_HEIGHT, height); - editor.commit(); + synchronized (mLock) { + if (width != mWidth || height != mHeight) { + mWidth = width; + mHeight = height; + saveSettingsLocked(); + } } } public int getWidthHint() throws RemoteException { - return mWidth; + synchronized (mLock) { + return mWidth; + } } public int getHeightHint() throws RemoteException { - return mHeight; + synchronized (mLock) { + return mHeight; + } } public ParcelFileDescriptor getWallpaper(IWallpaperServiceCallback cb) { - try { - mCallbacks.register(cb); - File f = WALLPAPER_FILE; - if (!f.exists()) { - return null; + synchronized (mLock) { + try { + mCallbacks.register(cb); + File f = WALLPAPER_FILE; + if (!f.exists()) { + return null; + } + return ParcelFileDescriptor.open(f, MODE_READ_ONLY); + } catch (FileNotFoundException e) { + /* Shouldn't happen as we check to see if the file exists */ + if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e); } - return ParcelFileDescriptor.open(f, MODE_READ_ONLY); - } catch (FileNotFoundException e) { - - /* Shouldn't happen as we check to see if the file exists */ - if (Config.LOGD) Log.d(TAG, "Error getting wallpaper", e); + return null; } - return null; } - public ParcelFileDescriptor setWallpaper() { + public ParcelFileDescriptor setWallpaper(String name) { checkPermission(android.Manifest.permission.SET_WALLPAPER); - try { - ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE, - MODE_CREATE|MODE_READ_WRITE); - - // changing the wallpaper means we'll need to back up the new one - long origId = Binder.clearCallingIdentity(); - BackupManager bm = new BackupManager(mContext); - bm.dataChanged(); - Binder.restoreCallingIdentity(origId); - - return fd; - } catch (FileNotFoundException e) { - if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e); - } - return null; - } - - private void createFilesDir() { - if (!WALLPAPER_DIR.exists()) { - WALLPAPER_DIR.mkdirs(); + synchronized (mLock) { + if (name == null) name = ""; + mName = name; + saveSettingsLocked(); + try { + ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE, + MODE_CREATE|MODE_READ_WRITE); + return fd; + } catch (FileNotFoundException e) { + if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e); + } + return null; } } - private void notifyCallbacks() { + private void notifyCallbacksLocked() { final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { try { @@ -195,9 +205,185 @@ class WallpaperService extends IWallpaperService.Stub { } private void checkPermission(String permission) { - if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) { + if (PackageManager.PERMISSION_GRANTED!= mContext.checkCallingOrSelfPermission(permission)) { throw new SecurityException("Access denied to process: " + Binder.getCallingPid() + ", must have permission " + permission); } } + + private static JournaledFile makeJournaledFile() { + final String base = "/data/system/wallpaper_info.xml"; + return new JournaledFile(new File(base), new File(base + ".tmp")); + } + + private void saveSettingsLocked() { + JournaledFile journal = makeJournaledFile(); + FileOutputStream stream = null; + try { + stream = new FileOutputStream(journal.chooseForWrite(), false); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(stream, "utf-8"); + out.startDocument(null, true); + + out.startTag(null, "wp"); + out.attribute(null, "width", Integer.toString(mWidth)); + out.attribute(null, "height", Integer.toString(mHeight)); + out.attribute(null, "name", mName); + out.endTag(null, "wp"); + + out.endDocument(); + stream.close(); + journal.commit(); + } catch (IOException e) { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException ex) { + // Ignore + } + journal.rollback(); + } + } + + private void loadSettingsLocked() { + JournaledFile journal = makeJournaledFile(); + FileInputStream stream = null; + File file = journal.chooseForRead(); + boolean success = false; + try { + stream = new FileInputStream(file); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(stream, null); + + int type; + int providerIndex = 0; + do { + type = parser.next(); + if (type == XmlPullParser.START_TAG) { + String tag = parser.getName(); + if ("wp".equals(tag)) { + mWidth = Integer.parseInt(parser.getAttributeValue(null, "width")); + mHeight = Integer.parseInt(parser.getAttributeValue(null, "height")); + mName = parser.getAttributeValue(null, "name"); + } + } + } while (type != XmlPullParser.END_DOCUMENT); + success = true; + } catch (NullPointerException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (NumberFormatException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (XmlPullParserException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (IOException e) { + Log.w(TAG, "failed parsing " + file, e); + } catch (IndexOutOfBoundsException e) { + Log.w(TAG, "failed parsing " + file, e); + } + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + // Ignore + } + + if (!success) { + mWidth = -1; + mHeight = -1; + mName = ""; + } + } + + void settingsRestored() { + boolean success = false; + synchronized (mLock) { + loadSettingsLocked(); + // If there's a wallpaper name, we use that. If that can't be loaded, then we + // use the default. + if ("".equals(mName)) { + success = true; + } else { + success = restoreNamedResourceLocked(); + } + } + + if (!success) { + Log.e(TAG, "Failed to restore wallpaper: '" + mName + "'"); + mName = ""; + WALLPAPER_FILE.delete(); + } + saveSettingsLocked(); + } + + boolean restoreNamedResourceLocked() { + if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) { + String resName = mName.substring(4); + + String pkg = null; + int colon = resName.indexOf(':'); + if (colon > 0) { + pkg = resName.substring(0, colon); + } + + String ident = null; + int slash = resName.lastIndexOf('/'); + if (slash > 0) { + ident = resName.substring(slash+1); + } + + String type = null; + if (colon > 0 && slash > 0 && (slash-colon) > 1) { + type = resName.substring(colon+1, slash); + } + + if (pkg != null && ident != null && type != null) { + int resId = -1; + InputStream res = null; + FileOutputStream fos = null; + try { + Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED); + Resources r = c.getResources(); + resId = r.getIdentifier(resName, null, null); + if (resId == 0) { + Log.e(TAG, "couldn't resolve identifier pkg=" + pkg + " type=" + type + + " ident=" + ident); + return false; + } + + res = r.openRawResource(resId); + fos = new FileOutputStream(WALLPAPER_FILE); + + byte[] buffer = new byte[32768]; + int amt; + while ((amt=res.read(buffer)) > 0) { + fos.write(buffer, 0, amt); + } + // mWallpaperObserver will notice the close and send the change broadcast + + Log.d(TAG, "Restored wallpaper: " + resName); + return true; + } catch (NameNotFoundException e) { + Log.e(TAG, "Package name " + pkg + " not found"); + } catch (Resources.NotFoundException e) { + Log.e(TAG, "Resource not found: " + resId); + } catch (IOException e) { + Log.e(TAG, "IOException while restoring wallpaper ", e); + } finally { + if (res != null) { + try { + res.close(); + } catch (IOException ex) {} + } + if (fos != null) { + try { + fos.close(); + } catch (IOException ex) {} + } + } + } + } + return false; + } } |