Merge "Ensure the selection does not change in setTextAndKeepSelection." into froyo
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/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b3223e5..c9096cf 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -145,6 +145,13 @@
     public static final int RECENT_WITH_EXCLUDED = 0x0001;
     
     /**
+     * @hide
+     * TODO: Make this public.  Provides a list that does not contain any
+     * recent tasks that currently are not available to the user.
+     */
+    public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
+    
+    /**
      * Return a list of the tasks that the user has recently launched, with
      * the most recent being first and older ones after in order.
      * 
diff --git a/core/java/android/app/backup/BackupAgentHelper.java b/core/java/android/app/backup/BackupAgentHelper.java
index 788b1b5..6d73090 100644
--- a/core/java/android/app/backup/BackupAgentHelper.java
+++ b/core/java/android/app/backup/BackupAgentHelper.java
@@ -21,16 +21,28 @@
 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
  */
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/BackupHelper.java b/core/java/android/app/backup/BackupHelper.java
index 3f41ed2..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} class 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>
- * STOPSHIP: 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,24 +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}
      * after a restore operation to write the backup state file corresponding to
-     * the data as processed by the helper.
+     * 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/provider/Settings.java b/core/java/android/provider/Settings.java
index e640005..e8c09b0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3306,13 +3306,13 @@
          * The bandwidth throttle threshold (long)
          * @hide
          */
-        public static final String THROTTLE_THRESHOLD = "throttle_threshold";
+        public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes";
 
         /**
          * The bandwidth throttle value (kbps)
          * @hide
          */
-        public static final String THROTTLE_VALUE = "throttle_value";
+        public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps";
 
         /**
          * The bandwidth throttle reset calendar day (1-28)
@@ -3327,12 +3327,6 @@
         public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type";
 
         /**
-         * The interface we throttle
-         * @hide
-         */
-        public static final String THROTTLE_IFACE = "throttle_iface";
-
-        /**
          * Help URI for data throttling policy
          * @hide
          */
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 906264a..7fd993a 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -102,8 +102,9 @@
                                 com.android.internal.R.string.httpErrorBadUrl));
                 return false;
             }
-            // Make sure it is correctly URL encoded before sending the request
-            if (!URLUtil.verifyURLEncoding(url)) {
+            // Make sure the host part of the url is correctly
+            // encoded before sending the request
+            if (!URLUtil.verifyURLEncoding(mListener.host())) {
                 mListener.error(EventHandler.ERROR_BAD_URL,
                         mListener.getContext().getString(
                         com.android.internal.R.string.httpErrorBadUrl));
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 12b8c74..e0f8bc0 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -476,6 +476,7 @@
             }
             WebViewWorker.CacheEncoding ce = new WebViewWorker.CacheEncoding();
             ce.mEncoding = mEncoding;
+            ce.mListener = this;
             WebViewWorker.getHandler().obtainMessage(
                     WebViewWorker.MSG_UPDATE_CACHE_ENCODING, ce).sendToTarget();
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4f2a67b..7bd83e7 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();
             }
         }
@@ -4655,13 +4659,16 @@
                         ted.mY = contentY;
                         ted.mMetaState = ev.getMetaState();
                         ted.mReprocess = mDeferTouchProcess;
-                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         if (mDeferTouchProcess) {
                             // still needs to set them for compute deltaX/Y
                             mLastTouchX = x;
                             mLastTouchY = y;
+                            ted.mViewX = x;
+                            ted.mViewY = y;
+                            mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                             break;
                         }
+                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         if (!inFullScreenMode()) {
                             mPrivateHandler.sendMessageDelayed(mPrivateHandler
                                     .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
@@ -4687,17 +4694,20 @@
                 // pass the touch events from UI thread to WebCore thread
                 if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
                         || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
+                    mLastSentTouchTime = eventTime;
                     TouchEventData ted = new TouchEventData();
                     ted.mAction = action;
                     ted.mX = contentX;
                     ted.mY = contentY;
                     ted.mMetaState = ev.getMetaState();
                     ted.mReprocess = mDeferTouchProcess;
-                    mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
-                    mLastSentTouchTime = eventTime;
                     if (mDeferTouchProcess) {
+                        ted.mViewX = x;
+                        ted.mViewY = y;
+                        mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         break;
                     }
+                    mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     if (firstMove && !inFullScreenMode()) {
                         mPrivateHandler.sendMessageDelayed(mPrivateHandler
                                 .obtainMessage(PREVENT_DEFAULT_TIMEOUT,
@@ -4862,6 +4872,10 @@
                     ted.mY = contentY;
                     ted.mMetaState = ev.getMetaState();
                     ted.mReprocess = mDeferTouchProcess;
+                    if (mDeferTouchProcess) {
+                        ted.mViewX = x;
+                        ted.mViewY = y;
+                    }
                     mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                 }
                 mLastTouchUpTime = eventTime;
@@ -4876,6 +4890,10 @@
                             ted.mY = contentY;
                             ted.mMetaState = ev.getMetaState();
                             ted.mReprocess = mDeferTouchProcess;
+                            if (mDeferTouchProcess) {
+                                ted.mViewX = x;
+                                ted.mViewY = y;
+                            }
                             mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                         } else if (mPreventDefault != PREVENT_DEFAULT_YES){
                             doDoubleTap();
@@ -6152,6 +6170,10 @@
                         // simplicity for now, we don't set it.
                         ted.mMetaState = 0;
                         ted.mReprocess = mDeferTouchProcess;
+                        if (mDeferTouchProcess) {
+                            ted.mViewX = mLastTouchX;
+                            ted.mViewY = mLastTouchY;
+                        }
                         mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
                     } else if (mPreventDefault != PREVENT_DEFAULT_YES) {
                         mTouchMode = TOUCH_DONE_MODE;
@@ -6448,31 +6470,27 @@
                         TouchEventData ted = (TouchEventData) msg.obj;
                         switch (ted.mAction) {
                             case MotionEvent.ACTION_DOWN:
-                                mLastDeferTouchX = contentToViewX(ted.mX)
-                                        - mScrollX;
-                                mLastDeferTouchY = contentToViewY(ted.mY)
-                                        - mScrollY;
+                                mLastDeferTouchX = ted.mViewX;
+                                mLastDeferTouchY = ted.mViewY;
                                 mDeferTouchMode = TOUCH_INIT_MODE;
                                 break;
                             case MotionEvent.ACTION_MOVE: {
                                 // no snapping in defer process
-                                int x = contentToViewX(ted.mX) - mScrollX;
-                                int y = contentToViewY(ted.mY) - mScrollY;
                                 if (mDeferTouchMode != TOUCH_DRAG_MODE) {
                                     mDeferTouchMode = TOUCH_DRAG_MODE;
-                                    mLastDeferTouchX = x;
-                                    mLastDeferTouchY = y;
+                                    mLastDeferTouchX = ted.mViewX;
+                                    mLastDeferTouchY = ted.mViewY;
                                     startDrag();
                                 }
                                 int deltaX = pinLocX((int) (mScrollX
-                                        + mLastDeferTouchX - x))
+                                        + mLastDeferTouchX - ted.mViewX))
                                         - mScrollX;
                                 int deltaY = pinLocY((int) (mScrollY
-                                        + mLastDeferTouchY - y))
+                                        + mLastDeferTouchY - ted.mViewY))
                                         - mScrollY;
                                 doDrag(deltaX, deltaY);
-                                if (deltaX != 0) mLastDeferTouchX = x;
-                                if (deltaY != 0) mLastDeferTouchY = y;
+                                if (deltaX != 0) mLastDeferTouchX = ted.mViewX;
+                                if (deltaY != 0) mLastDeferTouchY = ted.mViewY;
                                 break;
                             }
                             case MotionEvent.ACTION_UP:
@@ -6485,8 +6503,8 @@
                                 break;
                             case WebViewCore.ACTION_DOUBLETAP:
                                 // doDoubleTap() needs mLastTouchX/Y as anchor
-                                mLastTouchX = contentToViewX(ted.mX) - mScrollX;
-                                mLastTouchY = contentToViewY(ted.mY) - mScrollY;
+                                mLastTouchX = ted.mViewX;
+                                mLastTouchY = ted.mViewY;
                                 doDoubleTap();
                                 mDeferTouchMode = TOUCH_DONE_MODE;
                                 break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 625e7ba..0175aed 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -708,6 +708,8 @@
         int mY;
         int mMetaState;
         boolean mReprocess;
+        float mViewX;
+        float mViewY;
     }
 
     static class GeolocationPermissionsData {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7ebbab0..64f05fe 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -290,4 +290,21 @@
     <!-- Boolean indicating if current platform supports bluetooth SCO for off call
     use cases -->
     <bool name="config_bluetooth_sco_off_call">true</bool>
+
+    <!-- The default data-use polling period. -->
+    <integer name="config_datause_polling_period_sec">600</integer>
+
+    <!-- The default data-use threshold in bytes. 0 disables-->
+    <integer name="config_datause_threshold_bytes">0</integer>
+
+    <!-- The default reduced-datarate value in kilobits per sec -->
+    <integer name="config_datause_throttle_kbitsps">300</integer>
+
+    <!-- The default iface on which to monitor data use -->
+    <string name="config_datause_iface">rmnet0</string>
+
+    <!-- The default reduced-datarate notification mask -->
+    <!-- 2 means give warning -->
+    <integer name="config_datause_notification_type">2</integer>
+
 </resources>
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/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 0e21d08..323f145 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1642,6 +1642,8 @@
     }
 
     if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+        || !memcmp(header, "ftyp3gr6", 8) || !memcmp(header, "ftyp3gs6", 8)
+        || !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8)
         || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
         || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
         || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
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/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 3908389..78f7b33 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -615,10 +615,27 @@
                     }
                 } break;
                 case UPDATED_MEDIA_STATUS: {
-                    try {
-                        PackageHelper.getMountService().finishMediaUpdate();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "MountService not running?");
+                    if (DEBUG_SD_INSTALL) Log.i(TAG, "Got message UPDATED_MEDIA_STATUS");
+                    boolean reportStatus = msg.arg1 == 1;
+                    boolean doGc = msg.arg2 == 1;
+                    if (DEBUG_SD_INSTALL) Log.i(TAG, "reportStatus=" + reportStatus + ", doGc = " + doGc);
+                    if (doGc) {
+                        // Force a gc to clear up stale containers.
+                        Runtime.getRuntime().gc();
+                    }
+                    if (msg.obj != null) {
+                        Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;
+                        if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
+                        // Unload containers
+                        unloadAllContainers(args);
+                    }
+                    if (reportStatus) {
+                        try {
+                            if (DEBUG_SD_INSTALL) Log.i(TAG, "Invoking MountService call back");
+                            PackageHelper.getMountService().finishMediaUpdate();
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "MountService not running?");
+                        }
                     }
                 } break;
                 case WRITE_SETTINGS: {
@@ -9429,9 +9446,9 @@
            if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
                    mediaStatus+", mMediaMounted=" + mMediaMounted);
            if (mediaStatus == mMediaMounted) {
-               if (reportStatus) {
-                   mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
-               }
+               Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+                       reportStatus ? 1 : 0, -1);
+               mHandler.sendMessage(msg);
                return;
            }
            mMediaMounted = mediaStatus;
@@ -9440,38 +9457,42 @@
        mHandler.post(new Runnable() {
            public void run() {
                mHandler.removeCallbacks(this);
-               try {
-                   updateExternalMediaStatusInner(mediaStatus);
-               } finally {
-                   if (reportStatus) {
-                       mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
-                   }
-               }
+               updateExternalMediaStatusInner(mediaStatus, reportStatus);
            }
        });
    }
 
-   private void updateExternalMediaStatusInner(boolean mediaStatus) {
-       // If we are up here that means there are packages to be
-       // enabled or disabled.
+   /*
+    * Collect information of applications on external media, map them
+    * against existing containers and update information based on current
+    * mount status. Please note that we always have to report status
+    * if reportStatus has been set to true especially when unloading packages.
+    */
+   private void updateExternalMediaStatusInner(boolean mediaStatus,
+           boolean reportStatus) {
+       // Collection of uids
+       int uidArr[] = null;
+       // Collection of stale containers
+       HashSet<String> removeCids = new HashSet<String>();
+       // Collection of packages on external media with valid containers.
+       HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+       // Get list of secure containers.
        final String list[] = PackageHelper.getSecureContainerList();
        if (list == null || list.length == 0) {
            Log.i(TAG, "No secure containers on sdcard");
-           return;
-       }
-
-       int uidList[] = new int[list.length];
-       int num = 0;
-       HashSet<String> removeCids = new HashSet<String>();
-       HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
-       synchronized (mPackages) {
-           for (String cid : list) {
-               SdInstallArgs args = new SdInstallArgs(cid);
-               if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
-               boolean failed = true;
-               try {
+       } else {
+           // Process list of secure containers and categorize them
+           // as active or stale based on their package internal state.
+           int uidList[] = new int[list.length];
+           int num = 0;
+           synchronized (mPackages) {
+               for (String cid : list) {
+                   SdInstallArgs args = new SdInstallArgs(cid);
+                   if (DEBUG_SD_INSTALL) Log.i(TAG, "Processing container " + cid);
                    String pkgName = args.getPackageName();
                    if (pkgName == null) {
+                       if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
+                       removeCids.add(cid);
                        continue;
                    }
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
@@ -9483,33 +9504,29 @@
                                " at code path: " + ps.codePathString);
                        // We do have a valid package installed on sdcard
                        processCids.put(args, ps.codePathString);
-                       failed = false;
                        int uid = ps.userId;
                        if (uid != -1) {
                            uidList[num++] = uid;
                        }
-                   }
-               } finally {
-                   if (failed) {
+                   } else {
                        // Stale container on sdcard. Just delete
                        if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid + " stale");
                        removeCids.add(cid);
                    }
                }
            }
-       }
-       // Organize uids
-       int uidArr[] = null;
-       if (num > 0) {
-           // Sort uid list
-           Arrays.sort(uidList, 0, num);
-           // Throw away duplicates
-           uidArr = new int[num];
-           uidArr[0] = uidList[0];
-           int di = 0;
-           for (int i = 1; i < num; i++) {
-               if (uidList[i-1] != uidList[i]) {
-                   uidArr[di++] = uidList[i];
+
+           if (num > 0) {
+               // Sort uid list
+               Arrays.sort(uidList, 0, num);
+               // Throw away duplicates
+               uidArr = new int[num];
+               uidArr[0] = uidList[0];
+               int di = 0;
+               for (int i = 1; i < num; i++) {
+                   if (uidList[i-1] != uidList[i]) {
+                       uidArr[di++] = uidList[i];
+                   }
                }
            }
        }
@@ -9520,7 +9537,7 @@
            startCleaningPackages();
        } else {
            if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
-           unloadMediaPackages(processCids, uidArr);
+           unloadMediaPackages(processCids, uidArr, reportStatus);
        }
    }
 
@@ -9545,10 +9562,7 @@
     * Look at potentially valid container ids from processCids
     * If package information doesn't match the one on record
     * or package scanning fails, the cid is added to list of
-    * removeCids and cleaned up. Since cleaning up containers
-    * involves destroying them, we do not want any parse
-    * references to such stale containers. So force gc's
-    * to avoid unnecessary crashes.
+    * removeCids. We currently don't delete stale containers.
     */
    private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
            int uidArr[], HashSet<String> removeCids) {
@@ -9626,6 +9640,7 @@
        if (pkgList.size() > 0) {
            sendResourcesChangedBroadcast(true, pkgList, uidArr, null);
        }
+       // Force gc to avoid any stale parser references that we might have.
        if (doGc) {
            Runtime.getRuntime().gc();
        }
@@ -9637,12 +9652,33 @@
        }
    }
 
+   /*
+    * Utility method to unload a list of specified containers
+    */
+   private void unloadAllContainers(Set<SdInstallArgs> cidArgs) {
+       // Just unmount all valid containers.
+       for (SdInstallArgs arg : cidArgs) {
+           synchronized (mInstallLock) {
+               arg.doPostDeleteLI(false);
+           }
+       }
+   }
+
+   /*
+    * Unload packages mounted on external media. This involves deleting
+    * package data from internal structures, sending broadcasts about
+    * diabled packages, gc'ing to free up references, unmounting all
+    * secure containers corresponding to packages on external media, and
+    * posting a UPDATED_MEDIA_STATUS message if status has been requested.
+    * Please note that we always have to post this message if status has
+    * been requested no matter what.
+    */
    private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
-           int uidArr[]) {
+           int uidArr[], final boolean reportStatus) {
        if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
        ArrayList<String> pkgList = new ArrayList<String>();
        ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
-       Set<SdInstallArgs> keys = processCids.keySet();
+       final Set<SdInstallArgs> keys = processCids.keySet();
        for (SdInstallArgs args : keys) {
            String cid = args.cid;
            String pkgName = args.getPackageName();
@@ -9660,22 +9696,23 @@
                }
            }
        }
-       // Send broadcasts
+       // We have to absolutely send UPDATED_MEDIA_STATUS only
+       // after confirming that all the receivers processed the ordered
+       // broadcast when packages get disabled, force a gc to clean things up.
+       // and unload all the containers.
        if (pkgList.size() > 0) {
            sendResourcesChangedBroadcast(false, pkgList, uidArr, new IIntentReceiver.Stub() {
                public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
                        boolean ordered, boolean sticky) throws RemoteException {
-                   // Force gc now that everyone is done cleaning up, to release
-                   // references on assets.
-                   Runtime.getRuntime().gc();
+                   Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+                           reportStatus ? 1 : 0, 1, keys);
+                   mHandler.sendMessage(msg);
                }
            });
-       }
-       // Just unmount all valid containers.
-       for (SdInstallArgs args : keys) {
-           synchronized (mInstallLock) {
-               args.doPostDeleteLI(false);
-           }
+       } else {
+           Message msg = mHandler.obtainMessage(UPDATED_MEDIA_STATUS,
+                   reportStatus ? 1 : 0, -1, keys);
+           mHandler.sendMessage(msg);
        }
    }
 
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 9d4e226..71557f5 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -66,23 +66,17 @@
 
     private Context mContext;
 
-    private int mPolicyPollPeriodSec;
-    private static final int DEFAULT_POLLING_PERIOD_SEC = 60 * 10;
     private static final int TESTING_POLLING_PERIOD_SEC = 60 * 1;
-
     private static final int TESTING_RESET_PERIOD_SEC = 60 * 3;
+    private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
 
     private static final int PERIOD_COUNT = 6;
 
+    private int mPolicyPollPeriodSec;
     private long mPolicyThreshold;
-    // TODO - remove testing stuff?
-    private static final long DEFAULT_TESTING_THRESHOLD = 1 * 1024 * 1024;
-    private static final long DEFAULT_THRESHOLD = 0; // off by default
-
     private int mPolicyThrottleValue;
-    private static final int DEFAULT_THROTTLE_VALUE = 100; // 100 Kbps
-
     private int mPolicyResetDay; // 1-28
+    private int mPolicyNotificationsAllowedMask;
 
     private long mLastRead; // read byte count from last poll
     private long mLastWrite; // write byte count from last poll
@@ -100,11 +94,10 @@
 
     private DataRecorder mRecorder;
 
-    private String mPolicyIface;
+    private String mIface;
 
     private static final int NOTIFICATION_WARNING   = 2;
     private static final int NOTIFICATION_ALL       = 0xFFFFFFFF;
-    private int mPolicyNotificationsAllowedMask;
 
     private Notification mThrottlingNotification;
     private boolean mWarningNotificationSent = false;
@@ -146,16 +139,15 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.THROTTLE_POLLING_SEC), false, this);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.THROTTLE_THRESHOLD), false, this);
+                    Settings.Secure.THROTTLE_THRESHOLD_BYTES), false, this);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.THROTTLE_VALUE), false, this);
+                    Settings.Secure.THROTTLE_VALUE_KBITSPS), false, this);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.THROTTLE_RESET_DAY), false, this);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.THROTTLE_NOTIFICATION_TYPE), false, this);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.THROTTLE_IFACE), false, this);
-                    // TODO - add help url
+                    Settings.Secure.THROTTLE_HELP_URI), false, this);
         }
 
         @Override
@@ -172,18 +164,26 @@
 
     public synchronized long getResetTime(String iface) {
         enforceAccessPermission();
-        if (iface.equals(mPolicyIface) && (mRecorder != null)) mRecorder.getPeriodEnd();
+        if ((iface != null) &&
+                iface.equals(mIface) &&
+                (mRecorder != null)) {
+            mRecorder.getPeriodEnd();
+        }
         return 0;
     }
     public synchronized long getPeriodStartTime(String iface) {
         enforceAccessPermission();
-        if (iface.equals(mPolicyIface) && (mRecorder != null)) mRecorder.getPeriodStart();
+        if ((iface != null) &&
+                iface.equals(mIface) &&
+                (mRecorder != null)) {
+            mRecorder.getPeriodStart();
+        }
         return 0;
     }
     //TODO - a better name?  getCliffByteCountThreshold?
     public synchronized long getCliffThreshold(String iface, int cliff) {
         enforceAccessPermission();
-        if ((cliff == 1) && iface.equals(mPolicyIface)) {
+        if ((iface != null) && (cliff == 1) && iface.equals(mIface)) {
             return mPolicyThreshold;
         }
         return 0;
@@ -191,7 +191,7 @@
     // TODO - a better name? getThrottleRate?
     public synchronized int getCliffLevel(String iface, int cliff) {
         enforceAccessPermission();
-        if ((cliff == 1) && iface.equals(mPolicyIface)) {
+        if ((iface != null) && (cliff == 1) && iface.equals(mIface)) {
             return mPolicyThrottleValue;
         }
         return 0;
@@ -205,7 +205,8 @@
 
     public synchronized long getByteCount(String iface, int dir, int period, int ago) {
         enforceAccessPermission();
-        if (iface.equals(mPolicyIface) &&
+        if ((iface != null) &&
+                iface.equals(mIface) &&
                 (period == ThrottleManager.PERIOD_CYCLE) &&
                 (mRecorder != null)) {
             if (dir == ThrottleManager.DIRECTION_TX) return mRecorder.getPeriodTx(ago);
@@ -217,7 +218,7 @@
     // TODO - a better name - getCurrentThrottleRate?
     public synchronized int getThrottle(String iface) {
         enforceAccessPermission();
-        if (iface.equals(mPolicyIface) && (mThrottleIndex == 1)) {
+        if ((iface != null) && iface.equals(mIface) && (mThrottleIndex == 1)) {
             return mPolicyThrottleValue;
         }
         return 0;
@@ -302,20 +303,27 @@
         private void onPolicyChanged() {
             boolean testing = SystemProperties.get(TESTING_ENABLED_PROPERTY).equals("true");
 
-            int pollingPeriod = DEFAULT_POLLING_PERIOD_SEC;
-            if (testing) pollingPeriod = TESTING_POLLING_PERIOD_SEC;
+            int pollingPeriod = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_datause_polling_period_sec);
             mPolicyPollPeriodSec = Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.THROTTLE_POLLING_SEC, pollingPeriod);
 
             // TODO - remove testing stuff?
-            long defaultThreshold = DEFAULT_THRESHOLD;
-            if (testing) defaultThreshold = DEFAULT_TESTING_THRESHOLD;
+            long defaultThreshold = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_datause_threshold_bytes);
+            int defaultValue = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_datause_throttle_kbitsps);
             synchronized (ThrottleService.this) {
                 mPolicyThreshold = Settings.Secure.getLong(mContext.getContentResolver(),
-                        Settings.Secure.THROTTLE_THRESHOLD, defaultThreshold);
+                        Settings.Secure.THROTTLE_THRESHOLD_BYTES, defaultThreshold);
                 mPolicyThrottleValue = Settings.Secure.getInt(mContext.getContentResolver(),
-                        Settings.Secure.THROTTLE_VALUE, DEFAULT_THROTTLE_VALUE);
+                        Settings.Secure.THROTTLE_VALUE_KBITSPS, defaultValue);
+                if (testing) {
+                    mPolicyPollPeriodSec = TESTING_POLLING_PERIOD_SEC;
+                    mPolicyThreshold = TESTING_THRESHOLD;
+                }
             }
+
             mPolicyResetDay = Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.THROTTLE_RESET_DAY, -1);
             if (mPolicyResetDay == -1 ||
@@ -325,15 +333,18 @@
                 Settings.Secure.putInt(mContext.getContentResolver(),
                 Settings.Secure.THROTTLE_RESET_DAY, mPolicyResetDay);
             }
+            mIface = mContext.getResources().getString(
+                    com.android.internal.R.string.config_datause_iface);
             synchronized (ThrottleService.this) {
-                mPolicyIface = Settings.Secure.getString(mContext.getContentResolver(),
-                        Settings.Secure.THROTTLE_IFACE);
-                // TODO - read default from resource so it's device-specific
-                if (mPolicyIface == null) mPolicyIface = "rmnet0";
+                if (mIface == null) {
+                    mPolicyThreshold = 0;
+                }
             }
 
+            int defaultNotificationType = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_datause_notification_type);
             mPolicyNotificationsAllowedMask = Settings.Secure.getInt(mContext.getContentResolver(),
-                    Settings.Secure.THROTTLE_NOTIFICATION_TYPE, NOTIFICATION_ALL);
+                    Settings.Secure.THROTTLE_NOTIFICATION_TYPE, defaultNotificationType);
 
             Slog.d(TAG, "onPolicyChanged testing=" + testing +", period=" + mPolicyPollPeriodSec +
                     ", threshold=" + mPolicyThreshold + ", value=" + mPolicyThrottleValue +
@@ -352,8 +363,8 @@
             long incRead = 0;
             long incWrite = 0;
             try {
-                incRead = mNMService.getInterfaceRxCounter(mPolicyIface) - mLastRead;
-                incWrite = mNMService.getInterfaceTxCounter(mPolicyIface) - mLastWrite;
+                incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
+                incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
             } catch (RemoteException e) {
                 Slog.e(TAG, "got remoteException in onPollAlarm:" + e);
             }
@@ -383,11 +394,12 @@
             broadcast.putExtra(ThrottleManager.EXTRA_CYCLE_END, mRecorder.getPeriodEnd());
             mContext.sendStickyBroadcast(broadcast);
 
+            mAlarmManager.cancel(mPendingPollIntent);
             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, next, mPendingPollIntent);
         }
 
         private void checkThrottleAndPostNotification(long currentTotal) {
-            // are we even doing this?
+            // is throttling enabled?
             if (mPolicyThreshold == 0)
                 return;
 
@@ -399,7 +411,7 @@
                     }
                     if (DBG) Slog.d(TAG, "Threshold " + mPolicyThreshold + " exceeded!");
                     try {
-                        mNMService.setInterfaceThrottle(mPolicyIface,
+                        mNMService.setInterfaceThrottle(mIface,
                                 mPolicyThrottleValue, mPolicyThrottleValue);
                     } catch (Exception e) {
                         Slog.e(TAG, "error setting Throttle: " + e);
@@ -463,7 +475,7 @@
         private void postNotification(int titleInt, int messageInt, int icon, int flags) {
             Intent intent = new Intent();
             // TODO - fix up intent
-            intent.setClassName("com.android.settings", "com.android.settings.TetherSettings");
+            intent.setClassName("com.android.phone", "com.android.phone.DataUsage");
             intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
 
             PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
@@ -492,7 +504,7 @@
                     mThrottleIndex = THROTTLE_INDEX_UNTHROTTLED;
                 }
                 try {
-                    mNMService.setInterfaceThrottle(mPolicyIface, -1, -1);
+                    mNMService.setInterfaceThrottle(mIface, -1, -1);
                 } catch (Exception e) {
                     Slog.e(TAG, "error clearing Throttle: " + e);
                 }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index cd6a131..657b6af 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -148,6 +148,7 @@
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
+    static final boolean DEBUG_FREEZE = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean HIDE_STACK_CRAWLS = true;
     static final boolean MEASURE_LATENCY = false;
@@ -4418,7 +4419,8 @@
             final int N = mWindows.size();
             for (int i=0; i<N; i++) {
                 WindowState w = (WindowState)mWindows.get(i);
-                if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
+                if (w.isVisibleLw() && !w.mObscured
+                        && (w.mOrientationChanging || !w.isDrawnLw())) {
                     return;
                 }
             }
@@ -7925,7 +7927,7 @@
             final AppWindowToken atoken = mAppToken;
             return mSurface != null && !mAttachedHidden
                     && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
-                    && !mDrawPending && !mCommitDrawPending
+                    && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending))
                     && !mExiting && !mDestroying;
         }
 
@@ -8029,12 +8031,14 @@
 
         /**
          * Returns true if the window has a surface that it has drawn a
-         * complete UI in to.
+         * complete UI in to.  Note that this returns true if the orientation
+         * is changing even if the window hasn't redrawn because we don't want
+         * to stop things from executing during that time.
          */
         public boolean isDrawnLw() {
             final AppWindowToken atoken = mAppToken;
             return mSurface != null && !mDestroying
-                && !mDrawPending && !mCommitDrawPending;
+                && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending));
         }
 
         public boolean fillsScreenLw(int screenWidth, int screenHeight,
@@ -10291,6 +10295,12 @@
                     if (w.mAttachedHidden || !w.isReadyForDisplay()) {
                         if (!w.mLastHidden) {
                             //dump();
+                            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Window hiding: waitingToShow="
+                                    + w.mRootToken.waitingToShow + " polvis="
+                                    + w.mPolicyVisibility + " atthid="
+                                    + w.mAttachedHidden + " tokhid="
+                                    + w.mRootToken.hidden + " vis="
+                                    + w.mViewVisibility);
                             w.mLastHidden = true;
                             if (SHOW_TRANSACTIONS) logSurface(w,
                                     "HIDE (performLayout)", null);
@@ -10686,23 +10696,28 @@
         } else if (animating) {
             requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
         }
-        mQueue.setHoldScreenLocked(holdScreen != null);
-        if (screenBrightness < 0 || screenBrightness > 1.0f) {
-            mPowerManager.setScreenBrightnessOverride(-1);
-        } else {
-            mPowerManager.setScreenBrightnessOverride((int)
-                    (screenBrightness * Power.BRIGHTNESS_ON));
-        }
-        if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
-            mPowerManager.setButtonBrightnessOverride(-1);
-        } else {
-            mPowerManager.setButtonBrightnessOverride((int)
-                    (buttonBrightness * Power.BRIGHTNESS_ON));
-        }
-        if (holdScreen != mHoldingScreenOn) {
-            mHoldingScreenOn = holdScreen;
-            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
-            mH.sendMessage(m);
+        
+        if (DEBUG_FREEZE) Slog.v(TAG, "Layout: mDisplayFrozen=" + mDisplayFrozen
+                + " holdScreen=" + holdScreen);
+        if (!mDisplayFrozen) {
+            mQueue.setHoldScreenLocked(holdScreen != null);
+            if (screenBrightness < 0 || screenBrightness > 1.0f) {
+                mPowerManager.setScreenBrightnessOverride(-1);
+            } else {
+                mPowerManager.setScreenBrightnessOverride((int)
+                        (screenBrightness * Power.BRIGHTNESS_ON));
+            }
+            if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+                mPowerManager.setButtonBrightnessOverride(-1);
+            } else {
+                mPowerManager.setButtonBrightnessOverride((int)
+                        (buttonBrightness * Power.BRIGHTNESS_ON));
+            }
+            if (holdScreen != mHoldingScreenOn) {
+                mHoldingScreenOn = holdScreen;
+                Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
+                mH.sendMessage(m);
+            }
         }
 
         if (mTurnOnScreen) {
@@ -10979,6 +10994,8 @@
             mFreezeGcPending = now;
         }
 
+        if (DEBUG_FREEZE) Slog.v(TAG, "*** FREEZING DISPLAY", new RuntimeException());
+        
         mDisplayFrozen = true;
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -11002,6 +11019,8 @@
             return;
         }
         
+        if (DEBUG_FREEZE) Slog.v(TAG, "*** UNFREEZING DISPLAY", new RuntimeException());
+        
         mDisplayFrozen = false;
         mH.removeMessages(H.APP_FREEZE_TIMEOUT);
         if (PROFILE_ORIENTATION) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bc26fa0..b6f323d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6867,6 +6867,8 @@
             enforceCallingPermission(android.Manifest.permission.GET_TASKS,
                     "getRecentTasks()");
 
+            IPackageManager pm = ActivityThread.getPackageManager();
+            
             final int N = mRecentTasks.size();
             ArrayList<ActivityManager.RecentTaskInfo> res
                     = new ArrayList<ActivityManager.RecentTaskInfo>(
@@ -6883,6 +6885,25 @@
                     rti.baseIntent = new Intent(
                             tr.intent != null ? tr.intent : tr.affinityIntent);
                     rti.origActivity = tr.origActivity;
+                    
+                    if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0) {
+                        // Check whether this activity is currently available.
+                        try {
+                            if (rti.origActivity != null) {
+                                if (pm.getActivityInfo(rti.origActivity, 0) == null) {
+                                    continue;
+                                }
+                            } else if (rti.baseIntent != null) {
+                                if (pm.queryIntentActivities(rti.baseIntent,
+                                        null, 0) == null) {
+                                    continue;
+                                }
+                            }
+                        } catch (RemoteException e) {
+                            // Will never happen.
+                        }
+                    }
+                    
                     res.add(rti);
                     maxNum--;
                 }