Merge "Build searchables list after boot" into froyo
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 0bb2cb5..5245da5 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -29,42 +29,44 @@
 import java.io.IOException;
 
 /**
- * {@link android.app.backup.BackupAgent} is the central interface between an
+ * Provides 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)} methods,
- * and provide the name of its agent class in the AndroidManifest.xml file via
- * the <application> tag's android:backupAgent attribute.
- * <p>
- * <b>Basic Operation</b>
+ * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
+ * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods,
+ * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via
+ * the <code><a
+ * href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+ * tag's {@code android:backupAgent} attribute.
+ * <h3>Basic Operation</h3>
  * <p>
  * 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
+ * This notifies the Android Backup Manager that the application needs an opportunity
+ * to update its backup image.  The Backup Manager, in turn, schedules a
  * backup pass to be performed at an opportune time.
  * <p>
- * Restore operations are typically only performed when applications are first
+ * Restore operations are typically performed only 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
+ * there is a previously-saved data set available for the application being installed, and if so,
+ * begins an immediate restore pass to deliver the backup data as part of the installation
  * process.
  * <p>
- * 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
+ * When a backup or restore pass is run, the application's process is launched
+ * (if not already running), the manifest-declared backup agent class (in the {@code
+ * android:backupAgent} attribute) is instantiated within
+ * that process, and the agent's {@link #onCreate()} method is 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.
  * <p>
- * 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
+ * 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 is 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.
diff --git a/core/java/android/app/backup/BackupAgentHelper.java b/core/java/android/app/backup/BackupAgentHelper.java
index 6d73090..d47ca22 100644
--- a/core/java/android/app/backup/BackupAgentHelper.java
+++ b/core/java/android/app/backup/BackupAgentHelper.java
@@ -24,19 +24,19 @@
  * A convenient {@link BackupAgent} wrapper class that automatically manages
  * heterogeneous data sets within the backup data, each identified by a unique
  * key prefix.  When processing a backup or restore operation, the BackupAgentHelper
- * dispatches to one or more installed {@link BackupHelper helpers} objects, each
+ * dispatches to one or more installed {@link BackupHelper} objects, each
  * of which is responsible for a defined subset of the data being processed.
  * <p>
- * An application will typically extend this class in their own
+ * An application will typically extend this class in its own
  * backup agent. Then, within the agent's {@link BackupAgent#onCreate() onCreate()}
- * method, it will call {@link #addHelper(String, BackupHelper)} one or more times to
+ * method, it will call {@link #addHelper(String, BackupHelper) addHelper()} one or more times to
  * install the handlers for each kind of data it wishes to manage within its backups.
  * <p>
- * The Android framework currently provides two predefined {@link BackupHelper} classes:
- * {@link FileBackupHelper}, which manages the backup and restore of entire files
- * within an application's data directory hierarchy; and {@link SharedPreferencesBackupHelper},
- * which manages the backup and restore of an application's
- * {@link android.content.SharedPreferences} data.
+ * The Android framework currently provides two predefined {@link BackupHelper} classes:</p>
+ * <ul><li>{@link FileBackupHelper} - Manages the backup and restore of entire files
+ * within an application's data directory hierarchy.</li>
+ * <li>{@link SharedPreferencesBackupHelper} - Manages the backup and restore of an
+ * application's {@link android.content.SharedPreferences} data.</li></ul>
  * <p>
  * An application can also implement its own helper classes to work within the
  * {@link BackupAgentHelper} framework.  See the {@link BackupHelper} interface
diff --git a/core/java/android/app/backup/BackupDataInput.java b/core/java/android/app/backup/BackupDataInput.java
index 976e0c9..43b920a 100644
--- a/core/java/android/app/backup/BackupDataInput.java
+++ b/core/java/android/app/backup/BackupDataInput.java
@@ -20,40 +20,42 @@
 import java.io.IOException;
 
 /**
- * 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)}
+ * Provides the structured interface through which a {@link BackupAgent} reads
+ * information from the backup data set, via its
+ * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
  * 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.
+ * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+ * onBackup()} implementation.  An entity is composed of a descriptive header plus a
+ * byte array that holds the raw data saved in the remote backup.
  * <p>
  * The agent must consume every entity in the data stream, otherwise the
  * restored state of the application will be incomplete.
- * <p>
- * <b>Example</b>
+ * <h3>Example</h3>
  * <p>
  * A typical
- * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore(data, appVersionCode, newState)}
- * implementation might be structured something like this:
+ * {@link BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+ * onRestore()} implementation might be structured something like this:
  * <pre>
- * while (data.readNextHeader()) {
- *     String key = data.getKey();
- *     int dataSize = data.getDataSize();
+ * public void onRestore(BackupDataInput data, int appVersionCode,
+ *                       ParcelFileDescriptor newState) {
+ *     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
+ *         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.
+ *             // 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.
+ *    }
  * }</pre>
  */
 public class BackupDataInput {
diff --git a/core/java/android/app/backup/BackupDataInputStream.java b/core/java/android/app/backup/BackupDataInputStream.java
index 465b3b6..94c7845 100644
--- a/core/java/android/app/backup/BackupDataInputStream.java
+++ b/core/java/android/app/backup/BackupDataInputStream.java
@@ -20,17 +20,17 @@
 import java.io.IOException;
 
 /**
- * Used by {@link BackupHelper} classes within the {@link BackupAgentHelper} mechanism,
- * this class provides an {@link java.io.InputStream}-like interface for accessing an
- * entity's data during a restore operation.
+ * Provides an {@link java.io.InputStream}-like interface for accessing an
+ * entity's data during a restore operation. Used by {@link BackupHelper} classes within the {@link
+ * BackupAgentHelper} mechanism.
  * <p>
- * When {@link BackupHelper#restoreEntity(BackupDataInputStream) BackupHelper.restoreEntity(BackupDataInputStream)}
+ * When {@link BackupHelper#restoreEntity(BackupDataInputStream) BackupHelper.restoreEntity()}
  * is called, the current entity's header has already been read from the underlying
  * {@link BackupDataInput}.  The entity's key string and total data size are available
  * through this class's {@link #getKey()} and {@link #size()} methods, respectively.
  * <p class="note">
- * <em>Note:</em> The caller should take care not to seek or close the underlying data
- * source, or to read more than {@link #size()} bytes total from the stream.</p>
+ * <strong>Note:</strong> The caller should take care not to seek or close the underlying data
+ * source, nor read more than {@link #size()} bytes from the stream.</p>
  *
  * @see BackupAgentHelper
  * @see BackupHelper
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index a69547a..22668b6 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -22,27 +22,28 @@
 import java.io.IOException;
 
 /**
- * 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
+ * Provides the structured interface through which a {@link BackupAgent} commits
+ * information to the backup data set, via its {@link
+ * BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+ * onBackup()} method.  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."
  * <p>
  * 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
+ * {@link BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+ * onBackup()} 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
+ * 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)}.
+ * matches what was supplied to {@link #writeEntityHeader(String, int) writeEntityHeader()}.
  * <p>
  * 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
+ * data set. If a backup agent writes a new entity under an existing key string, its value will
+ * replace any previous value in the transport's remote data store.  You can remove a record
+ * entirely from the remote data set by writing a new entity header using the
  * existing record's key, but supplying a negative <code>dataSize</code> parameter.
- * When doing this the agent does not need to call {@link #writeEntityData(byte[], int)}.
- * <p>
- * <b>Example</b>
+ * When you do so, the agent does not need to call {@link #writeEntityData(byte[], int)}.
+ * <h3>Example</h3>
  * <p>
  * Here is an example illustrating a way to back up the value of a String variable
  * called <code>mStringToBackUp</code>:
@@ -73,9 +74,9 @@
     }
 
     /**
-     * Mark the beginning of one record in the backup data stream.
-     *
-     * @param key
+     * Mark the beginning of one record in the backup data stream. This must be called before
+     * {@link #writeEntityData}.
+     * @param key A string key that uniquely identifies the data record within the application
      * @param dataSize The size in bytes of this record's data.  Passing a dataSize
      *    of -1 indicates that the record under this key should be deleted.
      * @return The number of bytes written to the backup stream
diff --git a/core/java/android/app/backup/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java
index 87b581b..e3f0d54 100644
--- a/core/java/android/app/backup/BackupHelper.java
+++ b/core/java/android/app/backup/BackupHelper.java
@@ -19,7 +19,7 @@
 import android.os.ParcelFileDescriptor;
 
 /**
- * This interface defines the calling interface that {@link BackupAgentHelper} uses
+ * Defines the calling interface that {@link BackupAgentHelper} uses
  * when dispatching backup and restore operations to the installed helpers.
  * Applications can define and install their own helpers as well as using those
  * provided as part of the Android framework.
@@ -43,15 +43,28 @@
      * exists now.
      * <p>
      * Implementing this method is much like implementing
-     * {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
-     * &mdash; the method parameters are the same.  When this method is invoked the
+     * {@link BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)
+     * onBackup()} &mdash; the method parameters are the same.  When this method is invoked the
      * {@code oldState} descriptor points to the beginning of the state data
      * written during this helper's previous backup operation, and the {@code newState}
      * descriptor points to the file location at which the helper should write its
      * new state after performing the backup operation.
      * <p class="note">
-     * <em>Note:</em> The helper should not close or seek either the {@code oldState} or
+     * <strong>Note:</strong> The helper should not close or seek either the {@code oldState} or
      * the {@code newState} file descriptors.</p>
+     *
+     * @param oldState An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the
+     *            last backup state provided by the application. May be
+     *            <code>null</code>, in which case no prior state is being
+     *            provided and the application should perform a full backup.
+     * @param data An open, read/write {@link BackupDataOutput}
+     *            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 {@link android.os.ParcelFileDescriptor} pointing to an
+     *            empty file. The application should record the final backup
+     *            state here after writing the requested data to the <code>data</code>
+     *            output stream.
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState);
@@ -61,8 +74,11 @@
      * to restore a single entity from the restore data set.  This method will be
      * called for each entity in the data set that belongs to this handler.
      * <p class="note">
-     * <em>Note:</em> Do not close the <code>data</code> stream.  Do not read more than
-     * <code>data.size()</code> bytes from <code>data</code>.</p>
+     * <strong>Note:</strong> Do not close the <code>data</code> stream.  Do not read more than
+     * {@link android.app.backup.BackupDataInputStream#size() size()} bytes from
+     * <code>data</code>.</p>
+     *
+     * @param data An open {@link BackupDataInputStream} from which the backup data can be read.
      */
     public void restoreEntity(BackupDataInputStream data);
 
@@ -71,15 +87,18 @@
      * after a restore operation to write the backup state file corresponding to
      * the data as processed by the helper.  The data written here will be
      * available to the helper during the next call to its
-     * {@link #performBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
-     * method.
+     * {@link #performBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)
+     * performBackup()} method.
      * <p>
-     * Note that this method will be called even if the handler's
-     * {@link #restoreEntity(BackupDataInputStream)} method was never invoked during
+     * This method will be called even if the handler's
+     * {@link #restoreEntity(BackupDataInputStream) restoreEntity()} method was never invoked during
      * the restore operation.
      * <p class="note">
-     * <em>Note:</em> The helper should not close or seek the {@code newState}
+     * <strong>Note:</strong> The helper should not close or seek the {@code newState}
      * file descriptor.</p>
+     *
+     * @param newState A {@link android.os.ParcelFileDescriptor} to which the new state will be
+     * written.
      */
     public void writeNewStateDescription(ParcelFileDescriptor newState);
 }
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 7070827..52dd707 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -25,9 +25,9 @@
 import android.util.Log;
 
 /**
- * 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.
+ * The interface through which an application interacts with the Android backup service to
+ * request backup and restore operations.
+ * Applications instantiate it using the constructor and issue calls through that instance.
  * <p>
  * 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,19 +35,16 @@
  * calls to {@link #dataChanged()} have no further effect until the backup
  * operation actually occurs.
  * <p>
- * A backup or restore operation begins with the system launching the
- * {@link android.app.backup.BackupAgent} subclass declared in your manifest. See the
+ * A backup or restore operation for your application begins when the system launches the
+ * {@link android.app.backup.BackupAgent} subclass you've declared in your manifest. See the
  * documentation for {@link android.app.backup.BackupAgent} for a detailed description
  * of how the operation then proceeds.
  * <p>
- * <b>XML attributes</b>
- * <p>
  * Several attributes affecting the operation of the backup and restore mechanism
- * can be set on the &lt;application&gt; 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.
- * 
+ * can be set on the <code><a
+ * href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
+ * tag in your application's AndroidManifest.xml file.
+ *
  * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
  * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
  * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
@@ -103,6 +100,8 @@
      * This method requires that the application hold the "android.permission.BACKUP"
      * permission if the package named in the argument does not run under the same uid
      * as the caller.
+     *
+     * @param packageName The package name identifying the application to back up.
      */
     public static void dataChanged(String packageName) {
         checkServiceBinder();
@@ -128,6 +127,9 @@
      * {@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) onRestore()}
      * method.
      *
+     * @param observer The {@link RestoreObserver} to receive callbacks during the restore
+     * operation. This must not be null.
+     *
      * @return Zero on success; nonzero on error.
      */
     public int requestRestore(RestoreObserver observer) {
diff --git a/core/java/android/app/backup/FileBackupHelper.java b/core/java/android/app/backup/FileBackupHelper.java
index a326941..c6a523a 100644
--- a/core/java/android/app/backup/FileBackupHelper.java
+++ b/core/java/android/app/backup/FileBackupHelper.java
@@ -23,16 +23,17 @@
 import java.io.File;
 
 /**
- * A helper class which can be used in conjunction with
+ * A helper class that 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,
- * 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.
+ * will be saved in their entirety. When backup first occurs,
+ * every file in the list provided to {@link #FileBackupHelper} will be backed up.
  * <p>
  * 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.
+ * <p class="note"><strong>Note:</strong> This should be
+ * used only with small configuration files, not large binary files.
  */
 public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
     private static final String TAG = "FileBackupHelper";
diff --git a/core/java/android/app/backup/SharedPreferencesBackupHelper.java b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
index 9efecc5..23b1703 100644
--- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
@@ -24,18 +24,18 @@
 import java.io.File;
 
 /**
- * A helper class which can be used in conjunction with
+ * A helper class that can be used in conjunction with
  * {@link android.app.backup.BackupAgentHelper} to manage the backup of
- * {@link android.content.SharedPreferences}. Whenever a backup is performed it
- * will back up all named shared preferences which have changed since the last
+ * {@link android.content.SharedPreferences}. Whenever a backup is performed, it
+ * will back up all named shared preferences that have changed since the last
  * backup operation.
  * <p>
- * To use this class, the application's agent class should extend
+ * To use this class, the application's backup 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}
+ * framework.  For example, an agent supporting backup and restore for
+ * an application with two groups of {@link android.content.SharedPreferences}
  * data might look something like this:
  * <pre>
  * import android.app.backup.BackupAgentHelper;
@@ -59,12 +59,12 @@
  *     }
  * }</pre>
  * <p>
- * No further implementation is needed; the BackupAgentHelper mechanism automatically
+ * No further implementation is needed; the {@link 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.  
+ * callbacks to the SharedPreferencesBackupHelper as appropriate.
  */
 public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
     private static final String TAG = "SharedPreferencesBackupHelper";
@@ -77,8 +77,9 @@
      * Construct a helper for backing up and restoring the
      * {@link android.content.SharedPreferences} under the given names.
      *
-     * @param context
-     * @param prefGroups
+     * @param context The application {@link android.content.Context}
+     * @param prefGroups The names of each {@link android.content.SharedPreferences} file to
+     * back up
      */
     public SharedPreferencesBackupHelper(Context context, String... prefGroups) {
         super(context);
@@ -88,7 +89,7 @@
     }
 
     /**
-     * Backs up the configured SharedPreferences groups
+     * Backs up the configured {@link android.content.SharedPreferences} groups.
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) {
diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html
index 2a5b628..e2518ec 100644
--- a/core/java/android/app/backup/package.html
+++ b/core/java/android/app/backup/package.html
@@ -1,7 +1,9 @@
 <HTML>
 <BODY>
-<p>Package containing the backup and restore functionality available to
-applications. All backup management is controlled through
+<p>Contains the backup and restore functionality available to
+applications. If a user wipes the data on their device or upgrades to a new Android-powered
+device, all applications that have enabled backup will restore the user's previous data and/or
+preferences. {@more} All backup management is controlled through
 {@link android.app.backup.BackupManager}.  Individual backup functionality is
 implemented through a subclass {@link android.app.backup.BackupAgent} and a
 simple and easy-to-use implementation is provided in
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 456ceb6..88adabd 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -231,8 +231,14 @@
     /**
      * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
      */
-    @SuppressWarnings({"UnusedDeclaration"})
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+        AppWidgetHostView v;
+        synchronized (mViews) {
+            v = mViews.get(appWidgetId);
+        }
+        if (v != null) {
+            v.updateAppWidget(null, AppWidgetHostView.UPDATE_FLAGS_RESET);
+        }
     }
 
     void updateAppWidgetView(int appWidgetId, RemoteViews views) {
@@ -241,7 +247,7 @@
             v = mViews.get(appWidgetId);
         }
         if (v != null) {
-            v.updateAppWidget(views);
+            v.updateAppWidget(views, 0);
         }
     }
 }
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 792b289..5375193 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -46,6 +46,8 @@
     static final boolean LOGD = false;
     static final boolean CROSSFADE = false;
 
+    static final int UPDATE_FLAGS_RESET = 0x00000001;
+
     static final int VIEW_MODE_NOINIT = 0;
     static final int VIEW_MODE_CONTENT = 1;
     static final int VIEW_MODE_ERROR = 2;
@@ -150,7 +152,16 @@
      * AppWidget provider. Will animate into these new views as needed
      */
     public void updateAppWidget(RemoteViews remoteViews) {
-        if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
+        updateAppWidget(remoteViews, 0);
+    }
+
+    void updateAppWidget(RemoteViews remoteViews, int flags) {
+        if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld + " flags=0x"
+                + Integer.toHexString(flags));
+
+        if ((flags & UPDATE_FLAGS_RESET) != 0) {
+            mViewMode = VIEW_MODE_NOINIT;
+        }
         
         boolean recycled = false;
         View content = null;
@@ -323,6 +334,9 @@
      * Inflate and return the default layout requested by AppWidget provider.
      */
     protected View getDefaultView() {
+        if (LOGD) {
+            Log.d(TAG, "getDefaultView");
+        }
         View defaultView = null;
         Exception exception = null;
         
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 1543b62..9b58205 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -16,10 +16,12 @@
 
 package com.android.internal.view.menu;
 
-import com.android.internal.view.menu.MenuView.ItemView;
+import java.lang.ref.WeakReference;
 
+import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.SubMenu;
@@ -28,12 +30,14 @@
 import android.view.ViewGroup;
 import android.view.ContextMenu.ContextMenuInfo;
 
-import java.lang.ref.WeakReference;
+import com.android.internal.view.menu.MenuView.ItemView;
 
 /**
  * @hide
  */
 public final class MenuItemImpl implements MenuItem {
+    private static final String TAG = "MenuItemImpl";
+    
     private final int mId;
     private final int mGroup;
     private final int mCategoryOrder;
@@ -147,8 +151,12 @@
         }
         
         if (mIntent != null) {
-            mMenu.getContext().startActivity(mIntent);
-            return true;
+            try {
+                mMenu.getContext().startActivity(mIntent);
+                return true;
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "Can't find activity to handle intent; ignoring", e);
+            }
         }
         
         return false;
diff --git a/core/res/res/layout-land/icon_menu_layout.xml b/core/res/res/layout-land/icon_menu_layout.xml
index 58f7bfb..70e3e83 100644
--- a/core/res/res/layout-land/icon_menu_layout.xml
+++ b/core/res/res/layout-land/icon_menu_layout.xml
@@ -18,7 +18,7 @@
     android:id="@+android:id/icon_menu" 
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:rowHeight="65dip"
+    android:rowHeight="66dip"
     android:maxItems="6"
     android:maxRows="2"
     android:maxItemsPerRow="6" />
diff --git a/core/res/res/layout-port/icon_menu_layout.xml b/core/res/res/layout-port/icon_menu_layout.xml
index c84f7d2..82082da 100644
--- a/core/res/res/layout-port/icon_menu_layout.xml
+++ b/core/res/res/layout-port/icon_menu_layout.xml
@@ -18,7 +18,7 @@
     android:id="@+android:id/icon_menu" 
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:rowHeight="65dip"
+    android:rowHeight="66dip"
     android:maxItems="6"
     android:maxRows="3"
     android:maxItemsPerRow="3" />
diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
index 6cd2199..05f61be 100644
--- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -600,7 +600,7 @@
   Every application must have at least one entry point &mdash; a way
   for the user or system to access activities inside the
   application. Each icon in the application launcher at home
-  represents an entry point. Applications can also from another
+  represents an entry point. Applications can also be launched from another
   application. Each activity is a potential entry point into the
   application.&nbsp;
 </p>
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 3f8bc51..4edfb88 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -36,6 +36,7 @@
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
+extern const char *MEDIA_MIMETYPE_CONTAINER_VORBIS;
 
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a6d8d2c..3e1f4a5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -678,6 +678,26 @@
     return PV_PLAYER;
 }
 
+// By default we use the VORBIS_PLAYER for vorbis playback (duh!),
+// but if the magic property is set we will use our new experimental
+// stagefright code instead.
+static player_type OverrideStagefrightForVorbis(player_type player) {
+    if (player != VORBIS_PLAYER) {
+        return player;
+    }
+
+#if BUILD_WITH_FULL_STAGEFRIGHT
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.enable-vorbis", value, NULL)
+        && (!strcmp(value, "1") || !strcmp(value, "true"))) {
+        return STAGEFRIGHT_PLAYER;
+    }
+#endif
+
+    return VORBIS_PLAYER;
+}
+
+
 player_type getPlayerType(int fd, int64_t offset, int64_t length)
 {
     char buf[20];
@@ -689,7 +709,7 @@
 
     // Ogg vorbis?
     if (ident == 0x5367674f) // 'OggS'
-        return VORBIS_PLAYER;
+        return OverrideStagefrightForVorbis(VORBIS_PLAYER);
 
 #ifndef NO_OPENCORE
     if (ident == 0x75b22630) {
@@ -725,6 +745,13 @@
         return TEST_PLAYER;
     }
 
+    bool useStagefrightForHTTP = false;
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.enable-http", value, NULL)
+        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        useStagefrightForHTTP = true;
+    }
+
     // use MidiFile for MIDI extensions
     int lenURL = strlen(url);
     for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
@@ -732,17 +759,18 @@
         int start = lenURL - len;
         if (start > 0) {
             if (!strncmp(url + start, FILE_EXTS[i].extension, len)) {
-                return FILE_EXTS[i].playertype;
+                if (FILE_EXTS[i].playertype == VORBIS_PLAYER
+                    && !strncasecmp(url, "http://", 7)
+                    && useStagefrightForHTTP) {
+                    return STAGEFRIGHT_PLAYER;
+                }
+                return OverrideStagefrightForVorbis(FILE_EXTS[i].playertype);
             }
         }
     }
 
     if (!strncasecmp(url, "http://", 7)) {
-        char value[PROPERTY_VALUE_MAX];
-        if (!property_get("media.stagefright.enable-http", value, NULL)
-            || (strcmp(value, "1") && strcasecmp(value, "true"))) {
-            // For now, we're going to use PV for http-based playback
-            // by default until we can clear up a few more issues.
+        if (!useStagefrightForHTTP) {
             return PV_PLAYER;
         }
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2a65766..8191cc7 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -39,6 +39,7 @@
         StagefrightMetadataRetriever.cpp \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
+        VorbisExtractor.cpp       \
         WAVExtractor.cpp          \
         string.cpp
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 86e4bfe..5db3201 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -18,6 +18,7 @@
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
+#include "include/VorbisExtractor.h"
 
 #include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/DataSource.h>
@@ -92,6 +93,7 @@
     RegisterSniffer(SniffMPEG4);
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffWAV);
+    RegisterSniffer(SniffVorbis);
 }
 
 // static
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 3a89170..db18ab6 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -34,5 +34,6 @@
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
+const char *MEDIA_MIMETYPE_CONTAINER_VORBIS = "application/ogg";
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 738e18a..832db04 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -22,6 +22,7 @@
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
+#include "include/VorbisExtractor.h"
 
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
@@ -62,6 +63,8 @@
         return new AMRExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
         return new WAVExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_VORBIS)) {
+        return new VorbisExtractor(source);
     }
 
     return NULL;
diff --git a/media/libstagefright/VorbisExtractor.cpp b/media/libstagefright/VorbisExtractor.cpp
new file mode 100644
index 0000000..96b05c0
--- /dev/null
+++ b/media/libstagefright/VorbisExtractor.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VorbisExtractor"
+#include <utils/Log.h>
+
+#include "include/VorbisExtractor.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+#include <ivorbisfile.h>
+
+namespace android {
+
+struct VorbisDataSource {
+    sp<DataSource> mDataSource;
+    off_t mOffset;
+};
+
+static size_t VorbisRead(
+        void *ptr, size_t size, size_t nmemb, void *datasource) {
+    VorbisDataSource *vds = (VorbisDataSource *)datasource;
+
+    ssize_t n = vds->mDataSource->readAt(vds->mOffset, ptr, size * nmemb);
+
+    if (n < 0) {
+        return n;
+    }
+
+    vds->mOffset += n;
+
+    return n / size;
+}
+
+static int VorbisSeek(
+        void *datasource, ogg_int64_t offset, int whence) {
+    VorbisDataSource *vds = (VorbisDataSource *)datasource;
+
+    switch (whence) {
+        case SEEK_SET:
+            vds->mOffset = offset;
+            break;
+        case SEEK_END:
+        {
+            off_t size;
+            if (vds->mDataSource->getSize(&size) != OK) {
+                errno = ESPIPE;
+                return -1;
+            }
+
+            vds->mOffset = offset + size;
+            break;
+        }
+
+        case SEEK_CUR:
+        {
+            vds->mOffset += offset;
+            break;
+        }
+
+        default:
+        {
+            errno = EINVAL;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int VorbisClose(void *datasource) {
+    return 0;
+}
+
+static long VorbisTell(void *datasource) {
+    VorbisDataSource *vds = (VorbisDataSource *)datasource;
+
+    return vds->mOffset;
+}
+
+static const ov_callbacks gVorbisCallbacks = {
+    &VorbisRead,
+    &VorbisSeek,
+    &VorbisClose,
+    &VorbisTell
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct VorbisSource : public MediaSource {
+    VorbisSource(const sp<VorbisExtractor> &extractor,
+                 const sp<MetaData> &meta, OggVorbis_File *file);
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~VorbisSource();
+
+private:
+    enum {
+        kMaxBufferSize = 8192
+    };
+
+    sp<VorbisExtractor> mExtractor;
+    sp<MetaData> mMeta;
+    OggVorbis_File *mFile;
+    MediaBufferGroup *mGroup;
+
+    VorbisSource(const VorbisSource &);
+    VorbisSource &operator=(const VorbisSource &);
+};
+
+VorbisSource::VorbisSource(
+        const sp<VorbisExtractor> &extractor,
+        const sp<MetaData> &meta, OggVorbis_File *file)
+    : mExtractor(extractor),
+      mMeta(meta),
+      mFile(file),
+      mGroup(NULL) {
+}
+
+VorbisSource::~VorbisSource() {
+    if (mGroup) {
+        stop();
+    }
+}
+
+sp<MetaData> VorbisSource::getFormat() {
+    return mMeta;
+}
+
+status_t VorbisSource::start(MetaData *params) {
+    if (mGroup != NULL) {
+        return INVALID_OPERATION;
+    }
+
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(kMaxBufferSize));
+
+    return OK;
+}
+
+status_t VorbisSource::stop() {
+    delete mGroup;
+    mGroup = NULL;
+
+    return OK;
+}
+
+status_t VorbisSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    if (options && options->getSeekTo(&seekTimeUs)) {
+        ov_time_seek(mFile, seekTimeUs / 1000ll);
+    }
+
+    MediaBuffer *buffer;
+    CHECK_EQ(OK, mGroup->acquire_buffer(&buffer));
+
+    ogg_int64_t positionMs = ov_time_tell(mFile);
+
+    int bitstream;
+    long n = ov_read(mFile, buffer->data(), buffer->size(), &bitstream);
+
+    if (n <= 0) {
+        LOGE("ov_read returned %ld", n);
+
+        buffer->release();
+        buffer = NULL;
+
+        return n < 0 ? ERROR_MALFORMED : ERROR_END_OF_STREAM;
+    }
+
+    buffer->set_range(0, n);
+    buffer->meta_data()->setInt64(kKeyTime, positionMs * 1000ll);
+
+    *out = buffer;
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+VorbisExtractor::VorbisExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mFile(new OggVorbis_File),
+      mVorbisDataSource(new VorbisDataSource),
+      mInitCheck(NO_INIT) {
+    mVorbisDataSource->mDataSource = mDataSource;
+    mVorbisDataSource->mOffset = 0;
+
+    int res = ov_open_callbacks(
+            mVorbisDataSource, mFile, NULL, 0, gVorbisCallbacks);
+
+    if (res != 0) {
+        return;
+    }
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+
+    vorbis_info *vi = ov_info(mFile, -1);
+    mMeta->setInt32(kKeySampleRate, vi->rate);
+    mMeta->setInt32(kKeyChannelCount, vi->channels);
+
+    ogg_int64_t durationMs = ov_time_total(mFile, -1);
+    mMeta->setInt64(kKeyDuration, durationMs * 1000ll);
+
+    LOGI("Successfully initialized.");
+
+    mInitCheck = OK;
+}
+
+VorbisExtractor::~VorbisExtractor() {
+    CHECK_EQ(0, ov_clear(mFile));
+
+    delete mVorbisDataSource;
+    mVorbisDataSource = NULL;
+
+    delete mFile;
+    mFile = NULL;
+}
+
+size_t VorbisExtractor::countTracks() {
+    return mInitCheck != OK ? 0 : 1;
+}
+
+sp<MediaSource> VorbisExtractor::getTrack(size_t index) {
+    if (index >= 1) {
+        return NULL;
+    }
+
+    return new VorbisSource(this, mMeta, mFile);
+}
+
+sp<MetaData> VorbisExtractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
+    if (index >= 1) {
+        return NULL;
+    }
+
+    return mMeta;
+}
+
+sp<MetaData> VorbisExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+
+    if (mInitCheck != OK) {
+        return meta;
+    }
+
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_VORBIS);
+
+    return meta;
+}
+
+bool SniffVorbis(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+    OggVorbis_File file;
+
+    VorbisDataSource vds;
+    vds.mDataSource = source;
+    vds.mOffset = 0;
+
+    int res = ov_test_callbacks(&vds, &file, NULL, 0, gVorbisCallbacks);
+
+    CHECK_EQ(0, ov_clear(&file));
+
+    if (res != 0) {
+        return false;
+    }
+
+    *mimeType = MEDIA_MIMETYPE_CONTAINER_VORBIS;
+    *confidence = 0.4f;
+
+    LOGV("This looks like an Ogg file.");
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/include/VorbisExtractor.h b/media/libstagefright/include/VorbisExtractor.h
new file mode 100644
index 0000000..8e38a93
--- /dev/null
+++ b/media/libstagefright/include/VorbisExtractor.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef VORBIS_EXTRACTOR_H_
+
+#define VORBIS_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+struct OggVorbis_File;
+
+namespace android {
+
+class DataSource;
+class String8;
+
+struct VorbisDataSource;
+
+struct VorbisExtractor : public MediaExtractor {
+    VorbisExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+protected:
+    virtual ~VorbisExtractor();
+
+private:
+    sp<DataSource> mDataSource;
+    struct OggVorbis_File *mFile;
+    struct VorbisDataSource *mVorbisDataSource;
+    status_t mInitCheck;
+    sp<MetaData> mMeta;
+
+    VorbisExtractor(const VorbisExtractor &);
+    VorbisExtractor &operator=(const VorbisExtractor &);
+};
+
+bool SniffVorbis(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // VORBIS_EXTRACTOR_H_
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 735a80d..1e8b395 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -523,10 +523,48 @@
             bool actWidgetReceivers = false;
             bool actImeService = false;
             bool actWallpaperService = false;
-            bool specCameraFeature = false;
+
+            // This next group of variables is used to implement a group of
+            // backward-compatibility heuristics necessitated by the addition of
+            // some new uses-feature constants in 2.1 and 2.2. In most cases, the
+            // heuristic is "if an app requests a permission but doesn't explicitly
+            // request the corresponding <uses-feature>, presume it's there anyway".
+            bool specCameraFeature = false; // camera-related
+            bool specCameraAutofocusFeature = false;
+            bool reqCameraAutofocusFeature = false;
+            bool reqCameraFlashFeature = false;
             bool hasCameraPermission = false;
+            bool specLocationFeature = false; // location-related
+            bool specNetworkLocFeature = false;
+            bool reqNetworkLocFeature = false;
             bool specGpsFeature = false;
+            bool reqGpsFeature = false;
+            bool hasMockLocPermission = false;
+            bool hasCoarseLocPermission = false;
             bool hasGpsPermission = false;
+            bool hasGeneralLocPermission = false;
+            bool specBluetoothFeature = false; // Bluetooth API-related
+            bool hasBluetoothPermission = false;
+            bool specMicrophoneFeature = false; // microphone-related
+            bool hasRecordAudioPermission = false;
+            bool specWiFiFeature = false;
+            bool hasWiFiPermission = false;
+            bool specTelephonyFeature = false; // telephony-related
+            bool reqTelephonySubFeature = false;
+            bool hasTelephonyPermission = false;
+            bool specTouchscreenFeature = false; // touchscreen-related
+            bool specMultitouchFeature = false;
+            bool reqDistinctMultitouchFeature = false;
+            // 2.2 also added some other features that apps can request, but that
+            // have no corresponding permission, so we cannot implement any
+            // back-compatibility heuristic for them. The below are thus unnecessary
+            // (but are retained here for documentary purposes.)
+            //bool specCompassFeature = false;
+            //bool specAccelerometerFeature = false;
+            //bool specProximityFeature = false;
+            //bool specAmbientLightFeature = false;
+            //bool specLiveWallpaperFeature = false;
+
             int targetSdk = 0;
             int smallScreen = 1;
             int normalScreen = 1;
@@ -719,10 +757,45 @@
                         if (name != "" && error == "") {
                             int req = getIntegerAttribute(tree,
                                     REQUIRED_ATTR, NULL, 1);
+
                             if (name == "android.hardware.camera") {
                                 specCameraFeature = true;
+                            } else if (name == "android.hardware.camera.autofocus") {
+                                // these have no corresponding permission to check for,
+                                // but should imply the foundational camera permission
+                                reqCameraAutofocusFeature = reqCameraAutofocusFeature || req;
+                                specCameraAutofocusFeature = true;
+                            } else if (req && (name == "android.hardware.camera.flash")) {
+                                // these have no corresponding permission to check for,
+                                // but should imply the foundational camera permission
+                                reqCameraFlashFeature = true;
+                            } else if (name == "android.hardware.location") {
+                                specLocationFeature = true;
+                            } else if (name == "android.hardware.location.network") {
+                                specNetworkLocFeature = true;
+                                reqNetworkLocFeature = reqNetworkLocFeature || req;
                             } else if (name == "android.hardware.location.gps") {
                                 specGpsFeature = true;
+                                reqGpsFeature = reqGpsFeature || req;
+                            } else if (name == "android.hardware.bluetooth") {
+                                specBluetoothFeature = true;
+                            } else if (name == "android.hardware.touchscreen") {
+                                specTouchscreenFeature = true;
+                            } else if (name == "android.hardware.touchscreen.multitouch") {
+                                specMultitouchFeature = true;
+                            } else if (name == "android.hardware.touchscreen.multitouch.distinct") {
+                                reqDistinctMultitouchFeature = reqDistinctMultitouchFeature || req;
+                            } else if (name == "android.hardware.microphone") {
+                                specMicrophoneFeature = true;
+                            } else if (name == "android.hardware.wifi") {
+                                specWiFiFeature = true;
+                            } else if (name == "android.hardware.telephony") {
+                                specTelephonyFeature = true;
+                            } else if (req && (name == "android.hardware.telephony.gsm" ||
+                                               name == "android.hardware.telephony.cdma")) {
+                                // these have no corresponding permission to check for,
+                                // but should imply the foundational telephony permission
+                                reqTelephonySubFeature = true;
                             }
                             printf("uses-feature%s:'%s'\n",
                                     req ? "" : "-not-required", name.string());
@@ -740,6 +813,34 @@
                                 hasCameraPermission = true;
                             } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
                                 hasGpsPermission = true;
+                            } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
+                                hasMockLocPermission = true;
+                            } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
+                                hasCoarseLocPermission = true;
+                            } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+                                       name == "android.permission.INSTALL_LOCATION_PROVIDER") {
+                                hasGeneralLocPermission = true;
+                            } else if (name == "android.permission.BLUETOOTH" ||
+                                       name == "android.permission.BLUETOOTH_ADMIN") {
+                                hasBluetoothPermission = true;
+                            } else if (name == "android.permission.RECORD_AUDIO") {
+                                hasRecordAudioPermission = true;
+                            } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
+                                       name == "android.permission.CHANGE_WIFI_STATE" ||
+                                       name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
+                                hasWiFiPermission = true;
+                            } else if (name == "android.permission.CALL_PHONE" ||
+                                       name == "android.permission.CALL_PRIVILEGED" ||
+                                       name == "android.permission.MODIFY_PHONE_STATE" ||
+                                       name == "android.permission.PROCESS_OUTGOING_CALLS" ||
+                                       name == "android.permission.READ_SMS" ||
+                                       name == "android.permission.RECEIVE_SMS" ||
+                                       name == "android.permission.RECEIVE_MMS" ||
+                                       name == "android.permission.RECEIVE_WAP_PUSH" ||
+                                       name == "android.permission.SEND_SMS" ||
+                                       name == "android.permission.WRITE_APN_SETTINGS" ||
+                                       name == "android.permission.WRITE_SMS") {
+                                hasTelephonyPermission = true;
                             }
                             printf("uses-permission:'%s'\n", name.string());
                         } else {
@@ -856,22 +957,89 @@
                 }
             }
 
-            if (!specCameraFeature && hasCameraPermission) {
-                // For applications that have not explicitly stated their
-                // camera feature requirements, but have requested the camera
-                // permission, we are going to give them compatibility treatment
-                // of requiring the equivalent to original android devices.
-                printf("uses-feature:'android.hardware.camera'\n");
-                printf("uses-feature:'android.hardware.camera.autofocus'\n");
+            /* The following blocks handle printing "inferred" uses-features, based
+             * on whether related features or permissions are used by the app.
+             * Note that the various spec*Feature variables denote whether the
+             * relevant tag was *present* in the AndroidManfest, not that it was
+             * present and set to true.
+             */
+            // Camera-related back-compatibility logic
+            if (!specCameraFeature) {
+                if (reqCameraFlashFeature || reqCameraAutofocusFeature) {
+                    // if app requested a sub-feature (autofocus or flash) and didn't
+                    // request the base camera feature, we infer that it meant to
+                    printf("uses-feature:'android.hardware.camera'\n");
+                } else if (hasCameraPermission) {
+                    // if app wants to use camera but didn't request the feature, we infer 
+                    // that it meant to, and further that it wants autofocus
+                    // (which was the 1.0 - 1.5 behavior)
+                    printf("uses-feature:'android.hardware.camera'\n");
+                    if (!specCameraAutofocusFeature) {
+                        printf("uses-feature:'android.hardware.camera.autofocus'\n");
+                    }
+                }
             }
 
+            // Location-related back-compatibility logic
+            if (!specLocationFeature &&
+                (hasMockLocPermission || hasCoarseLocPermission || hasGpsPermission ||
+                 hasGeneralLocPermission || reqNetworkLocFeature || reqGpsFeature)) {
+                // if app either takes a location-related permission or requests one of the
+                // sub-features, we infer that it also meant to request the base location feature
+                printf("uses-feature:'android.hardware.location'\n");
+            }
             if (!specGpsFeature && hasGpsPermission) {
-                // For applications that have not explicitly stated their
-                // GPS feature requirements, but have requested the "fine" (GPS)
-                // permission, we are going to give them compatibility treatment
-                // of requiring the equivalent to original android devices.
+                // if app takes GPS (FINE location) perm but does not request the GPS
+                // feature, we infer that it meant to
                 printf("uses-feature:'android.hardware.location.gps'\n");
             }
+            if (!specNetworkLocFeature && hasCoarseLocPermission) {
+                // if app takes Network location (COARSE location) perm but does not request the
+                // network location feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.location.network'\n");
+            }
+
+            // Bluetooth-related compatibility logic
+            if (!specBluetoothFeature && hasBluetoothPermission) {
+                // if app takes a Bluetooth permission but does not request the Bluetooth
+                // feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.bluetooth'\n");
+            }
+
+            // Microphone-related compatibility logic
+            if (!specMicrophoneFeature && hasRecordAudioPermission) {
+                // if app takes the record-audio permission but does not request the microphone
+                // feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.microphone'\n");
+            }
+
+            // WiFi-related compatibility logic
+            if (!specWiFiFeature && hasWiFiPermission) {
+                // if app takes one of the WiFi permissions but does not request the WiFi
+                // feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.wifi'\n");
+            }
+
+            // Telephony-related compatibility logic
+            if (!specTelephonyFeature && (hasTelephonyPermission || reqTelephonySubFeature)) {
+                // if app takes one of the telephony permissions or requests a sub-feature but
+                // does not request the base telephony feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.telephony'\n");
+            }
+
+            // Touchscreen-related back-compatibility logic
+            if (!specTouchscreenFeature) { // not a typo!
+                // all apps are presumed to require a touchscreen, unless they explicitly say
+                // <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
+                // Note that specTouchscreenFeature is true if the tag is present, regardless
+                // of whether its value is true or false, so this is safe
+                printf("uses-feature:'android.hardware.touchscreen'\n");
+            }
+            if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
+                // if app takes one of the telephony permissions or requests a sub-feature but
+                // does not request the base telephony feature, we infer that it meant to
+                printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
+            }
 
             if (hasMainActivity) {
                 printf("main\n");