Only restore the bits for wallpapers that aren't built in.
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -25,7 +25,7 @@ interface IWallpaperService {
|
||||
/**
|
||||
* Set the wallpaper.
|
||||
*/
|
||||
ParcelFileDescriptor setWallpaper();
|
||||
ParcelFileDescriptor setWallpaper(String name);
|
||||
|
||||
/**
|
||||
* Get the wallpaper.
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
107
services/java/com/android/server/JournaledFile.java
Normal file
107
services/java/com/android/server/JournaledFile.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
67
services/java/com/android/server/SystemBackupAgent.java
Normal file
67
services/java/com/android/server/SystemBackupAgent.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
File changedFile = new File(WALLPAPER_DIR, path);
|
||||
if (WALLPAPER_FILE.equals(changedFile)) {
|
||||
notifyCallbacks();
|
||||
// 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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user