Merge "Fix Throttle Notification intents" into froyo
diff --git a/api/current.xml b/api/current.xml
index a2063b5..8cffff1b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -27062,19 +27062,6 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<method name="setKeyPrefix"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="keyPrefix" type="java.lang.String">
-</parameter>
-</method>
 <method name="writeEntityData"
  return="int"
  abstract="false"
@@ -27109,28 +27096,6 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
-<field name="OP_DELETE"
- type="int"
- transient="false"
- volatile="false"
- value="2"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="OP_UPDATE"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 </class>
 <interface name="BackupHelper"
  abstract="true"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 52f767e..34648b5 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -5,7 +5,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
-	stagefright.cpp
+	stagefright.cpp \
+	SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libutils libbinder
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index fec9e1a..4405da6 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -20,9 +20,12 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "SineSource.h"
+
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <media/IMediaPlayerService.h>
+#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/HTTPDataSource.h>
@@ -42,6 +45,7 @@
 static long gMaxNumFrames;  // 0 means decode all available.
 static long gReproduceBug;  // if not -1.
 static bool gPreferSoftwareCodec;
+static bool gPlaybackAudio;
 
 static int64_t getNowUs() {
     struct timeval tv;
@@ -73,7 +77,20 @@
 
     rawSource->start();
 
-    if (gReproduceBug >= 3 && gReproduceBug <= 5) {
+    if (gPlaybackAudio) {
+        AudioPlayer *player = new AudioPlayer(NULL);
+        player->setSource(rawSource);
+
+        player->start(true /* sourceAlreadyStarted */);
+
+        status_t finalStatus;
+        while (!player->reachedEOS(&finalStatus)) {
+            usleep(100000ll);
+        }
+
+        delete player;
+        player = NULL;
+    } else if (gReproduceBug >= 3 && gReproduceBug <= 5) {
         int64_t durationUs;
         CHECK(meta->findInt64(kKeyDuration, &durationUs));
 
@@ -245,6 +262,7 @@
     fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
     fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
     fprintf(stderr, "       -s(oftware) prefer software codec\n");
+    fprintf(stderr, "       -o playback audio\n");
 }
 
 int main(int argc, char **argv) {
@@ -258,9 +276,10 @@
     gMaxNumFrames = 0;
     gReproduceBug = -1;
     gPreferSoftwareCodec = false;
+    gPlaybackAudio = false;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:pts")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:ptso")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -314,6 +333,12 @@
                 break;
             }
 
+            case 'o':
+            {
+                gPlaybackAudio = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -325,6 +350,11 @@
         }
     }
 
+    if (gPlaybackAudio && !audioOnly) {
+        // This doesn't make any sense if we're decoding the video track.
+        gPlaybackAudio = false;
+    }
+
     argc -= optind;
     argv += optind;
 
@@ -456,6 +486,11 @@
             dataSource = new FileSource(filename);
         }
 
+        if (dataSource == NULL) {
+            fprintf(stderr, "Unable to create data source.\n");
+            return 1;
+        }
+
         bool isJPEG = false;
 
         size_t len = strlen(filename);
@@ -467,10 +502,18 @@
 
         if (isJPEG) {
             mediaSource = new JPEGSource(dataSource);
+        } else if (!strncasecmp("sine:", filename, 5)) {
+            char *end;
+            long sampleRate = strtol(filename + 5, &end, 10);
+
+            if (end == filename + 5) {
+                sampleRate = 44100;
+            }
+            mediaSource = new SineSource(sampleRate, 1);
         } else {
             sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
             if (extractor == NULL) {
-                fprintf(stderr, "could not create data source\n");
+                fprintf(stderr, "could not create extractor.\n");
                 return -1;
             }
 
@@ -492,6 +535,17 @@
                 if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
                     break;
                 }
+
+                meta = NULL;
+            }
+
+            if (meta == NULL) {
+                fprintf(stderr,
+                        "No suitable %s track found. The '-a' option will "
+                        "target audio tracks only, the default is to target "
+                        "video tracks only.\n",
+                        audioOnly ? "audio" : "video");
+                return -1;
             }
 
             int64_t thumbTimeUs;
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index f9dcab8..0bb2cb5 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -29,18 +29,57 @@
 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 &lt;application&gt; tag's android:backupAgent attribute.
  * <p>
- * A backup agent based on convenient helper classes is available in
- * {@link android.app.backup.BackupAgentHelper} for less complex implementation
- * requirements.
+ * <b>Basic Operation</b>
  * <p>
- * 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.
+ * <p>
+ * 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.
+ * <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
+ * 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
+ * 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.
+ * <p>
+ * <b>Helper Classes</b>
+ * <p>
+ * 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 @@
         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.
+     * <p>
+     * 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.
+     * <p>
+     * Agents do not need to override this method.
+     */
     public void onDestroy() {
     }
 
@@ -65,18 +117,26 @@
      * 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
      * <code>newState</code>.
+     * <p>
+     * Each entity written to the {@link android.app.backup.BackupDataOutput}
+     * <code>data</code> 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
      *            <code>null</code>, 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 <code>data</code>
+     *            output stream.
      */
     public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
              ParcelFileDescriptor newState) throws IOException;
@@ -84,8 +144,7 @@
     /**
      * 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 <code>data</code>. Once
+     * provided through the <code>data</code> parameter. Once
      * the restore is finished, the application should write a representation of
      * the final state to the <code>newState</code> file descriptor.
      * <p>
@@ -98,17 +157,18 @@
      * 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 <code>data</code> 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 7b6be23..6d73090 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.
@@ -21,15 +21,30 @@
 import java.io.IOException;
 
 /**
- * A convenient BackupAgent wrapper class that automatically manages
+ * A convenient {@link BackupAgent} wrapper class that automatically manages
  * heterogeneous data sets within the backup data, each identified by a unique
- * key prefix. An application will typically extend this class in their own
- * backup agent. Then, within the agent's onBackup() and onRestore() methods, it
- * will call {@link #addHelper(String, BackupHelper)} one or more times to
- * specify the data sets, then invoke super.onBackup() or super.onRestore() to
- * have the BackupAgentHelper implementation process the data.
+ * key prefix.  When processing a backup or restore operation, the BackupAgentHelper
+ * dispatches to one or more installed {@link BackupHelper helpers} objects, each
+ * of which is responsible for a defined subset of the data being processed.
  * <p>
- * STOPSHIP: document!
+ * An application will typically extend this class in their 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
+ * 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.
+ * <p>
+ * An application can also implement its own helper classes to work within the
+ * {@link BackupAgentHelper} framework.  See the {@link BackupHelper} interface
+ * documentation for details.
+ *
+ * @see BackupHelper
+ * @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 2da0c11..976e0c9 100644
--- a/core/java/android/app/backup/BackupDataInput.java
+++ b/core/java/android/app/backup/BackupDataInput.java
@@ -20,7 +20,41 @@
 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.
+ * <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>
+ * <p>
+ * A typical
+ * {@link BackupAgent#onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor) BackupAgent.onRestore(data, appVersionCode, newState)}
+ * implementation might be structured something like this:
+ * <pre>
+ * 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.
+ * }</pre>
  */
 public class BackupDataInput {
     int mBackupReader;
@@ -52,10 +86,12 @@
     }
 
     /**
-     * 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 <code>true</code> when there is an entity ready for consumption from the
+     *    restore stream, <code>false</code> 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 @@
         } 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 @@
         if (mHeaderReady) {
             return mHeader.dataSize;
         } else {
-            throw new IllegalStateException("mHeaderReady=false");
+            throw new IllegalStateException("Entity header not read");
         }
     }
 
@@ -107,13 +143,15 @@
      * 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 @@
                 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 @@
         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/BackupDataInputStream.java b/core/java/android/app/backup/BackupDataInputStream.java
index a7f4ba6..465b3b6 100644
--- a/core/java/android/app/backup/BackupDataInputStream.java
+++ b/core/java/android/app/backup/BackupDataInputStream.java
@@ -20,7 +20,21 @@
 import java.io.IOException;
 
 /**
- * STOPSHIP: document */
+ * 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.
+ * <p>
+ * When {@link BackupHelper#restoreEntity(BackupDataInputStream) BackupHelper.restoreEntity(BackupDataInputStream)}
+ * 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>
+ *
+ * @see BackupAgentHelper
+ * @see BackupHelper
+ */
 public class BackupDataInputStream extends InputStream {
 
     String key;
@@ -34,6 +48,13 @@
         mData = data;
     }
 
+    /**
+     * Read one byte of entity data from the stream, returning it as
+     * an integer value.  If more than {@link #size()} bytes of data
+     * are read from the stream, the output of this method is undefined.
+     *
+     * @return The byte read, or undefined if the end of the stream has been reached.
+     */
     public int read() throws IOException {
         byte[] one = mOneByte;
         if (mOneByte == null) {
@@ -43,18 +64,52 @@
         return one[0];
     }
 
+    /**
+     * Read up to {@code size} bytes of data into a byte array, beginning at position
+     * {@code offset} within the array.
+     *
+     * @param b Byte array into which the data will be read
+     * @param offset The data will be stored in {@code b} beginning at this index
+     *   within the array.
+     * @param size The number of bytes to read in this operation.  If insufficient
+     *   data exists within the entity to fulfill this request, only as much data
+     *   will be read as is available.
+     * @return The number of bytes of data read, or zero if all of the entity's
+     *   data has already been read.
+     */
     public int read(byte[] b, int offset, int size) throws IOException {
         return mData.readEntityData(b, offset, size);
     }
 
+    /**
+     * Read enough entity data into a byte array to fill the array.
+     *
+     * @param b Byte array to fill with data from the stream.  If the stream does not
+     *   have sufficient data to fill the array, then the contents of the remainder of
+     *   the array will be undefined.
+     * @return The number of bytes of data read, or zero if all of the entity's
+     *   data has already been read.
+     */
     public int read(byte[] b) throws IOException {
         return mData.readEntityData(b, 0, b.length);
     }
 
+    /**
+     * Report the key string associated with this entity within the backup data set.
+     *
+     * @return The key string for this entity, equivalent to calling
+     *   {@link BackupDataInput#getKey()} on the underlying {@link BackupDataInput}.
+     */
     public String getKey() {
         return this.key;
     }
-    
+
+    /**
+     * Report the total number of bytes of data available for the current entity.
+     *
+     * @return The number of data bytes available, equivalent to calling
+     *   {@link BackupDataInput#getDataSize()} on the underlying {@link BackupDataInput}.
+     */
     public int size() {
         return this.dataSize;
     }
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 53b1d46..a69547a 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -16,18 +16,53 @@
 
 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."
+ * <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
+ * 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)}.
+ * <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
+ * 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>
+ * <p>
+ * Here is an example illustrating a way to back up the value of a String variable
+ * called <code>mStringToBackUp</code>:
+ * <pre>
+ * 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);
+ *     ...
+ * }</pre>
+ *
+ * @see BackupAgent
  */
 public class BackupDataOutput {
     int mBackupWriter;
 
-    public static final int OP_UPDATE = 1;
-    public static final int OP_DELETE = 2;
-
     /** @hide */
     public BackupDataOutput(FileDescriptor fd) {
         if (fd == null) throw new NullPointerException();
@@ -71,6 +106,7 @@
         }
     }
 
+    /** @hide */
     public void setKeyPrefix(String keyPrefix) {
         setKeyPrefix_native(mBackupWriter, keyPrefix);
     }
diff --git a/core/java/android/app/backup/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java
index b7ef268..87b581b 100644
--- a/core/java/android/app/backup/BackupHelper.java
+++ b/core/java/android/app/backup/BackupHelper.java
@@ -19,11 +19,21 @@
 import android.os.ParcelFileDescriptor;
 
 /**
- * A convenient interface to be used with the
- * {@link android.app.backup.BackupAgentHelper} to implement backup and restore of
- * arbitrary data types.
+ * This interface 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.
  * <p>
- * STOPSHOP: document!
+ * Although multiple helper objects may be installed simultaneously, each helper
+ * is responsible only for handling its own data, and will not see entities
+ * created by other components within the backup system.  Invocations of multiple
+ * helpers are performed sequentially by the {@link BackupAgentHelper}, with each
+ * helper given a chance to access its own saved state from within the state record
+ * produced during the previous backup operation.
+ *
+ * @see BackupAgentHelper
+ * @see FileBackupHelper
+ * @see SharedPreferencesBackupHelper
  */
 public interface BackupHelper {
     /**
@@ -31,25 +41,46 @@
      * application's data directory need to be backed up, write them to
      * <code>data</code>, and fill in <code>newState</code> with the state as it
      * 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
+     * {@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
+     * the {@code newState} file descriptors.</p>
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState);
 
     /**
      * Called by {@link android.app.backup.BackupAgentHelper BackupAgentHelper}
-     * to restore one entity from the restore dataset.
-     * <p class=note>
-     * Do not close the <code>data</code> stream.  Do not read more than
-     * <code>data.size()</code> bytes from <code>data</code>.
+     * 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>
      */
     public void restoreEntity(BackupDataInputStream data);
 
     /**
      * 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.  The data written here will be
+     * available to the helper during the next call to its
+     * {@link #performBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
+     * method.
+     * <p>
+     * Note that this method will be called even if the handler's
+     * {@link #restoreEntity(BackupDataInputStream)} method was never invoked during
+     * the restore operation.
+     * <p class="note">
+     * <em>Note:</em> The helper should not close or seek the {@code newState}
+     * file descriptor.</p>
      */
-    public void writeNewStateDescription(ParcelFileDescriptor fd);
+    public void writeNewStateDescription(ParcelFileDescriptor newState);
 }
 
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 7eb6265..7070827 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;
 
 /**
- * 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.
  * <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,24 +35,23 @@
  * calls to {@link #dataChanged()} have no further effect until the backup
  * operation actually occurs.
  * <p>
- * 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.
- * <p>
- * A simple implementation of a BackupAgent useful for backing up Preferences
- * and files is available by using {@link android.app.backup.BackupAgentHelper}.
- * <p>
- * STOPSHIP: more documentation!
+ * of how the operation then proceeds.
  * <p>
  * <b>XML attributes</b>
  * <p>
- * 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 &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.
  * 
  * @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 @@
     /**
      * 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 @@
 
     /**
      * 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.
+     * <p>
      * 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 3ce5b43..a326941 100644
--- a/core/java/android/app/backup/FileBackupHelper.java
+++ b/core/java/android/app/backup/FileBackupHelper.java
@@ -26,18 +26,13 @@
  * 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.
  * <p>
- * 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.
- * <p>
- * 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 @@
      * now. When <code>oldState</code> is <code>null</code>, all the files will
      * be backed up.
      * <p>
-     * 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 @@
 
     /**
      * Restore one record [representing a single file] from the restore dataset.
+     * <p>
+     * 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 f9e6b28..9efecc5 100644
--- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
@@ -26,11 +26,45 @@
 /**
  * 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.
  * <p>
- * 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:
+ * <pre>
+ * 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);
+ *     }
+ * }</pre>
+ * <p>
+ * 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/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 08cd2f0..893db2e 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -487,12 +487,6 @@
         if (state != prevState) {
             if (state == BluetoothA2dp.STATE_DISCONNECTED ||
                     state == BluetoothA2dp.STATE_DISCONNECTING) {
-                if (prevState == BluetoothA2dp.STATE_CONNECTED ||
-                        prevState == BluetoothA2dp.STATE_PLAYING) {
-                   // disconnecting or disconnected
-                   Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
-                   mContext.sendBroadcast(intent);
-                }
                 mSinkCount--;
             } else if (state == BluetoothA2dp.STATE_CONNECTED) {
                 mSinkCount ++;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4f2a67b..06a7a6f4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2150,11 +2150,15 @@
                 mScrollX = pinLocX(Math.round(sx));
                 mScrollY = pinLocY(Math.round(sy));
 
+                // update webkit
                 if (oldX != mScrollX || oldY != mScrollY) {
                     onScrollChanged(mScrollX, mScrollY, oldX, oldY);
+                } else {
+                    // the scroll position is adjusted at the beginning of the
+                    // zoom animation. But we want to update the WebKit at the
+                    // end of the zoom animation. See comments in onScaleEnd().
+                    sendOurVisibleRect();
                 }
-
-                // update webkit
                 sendViewSizeZoom();
             }
         }
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 945d283..79ca617 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -164,6 +164,7 @@
         android:layout_marginBottom="80dip"
         style="@style/Widget.Button.Transparent"
         android:drawablePadding="8dip"
+        android:visibility="gone"
         />
 
 </RelativeLayout>
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 6b76004e..8353887 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -163,6 +163,7 @@
         style="@style/Widget.Button.Transparent"
         android:drawablePadding="8dip"
         android:layout_marginRight="80dip"
+        android:visibility="gone"
         />
 
 </LinearLayout>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 3585bf1..ed7447c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -584,8 +584,8 @@
     <!-- Application's requirement for five way navigation -->
     <attr name="reqFiveWayNav" format="boolean" />
 
-    <!-- The name of the class implementing <code>BackupAgent</code> to manage
-         backup and restore of application data on external storage. -->
+    <!-- The name of the class subclassing <code>BackupAgent</code> to manage
+         backup and restore of the application's data on external storage. -->
     <attr name="backupAgent" format="string" />
 
     <!-- Whether to allow the application to participate in backup
diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd
index 5b3fcd5..08f35e9 100644
--- a/docs/html/guide/topics/manifest/application-element.jd
+++ b/docs/html/guide/topics/manifest/application-element.jd
@@ -3,19 +3,23 @@
 
 <dl class="xml">
 <dt>syntax:</dt>
-<dd><pre class="stx">&lt;application android:<a href="#clear">allowClearUserData</a>=["true" | "false"]
+<dd><pre class="stx">&lt;application android:<a href="#backup">allowBackup</a>=["true" | "false"]
+             android:<a href="#clear">allowClearUserData</a>=["true" | "false"]
              android:<a href="#reparent">allowTaskReparenting</a>=["true" | "false"]
+             android:<a href="#agent">backupAgent</a>="<i>string</i>"
              android:<a href="#debug">debuggable</a>=["true" | "false"]
              android:<a href="#desc">description</a>="<i>string resource</i>"
              android:<a href="#enabled">enabled</a>=["true" | "false"]
              android:<a href="#code">hasCode</a>=["true" | "false"]
              android:<a href="#icon">icon</a>="<i>drawable resource</i>"
+             android:<a href="#killrst">killAfterRestore</a>=["true" | "false"]
              android:<a href="#label">label</a>="<i>string resource</i>"
              android:<a href="#space">manageSpaceActivity</a>="<i>string</i>"
              android:<a href="#nm">name</a>="<i>string</i>"
              android:<a href="#prmsn">permission</a>="<i>string</i>"
              android:<a href="#persistent">persistent</a>=["true" | "false"]
              android:<a href="#proc">process</a>="<i>string</i>"
+             android:<a href="#restoreany">restoreAnyVersion</a>=["true" | "false"]
              android:<a href="#aff">taskAffinity</a>="<i>string</i>"
              android:<a href="#theme">theme</a>="<i>resource or theme</i>" &gt;
     . . .
@@ -45,6 +49,16 @@
 
 <dt>attributes</dt>
 <dd><dl class="attr">
+<dt><a name="backup"></a>{@code android:allowBackup}</dt>
+<dd>Whether the application allows its data to be backed up through the Android
+Backup Manager &mdash; "{@code true}" if it does, "{@code false}" if not.  By
+default this attribute is "{@code true}".  If an application declares this
+attribute to be "{@code false}" the Backup Manager will never attempt to
+perform any backup or restore operation, even if the application declares a
+valid <a href="#agent">{@code android:backupAgent}</a> attribute in its
+manifest.
+</dd>
+
 <dt><a name="clear"></a>{@code android:allowClearUserData}</dt>
 <dd>Whether or not users are given the option to remove user data &mdash; 
 "{@code true}" if they are, and "{@code false}" if not.  If the value is 
@@ -67,6 +81,20 @@
 information.
 </p></dd>
 
+<dt><a name="agent"></a>{@code android:backupAgent}</dt>
+<dd>The name of the class that implement's the application's backup agent,
+a subclass of {@link android.app.backup.BackupAgent}.  The attribute value should be
+a fully qualified  class name (such as, "{@code com.example.project.MyBackupAgent}").  
+However, as a shorthand, if the first character of the name is a period 
+(for example, "{@code .MyBackupAgent}"), it is appended to the 
+package name specified in the 
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code> 
+element.
+
+<p>
+There is no default.  The name must be specified.
+</p></dd>
+
 <dt><a name="debug"></a>{@code android:debuggable}</dt>
 <dd>Whether or not the application can be debugged, even when running 
 on a device in user mode &mdash; "{@code true}" if it can be, and "{@code false}"
@@ -113,6 +141,19 @@
 the image definition.   There is no default icon.
 </p></dd>
 
+<dt><a name="killrst"></a>{@code android:killAfterRestore}</dt>
+<dd>Whether the application in question should be terminated after its
+settings have been restored during a full-system restore operation.
+Single-package restore operations will never cause the application to
+be shut down.  Full-system restore operations typically only occur once,
+when the phone is first set up.  Third-party applications will not normally
+need to use this attribute.
+
+<p>The default is {@code true}, which means that after the application
+has finished processing its data during a full-system restore, it will be
+terminated.
+</p></dd>
+
 <dt><a name="label"></a>{@code android:label}</dt>
 <dd>A user-readable label for the application as a whole, and a default 
 label for each of the application's components.  See the individual 
@@ -196,6 +237,17 @@
 applications, reducing resource usage.
 </p></dd>
 
+<dt><a href name="restoreany"></a>{@code android:restoreAnyVersion}</dt>
+<dd>Indicate that the application is prepared to attempt a restore of any
+backed-up data set, even if the backup was stored by a newer version
+of the application than is currently installed on the device.  Setting
+this attribute to {@code true} will permit the Backup Manager to
+attempt restore even when a version mismatch suggests that the data are
+incompatible.  <em>Use with caution!</em>
+
+<p>The default value of this attribute is {@code false}.
+</p></dd>
+
 <dt><a href name="aff"></a>{@code android:taskAffinity}</dt>
 <dd>An affinity name that applies to all activities within the application,
 except for those that set a different affinity with their own
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index abf36c7..1099c3c 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -529,7 +529,7 @@
       <code>apt-get:</code>:
       <pre>apt-get install ia32-libs</pre>
       </li>
-      <li>Next, install Java: <pre>apt-get install sun-java6-bin</pre></li>
+      <li>Next, install Java: <pre>apt-get install sun-java6-jdk</pre></li>
       <li>The Ubuntu package manager does not currently offer an Eclipse 3.3
       version for download, so we recommend that you download Eclipse from
       eclipse.org (<a
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 1efeb92..3f8bc51 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -31,6 +31,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
 extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;
 extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
 extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 45497e9..9ab02f0 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -102,6 +102,9 @@
     private static final int MSG_MEDIA_SERVER_DIED = 5;
     private static final int MSG_MEDIA_SERVER_STARTED = 6;
     private static final int MSG_PLAY_SOUND_EFFECT = 7;
+    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8;
+
+    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
 
     /** @see AudioSystemThread */
     private AudioSystemThread mAudioSystemThread;
@@ -601,10 +604,8 @@
                 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
 
             case AudioManager.VIBRATE_SETTING_OFF:
-                // Phone ringer should always vibrate in vibrate mode
-                if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) {
-                    return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
-                }
+                // return false, even for incoming calls
+                return false;
 
             default:
                 return false;
@@ -1653,6 +1654,11 @@
                 case MSG_PLAY_SOUND_EFFECT:
                     playSoundEffect(msg.arg1, msg.arg2);
                     break;
+
+                case MSG_BTA2DP_DOCK_TIMEOUT:
+                    // msg.obj  == address of BTA2DP device
+                    makeA2dpDeviceUnavailableNow( (String) msg.obj );
+                    break;
             }
         }
     }
@@ -1707,6 +1713,38 @@
         }
     }
 
+    private void makeA2dpDeviceAvailable(String address) {
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                AudioSystem.DEVICE_STATE_AVAILABLE,
+                address);
+        // Reset A2DP suspend state each time a new sink is connected
+        AudioSystem.setParameters("A2dpSuspended=false");
+        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+                address);
+    }
+
+    private void makeA2dpDeviceUnavailableNow(String address) {
+        Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+        mContext.sendBroadcast(noisyIntent);
+        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                address);
+        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+    }
+
+    private void makeA2dpDeviceUnavailableLater(String address) {
+        // the device will be made unavailable later, so consider it disconnected right away
+        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+        // send the delayed message to make the device unavailable later
+        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
+        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
+
+    }
+
+    private void cancelA2dpDeviceTimeout(String address) {
+        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
+    }
+
     /**
      * Receiver for misc intent broadcasts the Phone app cares about.
      */
@@ -1741,20 +1779,25 @@
 
                 if (isConnected &&
                     state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) {
-                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                            address);
-                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+                    if (btDevice.isBluetoothDock()) {
+                        if (state == BluetoothA2dp.STATE_DISCONNECTED) {
+                            // introduction of a delay for transient disconnections of docks when
+                            // power is rapidly turned off/on, this message will be canceled if
+                            // we reconnect the dock under a preset delay
+                            makeA2dpDeviceUnavailableLater(address);
+                            // the next time isConnected is evaluated, it will be false for the dock
+                        }
+                    } else {
+                        makeA2dpDeviceUnavailableNow(address);
+                    }
                 } else if (!isConnected &&
                              (state == BluetoothA2dp.STATE_CONNECTED ||
                               state == BluetoothA2dp.STATE_PLAYING)) {
-                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                                                         AudioSystem.DEVICE_STATE_AVAILABLE,
-                                                         address);
-                    // Reset A2DP suspend state each time a new sink is connected
-                    AudioSystem.setParameters("A2dpSuspended=false");
-                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
-                            address);
+                    if (btDevice.isBluetoothDock()) {
+                        // this could be a reconnection after a transient disconnection
+                        cancelA2dpDeviceTimeout(address);
+                    }
+                    makeA2dpDeviceAvailable(address);
                 }
             } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 005c64a..bcf2463 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -102,7 +102,7 @@
                 (numChannels == 2)
                     ? AudioSystem::CHANNEL_OUT_STEREO
                     : AudioSystem::CHANNEL_OUT_MONO,
-                8192, 0, &AudioCallback, this, 0);
+                0, 0, &AudioCallback, this, 0);
 
         if ((err = mAudioTrack->initCheck()) != OK) {
             delete mAudioTrack;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index c1987dc..b14a03c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -763,9 +763,14 @@
                 mDurationUs = durationUs;
             }
         }
-    }
 
-    mAudioSource->start();
+        mAudioSource->start();
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
+        // For legacy reasons we're simply going to ignore the absence
+        // of an audio decoder for QCELP instead of aborting playback
+        // altogether.
+        return OK;
+    }
 
     return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
 }
@@ -1234,7 +1239,19 @@
     Mutex::Autolock autoLock(mLock);
 
     if (mSuspensionState != NULL) {
-        return INVALID_OPERATION;
+        if (mLastVideoBuffer == NULL) {
+            //go into here if video is suspended again
+            //after resuming without being played between
+            //them
+            SuspensionState *state = mSuspensionState;
+            mSuspensionState = NULL;
+            reset_l();
+            mSuspensionState = state;
+            return OK;
+        }
+
+        delete mSuspensionState;
+        mSuspensionState = NULL;
     }
 
     if (mFlags & PREPARING) {
@@ -1339,7 +1356,7 @@
         play_l();
     }
 
-    delete state;
+    mSuspensionState = state;
     state = NULL;
 
     return OK;
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index 28d338c..b7c8e0c 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -25,7 +25,8 @@
       mSize(size),
       mInitCheck(NO_INIT),
       mDecoderSpecificOffset(0),
-      mDecoderSpecificLength(0) {
+      mDecoderSpecificLength(0),
+      mObjectTypeIndication(0) {
     memcpy(mData, data, size);
 
     mInitCheck = parse();
@@ -40,6 +41,16 @@
     return mInitCheck;
 }
 
+status_t ESDS::getObjectTypeIndication(uint8_t *objectTypeIndication) const {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    *objectTypeIndication = mObjectTypeIndication;
+
+    return OK;
+}
+
 status_t ESDS::getCodecSpecificInfo(const void **data, size_t *size) const {
     if (mInitCheck != OK) {
         return mInitCheck;
@@ -164,6 +175,8 @@
         return ERROR_MALFORMED;
     }
 
+    mObjectTypeIndication = mData[offset];
+
     offset += 13;
     size -= 13;
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bd3925a..0e21d08 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -741,19 +741,25 @@
             uint16_t data_ref_index = U16_AT(&buffer[6]);
             uint16_t num_channels = U16_AT(&buffer[16]);
 
-            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
-                            FourCC2MIME(chunk_type))
-                || !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
-                               FourCC2MIME(chunk_type))) {
-                // AMR audio is always mono.
-                num_channels = 1;
-            }
-
             uint16_t sample_size = U16_AT(&buffer[18]);
             uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
 
-            // printf("*** coding='%s' %d channels, size %d, rate %d\n",
-            //        chunk, num_channels, sample_size, sample_rate);
+            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
+                            FourCC2MIME(chunk_type))) {
+                // AMR NB audio is always mono, 8kHz
+                num_channels = 1;
+                sample_rate = 8000;
+            } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
+                               FourCC2MIME(chunk_type))) {
+                // AMR WB audio is always mono, 16kHz
+                num_channels = 1;
+                sample_rate = 16000;
+            }
+
+#if 0
+            printf("*** coding='%s' %d channels, size %d, rate %d\n",
+                   chunk, num_channels, sample_size, sample_rate);
+#endif
 
             mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
             mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
@@ -1235,6 +1241,18 @@
 status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
         const void *esds_data, size_t esds_size) {
     ESDS esds(esds_data, esds_size);
+
+    uint8_t objectTypeIndication;
+    if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) {
+        return ERROR_MALFORMED;
+    }
+
+    if (objectTypeIndication == 0xe1) {
+        // This isn't MPEG4 audio at all, it's QCELP 14k...
+        mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
+        return OK;
+    }
+
     const uint8_t *csd;
     size_t csd_size;
     if (esds.getCodecSpecificInfo(
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 04b1454..3a89170 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -29,6 +29,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
 const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
 const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
+const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
 const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index b9d6fbc..873c2aa 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -3040,7 +3040,7 @@
             continue;
         }
 
-        OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
+        OMXCodec::setComponentRole(omx, node, !queryDecoders, mime);
 
         results->push();
         CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index e62d501..3de8c1d 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -19,6 +19,7 @@
 #define __STDC_LIMIT_MACROS
 #include <stdint.h>
 
+//#define LOG_NDEBUG 0
 #define LOG_TAG "TimedEventQueue"
 #include <utils/Log.h>
 
@@ -169,6 +170,8 @@
             mQueueHeadChangedCondition.signal();
         }
 
+        LOGV("cancelling event %d", (*it).event->eventID());
+
         (*it).event->setEventID(0);
         it = mQueue.erase(it);
 
@@ -229,14 +232,16 @@
                 mQueueNotEmptyCondition.wait(mLock);
             }
 
-            List<QueueItem>::iterator it;
+            event_id eventID = 0;
             for (;;) {
                 if (mQueue.empty()) {
                     // The only event in the queue could have been cancelled
                     // while we were waiting for its scheduled time.
                     break;
                 }
-                it = mQueue.begin();
+
+                List<QueueItem>::iterator it = mQueue.begin();
+                eventID = (*it).event->eventID();
 
                 now_us = getRealTimeUs();
                 int64_t when_us = (*it).realtime_us;
@@ -276,19 +281,39 @@
                 }
             }
 
-            if (mQueue.empty()) {
-                continue;
-            }
-
-            event = (*it).event;
-            event->setEventID(0);
-            mQueue.erase(it);
+            // The event w/ this id may have been cancelled while we're
+            // waiting for its trigger-time, in that case
+            // removeEventFromQueue_l will return NULL.
+            // Otherwise, the QueueItem will be removed
+            // from the queue and the referenced event returned.
+            event = removeEventFromQueue_l(eventID);
         }
 
-        // Fire event with the lock NOT held.
-        event->fire(this, now_us);
+        if (event != NULL) {
+            // Fire event with the lock NOT held.
+            event->fire(this, now_us);
+        }
     }
 }
 
+sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
+        event_id id) {
+    for (List<QueueItem>::iterator it = mQueue.begin();
+         it != mQueue.end(); ++it) {
+        if ((*it).event->eventID() == id) {
+            sp<Event> event = (*it).event;
+            event->setEventID(0);
+
+            mQueue.erase(it);
+
+            return event;
+        }
+    }
+
+    LOGW("Event %d was not found in the queue, already cancelled?", id);
+
+    return NULL;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/include/ESDS.h b/media/libstagefright/include/ESDS.h
index 01bcd18..3a79951 100644
--- a/media/libstagefright/include/ESDS.h
+++ b/media/libstagefright/include/ESDS.h
@@ -31,6 +31,7 @@
 
     status_t InitCheck() const;
 
+    status_t getObjectTypeIndication(uint8_t *objectTypeIndication) const;
     status_t getCodecSpecificInfo(const void **data, size_t *size) const;
 
 private:
@@ -47,6 +48,7 @@
 
     size_t mDecoderSpecificOffset;
     size_t mDecoderSpecificLength;
+    uint8_t mObjectTypeIndication;
 
     status_t skipDescriptorHeader(
             size_t offset, size_t size,
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
index 21eade37..11f844c 100644
--- a/media/libstagefright/include/TimedEventQueue.h
+++ b/media/libstagefright/include/TimedEventQueue.h
@@ -121,6 +121,8 @@
     static void *ThreadWrapper(void *me);
     void threadEntry();
 
+    sp<Event> removeEventFromQueue_l(event_id id);
+
     TimedEventQueue(const TimedEventQueue &);
     TimedEventQueue &operator=(const TimedEventQueue &);
 };
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 0c0bf93..2b4714d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -789,7 +789,8 @@
                         + " VALUES(?,?);");
     
                 // Set the timeout to 30 minutes in milliseconds
-                loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT, 30 * 60 * 1000);
+                loadSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
+                        Integer.toString(30 * 60 * 1000));
             } finally {
                 if (stmt != null) stmt.close();
             }