From 4e14a829129feee14ebe453f61a124784c870610 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 8 Apr 2010 12:54:23 -0700 Subject: [PATCH 1/2] SDK: more backup/restore documentation work Still not complete, but here's a lot more of the necessary documentation. Submitting a checkpoint seems prudent. Bug #2465360 Change-Id: Ifff60d57e4b24cee21f3a34f5f50e290d377c386 --- core/java/android/app/backup/BackupAgent.java | 100 ++++++++++++++---- .../android/app/backup/BackupAgentHelper.java | 5 +- .../android/app/backup/BackupDataInput.java | 72 ++++++++++--- .../android/app/backup/BackupDataOutput.java | 40 ++++++- .../java/android/app/backup/BackupHelper.java | 9 +- .../android/app/backup/BackupManager.java | 35 +++--- .../android/app/backup/FileBackupHelper.java | 24 ++--- .../backup/SharedPreferencesBackupHelper.java | 40 ++++++- core/res/res/values/attrs_manifest.xml | 4 +- .../topics/manifest/application-element.jd | 54 +++++++++- 10 files changed, 303 insertions(+), 80 deletions(-) diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index f9dcab87dbcf5..0bb2cb5313ae3 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -29,18 +29,57 @@ import android.util.Log; import java.io.IOException; /** - * This is the central interface between an application and Android's settings - * backup mechanism. Any implementation of a backup agent should perform backup - * and restore actions in + * {@link android.app.backup.BackupAgent} is the central interface between an + * application and Android's data backup infrastructure. An application that wishes + * to participate in the backup and restore mechanism will declare a subclass of + * {@link android.app.backup.BackupAgent}, implement the * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)} - * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)} - * respectively. + * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)} methods, + * and provide the name of its agent class in the AndroidManifest.xml file via + * the <application> tag's android:backupAgent attribute. *

- * A backup agent based on convenient helper classes is available in - * {@link android.app.backup.BackupAgentHelper} for less complex implementation - * requirements. + * Basic Operation *

- * STOPSHIP write more documentation about the backup process here. + * When the application makes changes to data that it wishes to keep backed up, + * it should call the + * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method. + * This notifies the Android backup manager that the application needs an opportunity + * to update its backup image. The backup manager, in turn, will then schedule a + * backup pass to be performed at an opportune time. + *

+ * Restore operations are typically only performed when applications are first + * installed on a device. At that time, the operating system checks to see whether + * there is a previously-saved data set available for the application, and if so, + * begins an immediate restore pass to deliver that data as part of the installation + * process. + *

+ * When a backup or restore pass is run, the application's process will be launched + * (if not already running), the manifest-declared agent class instantiated within + * that process, and the agent's {@link #onCreate()} method invoked. This prepares the + * agent instance to run the actual backup or restore logic. At this point the + * agent's + * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or + * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be + * invoked as appropriate for the operation being performed. + *

+ * A backup data set consists of one or more "entities," flattened binary data records + * that are each identified with a key string unique within the data set. Adding a + * record to the active data set, or updating an existing record, are done by simply + * writing new entity data under the desired key. Deleting an entity from the data set + * is done by writing an entity under that key with header specifying a negative data + * size, and no actual entity data. + *

+ * Helper Classes + *

+ * An extensible agent based on convenient helper classes is available in + * {@link android.app.backup.BackupAgentHelper}. That class is particularly + * suited to handling of simple file or {@link android.content.SharedPreferences} + * backup and restore. + * + * @see android.app.backup.BackupManager + * @see android.app.backup.BackupAgentHelper + * @see android.app.backup.BackupDataInput + * @see android.app.backup.BackupDataOutput */ public abstract class BackupAgent extends ContextWrapper { private static final String TAG = "BackupAgent"; @@ -50,9 +89,22 @@ public abstract class BackupAgent extends ContextWrapper { super(null); } + /** + * Provided as a convenience for agent implementations that need an opportunity + * to do one-time initialization before the actual backup or restore operation + * is begun. + *

+ * Agents do not need to override this method. + */ public void onCreate() { } + /** + * Provided as a convenience for agent implementations that need to do some + * sort of shutdown process after backup or restore is completed. + *

+ * Agents do not need to override this method. + */ public void onDestroy() { } @@ -65,18 +117,26 @@ public abstract class BackupAgent extends ContextWrapper { * cases, a representation of the final backup state after this pass should * be written to the file pointed to by the file descriptor wrapped in * newState. + *

+ * Each entity written to the {@link android.app.backup.BackupDataOutput} + * data stream will be transmitted + * over the current backup transport and stored in the remote data set under + * the key supplied as part of the entity. Writing an entity with a negative + * data size instructs the transport to delete whatever entity currently exists + * under that key from the remote data set. * * @param oldState An open, read-only ParcelFileDescriptor pointing to the * last backup state provided by the application. May be * null, in which case no prior state is being * provided and the application should perform a full backup. * @param data A structured wrapper around an open, read/write - * ParcelFileDescriptor pointing to the backup data destination. + * file descriptor pointing to the backup data destination. * Typically the application will use backup helper classes to * write to this file. * @param newState An open, read/write ParcelFileDescriptor pointing to an * empty file. The application should record the final backup - * state here after writing the requested data to dataFd. + * state here after writing the requested data to the data + * output stream. */ public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException; @@ -84,8 +144,7 @@ public abstract class BackupAgent extends ContextWrapper { /** * The application is being restored from backup and should replace any * existing data with the contents of the backup. The backup data is - * provided in the file descriptor pointed to by the - * {@link android.app.backup.BackupDataInput} instance data. Once + * provided through the data parameter. Once * the restore is finished, the application should write a representation of * the final state to the newState file descriptor. *

@@ -98,17 +157,18 @@ public abstract class BackupAgent extends ContextWrapper { * before proceeding. * * @param data A structured wrapper around an open, read-only - * ParcelFileDescriptor pointing to a full snapshot of the - * application's data. Typically the application will use helper - * classes to read this data. - * @param appVersionCode The android:versionCode value of the application - * that backed up this particular data set. This makes it easier - * for an application's agent to distinguish among several + * file descriptor pointing to a full snapshot of the + * application's data. The application should consume every + * entity represented in this data stream. + * @param appVersionCode The + * {@link android.R.styleable#AndroidManifest_versionCode android:versionCode} + * value of the application that backed up this particular data set. This + * makes it possible for an application's agent to distinguish among any * possible older data versions when asked to perform the restore * operation. * @param newState An open, read/write ParcelFileDescriptor pointing to an * empty file. The application should record the final backup - * state here after restoring its data from dataFd. + * state here after restoring its data from the data stream. */ public abstract void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) diff --git a/core/java/android/app/backup/BackupAgentHelper.java b/core/java/android/app/backup/BackupAgentHelper.java index 7b6be2327b462..788b1b53d07da 100644 --- a/core/java/android/app/backup/BackupAgentHelper.java +++ b/core/java/android/app/backup/BackupAgentHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * 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. @@ -30,6 +30,9 @@ import java.io.IOException; * have the BackupAgentHelper implementation process the data. *

* STOPSHIP: document! + * + * @see FileBackupHelper + * @see SharedPreferencesBackupHelper */ public class BackupAgentHelper extends BackupAgent { static final String TAG = "BackupAgentHelper"; diff --git a/core/java/android/app/backup/BackupDataInput.java b/core/java/android/app/backup/BackupDataInput.java index 2da0c11182b87..976e0c924adec 100644 --- a/core/java/android/app/backup/BackupDataInput.java +++ b/core/java/android/app/backup/BackupDataInput.java @@ -20,7 +20,41 @@ import java.io.FileDescriptor; import java.io.IOException; /** - * STOPSHIP: document! + * BackupDataInput is the structured interface used for passing the contents of + * a backup data set to an application's {@link BackupAgent} class in its + * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor)} + * method. The data is presented as a set of "entities," each + * representing one named record as previously stored by the agent's + * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor)} + * implementation. An entity is composed of a descriptive header plus a + * byte array that holds its raw data. + *

+ * The agent must consume every entity in the data stream, otherwise the + * restored state of the application will be incomplete. + *

+ * Example + *

+ * A typical + * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore(data, appVersionCode, newState)} + * implementation might be structured something like this: + *

+ * while (data.readNextHeader()) {
+ *     String key = data.getKey();
+ *     int dataSize = data.getDataSize();
+ *
+ *     if (key.equals(MY_BACKUP_KEY_ONE)) {
+ *         // process this kind of record here
+ *         byte[] buffer = new byte[dataSize];
+ *         data.readEntityData(buffer, 0, dataSize); // reads the entire entity at once
+ *
+ *         // now 'buffer' holds the raw data and can be processed however
+ *         // the agent wishes
+ *         processBackupKeyOne(buffer);
+ *     } else if (key.equals(MY_BACKUP_KEY_TO_IGNORE) {
+ *         // a key we recognize but wish to discard
+ *         data.skipEntityData();
+ *     } // ... etc.
+ * }
*/ public class BackupDataInput { int mBackupReader; @@ -52,10 +86,12 @@ public class BackupDataInput { } /** - * Consumes the next header from the restore stream. + * Extract the next entity header from the restore stream. After this method + * return success, the {@link #getKey()} and {@link #getDataSize()} methods can + * be used to inspect the entity that is now available for processing. * - * @return true when there is an entity ready for consumption from the restore stream, - * false if the restore stream has been fully consumed. + * @return true when there is an entity ready for consumption from the + * restore stream, false if the restore stream has been fully consumed. * @throws IOException if an error occurred while reading the restore stream */ public boolean readNextHeader() throws IOException { @@ -71,25 +107,25 @@ public class BackupDataInput { } else { // error mHeaderReady = false; - throw new IOException("result=0x" + Integer.toHexString(result)); + throw new IOException("failed: 0x" + Integer.toHexString(result)); } } /** - * Report the key associated with the current record in the restore stream - * @return the current record's key string + * Report the key associated with the current entity in the restore stream + * @return the current entity's key string * @throws IllegalStateException if the next record header has not yet been read */ public String getKey() { if (mHeaderReady) { return mHeader.key; } else { - throw new IllegalStateException("mHeaderReady=false"); + throw new IllegalStateException("Entity header not read"); } } /** - * Report the size in bytes of the data associated with the current record in the + * Report the size in bytes of the data associated with the current entity in the * restore stream. * * @return The size of the record's raw data, in bytes @@ -99,7 +135,7 @@ public class BackupDataInput { if (mHeaderReady) { return mHeader.dataSize; } else { - throw new IllegalStateException("mHeaderReady=false"); + throw new IllegalStateException("Entity header not read"); } } @@ -107,13 +143,15 @@ public class BackupDataInput { * Read a record's raw data from the restore stream. The record's header must first * have been processed by the {@link #readNextHeader()} method. Multiple calls to * this method may be made in order to process the data in chunks; not all of it - * must be read in a single call. + * must be read in a single call. Once all of the raw data for the current entity + * has been read, further calls to this method will simply return zero. * * @param data An allocated byte array of at least 'size' bytes * @param offset Offset within the 'data' array at which the data will be placed - * when read from the stream. - * @param size The number of bytes to read in this pass. - * @return The number of bytes of data read + * when read from the stream + * @param size The number of bytes to read in this pass + * @return The number of bytes of data read. Once all of the data for this entity + * has been read, further calls to this method will return zero. * @throws IOException if an error occurred when trying to read the restore data stream */ public int readEntityData(byte[] data, int offset, int size) throws IOException { @@ -125,12 +163,12 @@ public class BackupDataInput { throw new IOException("result=0x" + Integer.toHexString(result)); } } else { - throw new IllegalStateException("mHeaderReady=false"); + throw new IllegalStateException("Entity header not read"); } } /** - * Consume the current record's data without actually reading it into a buffer + * Consume the current entity's data without extracting it into a buffer * for further processing. This allows a {@link android.app.backup.BackupAgent} to * efficiently discard obsolete or otherwise uninteresting records during the * restore operation. @@ -141,7 +179,7 @@ public class BackupDataInput { if (mHeaderReady) { skipEntityData_native(mBackupReader); } else { - throw new IllegalStateException("mHeaderReady=false"); + throw new IllegalStateException("Entity header not read"); } } diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java index 3767797b607c4..a69547ae777d9 100644 --- a/core/java/android/app/backup/BackupDataOutput.java +++ b/core/java/android/app/backup/BackupDataOutput.java @@ -16,11 +16,49 @@ package android.app.backup; +import android.os.ParcelFileDescriptor; + import java.io.FileDescriptor; import java.io.IOException; /** - * STOPSHIP: document + * This class is the structured conduit through which a {@link BackupAgent} commits + * information to the current backup data set. Data written for backup is presented + * as a set of "entities," key/value pairs in which each binary data record "value" is + * named with a string "key." + *

+ * To commit a data record to the backup transport, the agent's + * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor)} + * method first writes an "entity header" that supplies the key string for the record + * and the total size of the binary value for the record. After the header has been + * written the agent then writes the binary entity value itself. The entity value can + * be written in multiple chunks if desired, as long as the total count of bytes written + * matches what was supplied to {@link #writeEntityHeader(String, int)}. + *

+ * Entity key strings are considered to be unique within a given application's backup + * data set. If a new entity is written under an existing key string, its value will + * replace any previous value in the transport's remote data store. A record can be + * removed entirely from the remote data set by writing a new entity header using the + * existing record's key, but supplying a negative dataSize parameter. + * When doing this the agent does not need to call {@link #writeEntityData(byte[], int)}. + *

+ * Example + *

+ * Here is an example illustrating a way to back up the value of a String variable + * called mStringToBackUp: + *

+ * static final String MY_STRING_KEY = "storedstring";
+ *
+ * public void {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)}
+ *         throws IOException {
+ *     ...
+ *     byte[] stringBytes = mStringToBackUp.getBytes();
+ *     data.writeEntityHeader(MY_STRING_KEY, stringBytes.length);
+ *     data.writeEntityData(stringBytes, stringBytes.length);
+ *     ...
+ * }
+ * + * @see BackupAgent */ public class BackupDataOutput { int mBackupWriter; diff --git a/core/java/android/app/backup/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java index b7ef268ae443d..3f41ed24dfcaf 100644 --- a/core/java/android/app/backup/BackupHelper.java +++ b/core/java/android/app/backup/BackupHelper.java @@ -20,10 +20,10 @@ import android.os.ParcelFileDescriptor; /** * A convenient interface to be used with the - * {@link android.app.backup.BackupAgentHelper} to implement backup and restore of + * {@link android.app.backup.BackupAgentHelper} class to implement backup and restore of * arbitrary data types. *

- * STOPSHOP: document! + * STOPSHIP: document! */ public interface BackupHelper { /** @@ -46,9 +46,8 @@ public interface BackupHelper { /** * Called by {@link android.app.backup.BackupAgentHelper BackupAgentHelper} - * to write the new backup state file corresponding to - * the current state of the app's data at the time the backup operation was - * performed. + * after a restore operation to write the backup state file corresponding to + * the data as processed by the helper. */ public void writeNewStateDescription(ParcelFileDescriptor fd); } diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index 7eb626582336a..707082730afec 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -25,9 +25,9 @@ import android.os.ServiceManager; import android.util.Log; /** - * BackupManager is the interface to the system's backup service. Applications - * simply instantiate one, and then use that instance to communicate with the - * backup infrastructure. + * The BackupManager class is interface through which an application's user interface + * code will interact with the Android backup service. Applications simply instantiate one + * and then issue calls through that instance. *

* When an application has made changes to data which should be backed up, a * call to {@link #dataChanged()} will notify the backup service. The system @@ -35,24 +35,23 @@ import android.util.Log; * calls to {@link #dataChanged()} have no further effect until the backup * operation actually occurs. *

- * The backup operation itself begins with the system launching the + * A backup or restore operation begins with the system launching the * {@link android.app.backup.BackupAgent} subclass declared in your manifest. See the * documentation for {@link android.app.backup.BackupAgent} for a detailed description - * of how the backup then proceeds. - *

- * A simple implementation of a BackupAgent useful for backing up Preferences - * and files is available by using {@link android.app.backup.BackupAgentHelper}. - *

- * STOPSHIP: more documentation! + * of how the operation then proceeds. *

* XML attributes *

- * See {@link android.R.styleable#AndroidManifestApplication - * AndroidManifest.xml's application attributes} + * Several attributes affecting the operation of the backup and restore mechanism + * can be set on the <application> tag in the application's + * AndroidManifest.xml file. See the documentation on the + * {@link android.R.styleable#AndroidManifestApplication AndroidManifest.xml's application attributes} + * for details. * * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore + * @attr ref android.R.styleable#AndroidManifestApplication_restoreAnyVersion */ public class BackupManager { private static final String TAG = "BackupManager"; @@ -82,7 +81,8 @@ public class BackupManager { /** * Notifies the Android backup system that your application wishes to back up * new changes to its data. A backup operation using your application's - * {@link android.app.backup.BackupAgent} subclass will be scheduled when you call this method. + * {@link android.app.backup.BackupAgent} subclass will be scheduled when you + * call this method. */ public void dataChanged() { checkServiceBinder(); @@ -97,11 +97,12 @@ public class BackupManager { /** * Convenience method for callers who need to indicate that some other package - * needs a backup pass. This can be relevant in the case of groups of packages - * that share a uid, for example. - * + * needs a backup pass. This can be useful in the case of groups of packages + * that share a uid. + *

* This method requires that the application hold the "android.permission.BACKUP" - * permission if the package named in the argument is not the caller's own. + * permission if the package named in the argument does not run under the same uid + * as the caller. */ public static void dataChanged(String packageName) { checkServiceBinder(); diff --git a/core/java/android/app/backup/FileBackupHelper.java b/core/java/android/app/backup/FileBackupHelper.java index 3ce5b4315729e..a326941a4ce5e 100644 --- a/core/java/android/app/backup/FileBackupHelper.java +++ b/core/java/android/app/backup/FileBackupHelper.java @@ -26,18 +26,13 @@ import java.io.File; * A helper class which can be used in conjunction with * {@link android.app.backup.BackupAgentHelper} to manage the backup of a set of * files. Whenever backup is performed, all files changed since the last backup - * will be saved in their entirety. During the first time the backup happens, - * all the files in the list will be backed up. Note that this should only be - * used with small configuration files and not with large binary files. + * will be saved in their entirety. During the first time the backup happens, + * every file in the list will be backed up. Note that this should only be + * used with small configuration files, not with large binary files. *

- * Any files not present in the list of files during the restore procedure will - * be ignored. If files present in a previous version of an application are - * removed in subsequent versions, it is the responsibility of the developer to - * design a mechanism to remove those files. Otherwise files no longer needed - * will linger and consume space on the device. - *

- * STOPSHIP: document! [manages backup of a set of files; restore is totally - * opaque] + * During restore, if the helper encounters data for a file that was not + * specified when the FileBackupHelper object was constructed, that data + * will be ignored. */ public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper { private static final String TAG = "FileBackupHelper"; @@ -69,8 +64,8 @@ public class FileBackupHelper extends FileBackupHelperBase implements BackupHelp * now. When oldState is null, all the files will * be backed up. *

- * This should be called from {@link android.app.backup.BackupAgentHelper} - * directly. See + * This should only be called directly from within the {@link BackupAgentHelper} + * implementation. See * {@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)} * for a description of parameter meanings. */ @@ -91,6 +86,9 @@ public class FileBackupHelper extends FileBackupHelperBase implements BackupHelp /** * Restore one record [representing a single file] from the restore dataset. + *

+ * This should only be called directly from within the {@link BackupAgentHelper} + * implementation. */ public void restoreEntity(BackupDataInputStream data) { if (DEBUG) Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size()); diff --git a/core/java/android/app/backup/SharedPreferencesBackupHelper.java b/core/java/android/app/backup/SharedPreferencesBackupHelper.java index f9e6b286b7daa..9efecc5f06229 100644 --- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java +++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java @@ -26,11 +26,45 @@ import java.io.File; /** * A helper class which can be used in conjunction with * {@link android.app.backup.BackupAgentHelper} to manage the backup of - * {@link android.content.SharedPreferences}. Whenever backup is performed it + * {@link android.content.SharedPreferences}. Whenever a backup is performed it * will back up all named shared preferences which have changed since the last - * backup. + * backup operation. *

- * STOPSHIP: document! + * To use this class, the application's agent class should extend + * {@link android.app.backup.BackupAgentHelper}. Then, in the agent's + * {@link BackupAgent#onCreate()} method, an instance of this class should be + * allocated and installed as a backup/restore handler within the BackupAgentHelper + * framework. An implementation of an agent supporting backup and restore for + * an application that wishes to back up two groups of {@link android.content.SharedPreferences} + * data might look something like this: + *

+ * import android.app.backup.BackupAgentHelper;
+ * import android.app.backup.SharedPreferencesBackupHelper;
+ *
+ * public class MyBackupAgent extends BackupAgentHelper {
+ *     // The names of the SharedPreferences groups that the application maintains.  These
+ *     // are the same strings that are passed to {@link Context#getSharedPreferences(String, int)}.
+ *     static final String PREFS_DISPLAY = "displayprefs";
+ *     static final String PREFS_SCORES = "highscores";
+ *
+ *     // An arbitrary string used within the BackupAgentHelper implementation to
+ *     // identify the SharedPreferenceBackupHelper's data.
+ *     static final String MY_PREFS_BACKUP_KEY = "myprefs";
+ *
+ *     // Simply allocate a helper and install it
+ *     void onCreate() {
+ *         SharedPreferencesBackupHelper helper =
+ *                 new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
+ *         addHelper(MY_PREFS_BACKUP_KEY, helper);
+ *     }
+ * }
+ *

+ * No further implementation is needed; the BackupAgentHelper mechanism automatically + * dispatches the + * {@link BackupAgent#onBackup(android.os.ParcelFileDescriptor, BackupDataOutput, android.os.ParcelFileDescriptor) BackupAgent.onBackup()} + * and + * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore()} + * callbacks to the SharedPreferencesBackupHelper as appropriate. */ public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper { private static final String TAG = "SharedPreferencesBackupHelper"; diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 3585bf14bb422..ed7447c71516a 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -584,8 +584,8 @@ - +