Merge "Don't handle click if the resolver is already finishing." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index e96eec2..db8f224 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_CALL_SERVICE = "android.permission.BIND_CALL_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
     field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
@@ -638,13 +639,13 @@
     field public static final int keyPreviewHeight = 16843321; // 0x1010239
     field public static final int keyPreviewLayout = 16843319; // 0x1010237
     field public static final int keyPreviewOffset = 16843320; // 0x1010238
+    field public static final int keySet = 16843739; // 0x10103db
     field public static final int keyTextColor = 16843318; // 0x1010236
     field public static final int keyTextSize = 16843316; // 0x1010234
     field public static final int keyWidth = 16843325; // 0x101023d
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
     field public static final int keycode = 16842949; // 0x10100c5
-    field public static final int keyset = 16843739; // 0x10103db
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
     field public static final int labelFor = 16843718; // 0x10103c6
@@ -6521,6 +6522,7 @@
     field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
     field public static final int FLAG_PERSIST_GRANT_URI_PERMISSION = 64; // 0x40
     field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
+    field public static final int FLAG_RECEIVER_NO_ABORT = 134217728; // 0x8000000
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -12430,7 +12432,7 @@
     method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
-    method public final void setParameters(java.util.Map<java.lang.String, java.lang.Object>);
+    method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
     method public final void start();
@@ -12446,7 +12448,7 @@
     field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
     field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
     field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
-    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -12757,6 +12759,9 @@
     field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
     field public static final java.lang.String KEY_HEIGHT = "height";
     field public static final java.lang.String KEY_IS_ADTS = "is-adts";
+    field public static final java.lang.String KEY_IS_AUTOSELECT = "is-autoselect";
+    field public static final java.lang.String KEY_IS_DEFAULT = "is-default";
+    field public static final java.lang.String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
     field public static final java.lang.String KEY_I_FRAME_INTERVAL = "i-frame-interval";
     field public static final java.lang.String KEY_LANGUAGE = "language";
     field public static final java.lang.String KEY_MAX_HEIGHT = "max-height";
@@ -12769,6 +12774,25 @@
     field public static final java.lang.String KEY_WIDTH = "width";
   }
 
+  public abstract class MediaMetadataEditor {
+    method public synchronized void addEditableKey(int);
+    method public abstract void apply();
+    method public synchronized void clear();
+    method public synchronized android.graphics.Bitmap getBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized int[] getEditableKeys();
+    method public synchronized long getLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized java.lang.Object getObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public synchronized java.lang.String getString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putObject(int, java.lang.Object) throws java.lang.IllegalArgumentException;
+    method public synchronized android.media.MediaMetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
+    method public synchronized void removeEditableKeys();
+    field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
+    field public static final int RATING_KEY_BY_OTHERS = 101; // 0x65
+    field public static final int RATING_KEY_BY_USER = 268435457; // 0x10000001
+  }
+
   public class MediaMetadataRetriever {
     ctor public MediaMetadataRetriever();
     method public java.lang.String extractMetadata(int);
@@ -13185,6 +13209,29 @@
     ctor public NotProvisionedException(java.lang.String);
   }
 
+  public final class Rating implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getPercentRating();
+    method public int getRatingStyle();
+    method public float getStarRating();
+    method public boolean hasHeart();
+    method public boolean isRated();
+    method public boolean isThumbUp();
+    method public static android.media.Rating newHeartRating(boolean);
+    method public static android.media.Rating newPercentageRating(float);
+    method public static android.media.Rating newStarRating(int, float);
+    method public static android.media.Rating newThumbRating(boolean);
+    method public static android.media.Rating newUnratedRating(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int RATING_3_STARS = 3; // 0x3
+    field public static final int RATING_4_STARS = 4; // 0x4
+    field public static final int RATING_5_STARS = 5; // 0x5
+    field public static final int RATING_HEART = 1; // 0x1
+    field public static final int RATING_PERCENTAGE = 6; // 0x6
+    field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+  }
+
   public class RemoteControlClient {
     ctor public RemoteControlClient(android.app.PendingIntent);
     ctor public RemoteControlClient(android.app.PendingIntent, android.os.Looper);
@@ -13216,21 +13263,9 @@
     field public static final int PLAYSTATE_STOPPED = 1; // 0x1
   }
 
-  public class RemoteControlClient.MetadataEditor {
-    method public synchronized void addEditableKey(int);
+  public class RemoteControlClient.MetadataEditor extends android.media.MediaMetadataEditor {
     method public synchronized void apply();
-    method public synchronized void clear();
-    method public synchronized void clearEditableKeys();
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putBitmap(int, android.graphics.Bitmap) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putLong(int, long) throws java.lang.IllegalArgumentException;
-    method public synchronized android.media.RemoteControlClient.MetadataEditor putString(int, java.lang.String) throws java.lang.IllegalArgumentException;
     field public static final int BITMAP_KEY_ARTWORK = 100; // 0x64
-    field public static final int LONG_KEY_RATING_BY_OTHERS = 102; // 0x66
-    field public static final int LONG_KEY_RATING_BY_USER = 268435457; // 0x10000001
-    field public static final int LONG_KEY_RATING_TYPE = 101; // 0x65
-    field public static final long RATING_HEART = -1L; // 0xffffffffffffffffL
-    field public static final long RATING_NOT_RATED = -101L; // 0xffffffffffffff9bL
-    field public static final long RATING_THUMB_UP_DOWN = -2L; // 0xfffffffffffffffeL
   }
 
   public static abstract interface RemoteControlClient.OnGetPlaybackPositionListener {
@@ -13238,9 +13273,7 @@
   }
 
   public static abstract interface RemoteControlClient.OnMetadataUpdateListener {
-    method public abstract void onMetadataUpdateBitmap(int, android.graphics.Bitmap);
-    method public abstract void onMetadataUpdateLong(int, long);
-    method public abstract void onMetadataUpdateString(int, java.lang.String);
+    method public abstract void onMetadataUpdate(int, java.lang.Object);
   }
 
   public static abstract interface RemoteControlClient.OnPlaybackPositionUpdateListener {
@@ -19115,12 +19148,54 @@
     field public static final android.print.PrintAttributes.MediaSize ISO_C7;
     field public static final android.print.PrintAttributes.MediaSize ISO_C8;
     field public static final android.print.PrintAttributes.MediaSize ISO_C9;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B0;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B1;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B10;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B2;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B3;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B4;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B5;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B6;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B7;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B8;
+    field public static final android.print.PrintAttributes.MediaSize JIS_B9;
+    field public static final android.print.PrintAttributes.MediaSize JIS_EXEC;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU2;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU3;
+    field public static final android.print.PrintAttributes.MediaSize JPN_CHOU4;
+    field public static final android.print.PrintAttributes.MediaSize JPN_HAGAKI;
+    field public static final android.print.PrintAttributes.MediaSize JPN_KAHU;
+    field public static final android.print.PrintAttributes.MediaSize JPN_KAKU2;
+    field public static final android.print.PrintAttributes.MediaSize JPN_OUFUKU;
+    field public static final android.print.PrintAttributes.MediaSize JPN_YOU4;
+    field public static final android.print.PrintAttributes.MediaSize NA_FOOLSCAP;
     field public static final android.print.PrintAttributes.MediaSize NA_GOVT_LETTER;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_3X5;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_4X6;
+    field public static final android.print.PrintAttributes.MediaSize NA_INDEX_5X8;
     field public static final android.print.PrintAttributes.MediaSize NA_JUNIOR_LEGAL;
     field public static final android.print.PrintAttributes.MediaSize NA_LEDGER;
     field public static final android.print.PrintAttributes.MediaSize NA_LEGAL;
     field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
+    field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
+    field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
     field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+    field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
+    field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
+    field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
+    field public static final android.print.PrintAttributes.MediaSize PRC_1;
+    field public static final android.print.PrintAttributes.MediaSize PRC_10;
+    field public static final android.print.PrintAttributes.MediaSize PRC_16k;
+    field public static final android.print.PrintAttributes.MediaSize PRC_2;
+    field public static final android.print.PrintAttributes.MediaSize PRC_3;
+    field public static final android.print.PrintAttributes.MediaSize PRC_4;
+    field public static final android.print.PrintAttributes.MediaSize PRC_5;
+    field public static final android.print.PrintAttributes.MediaSize PRC_6;
+    field public static final android.print.PrintAttributes.MediaSize PRC_7;
+    field public static final android.print.PrintAttributes.MediaSize PRC_8;
+    field public static final android.print.PrintAttributes.MediaSize PRC_9;
+    field public static final android.print.PrintAttributes.MediaSize ROC_16K;
+    field public static final android.print.PrintAttributes.MediaSize ROC_8K;
   }
 
   public static final class PrintAttributes.Resolution {
@@ -24944,9 +25019,7 @@
     method public static void clearMetaKeyState(android.text.Editable, int);
     method public long clearMetaKeyState(long, int);
     method public static final int getMetaState(java.lang.CharSequence);
-    method public static final int getMetaState(java.lang.CharSequence, android.view.KeyEvent);
     method public static final int getMetaState(java.lang.CharSequence, int);
-    method public static final int getMetaState(java.lang.CharSequence, int, android.view.KeyEvent);
     method public static final int getMetaState(long);
     method public static final int getMetaState(long, int);
     method public static long handleKeyDown(long, int, android.view.KeyEvent);
@@ -27265,6 +27338,7 @@
     method public float getScaleFactor();
     method public long getTimeDelta();
     method public boolean isInProgress();
+    method public boolean isQuickScaleEnabled();
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public void setQuickScaleEnabled(boolean);
   }
@@ -29935,7 +30009,7 @@
     method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
     method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
     method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
-    method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onGeolocationPermissionsHidePrompt();
     method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
     method public void onHideCustomView();
@@ -29945,7 +30019,7 @@
     method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
     method public deprecated boolean onJsTimeout();
     method public void onProgressChanged(android.webkit.WebView, int);
-    method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+    method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
     method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
     method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
     method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -30001,12 +30075,12 @@
     method public int getCacheMode();
     method public synchronized java.lang.String getCursiveFontFamily();
     method public synchronized boolean getDatabaseEnabled();
-    method public synchronized java.lang.String getDatabasePath();
+    method public deprecated synchronized java.lang.String getDatabasePath();
     method public synchronized int getDefaultFixedFontSize();
     method public synchronized int getDefaultFontSize();
     method public synchronized java.lang.String getDefaultTextEncodingName();
     method public static java.lang.String getDefaultUserAgent(android.content.Context);
-    method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+    method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
     method public boolean getDisplayZoomControls();
     method public synchronized boolean getDomStorageEnabled();
     method public synchronized java.lang.String getFantasyFontFamily();
@@ -30043,11 +30117,11 @@
     method public void setCacheMode(int);
     method public synchronized void setCursiveFontFamily(java.lang.String);
     method public synchronized void setDatabaseEnabled(boolean);
-    method public synchronized void setDatabasePath(java.lang.String);
+    method public deprecated synchronized void setDatabasePath(java.lang.String);
     method public synchronized void setDefaultFixedFontSize(int);
     method public synchronized void setDefaultFontSize(int);
     method public synchronized void setDefaultTextEncodingName(java.lang.String);
-    method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+    method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
     method public void setDisplayZoomControls(boolean);
     method public synchronized void setDomStorageEnabled(boolean);
     method public deprecated void setEnableSmoothTransition(boolean);
@@ -30090,9 +30164,10 @@
   public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
     method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
     method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
-    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+    enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
     enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
     enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+    enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
   }
 
   public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -30145,7 +30220,7 @@
     method public long getUsage();
   }
 
-  public static abstract interface WebStorage.QuotaUpdater {
+  public static abstract deprecated interface WebStorage.QuotaUpdater {
     method public abstract void updateQuota(long);
   }
 
@@ -30173,7 +30248,7 @@
     method public boolean canGoForward();
     method public deprecated boolean canZoomIn();
     method public deprecated boolean canZoomOut();
-    method public android.graphics.Picture capturePicture();
+    method public deprecated android.graphics.Picture capturePicture();
     method public void clearCache(boolean);
     method public void clearFormData();
     method public void clearHistory();
@@ -30190,7 +30265,7 @@
     method public void findAllAsync(java.lang.String);
     method public void findNext(boolean);
     method public void flingScroll(int, int);
-    method public void freeMemory();
+    method public deprecated void freeMemory();
     method public android.net.http.SslCertificate getCertificate();
     method public int getContentHeight();
     method public android.graphics.Bitmap getFavicon();
@@ -31535,6 +31610,8 @@
     ctor public NumberPicker(android.content.Context);
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet);
     ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int);
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
     method public java.lang.String[] getDisplayedValues();
     method public int getMaxValue();
     method public int getMinValue();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3e4795c..bf2a1e4 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -65,7 +65,7 @@
 
     // when adding one of these:
     //  - increment _NUM_OP
-    //  - add rows to sOpToSwitch, sOpNames, sOpPerms
+    //  - add rows to sOpToSwitch, sOpNames, sOpPerms, sOpDefaultMode
     //  - add descriptive strings to Settings/res/values/arrays.xml
     //  - add the op to the appropriate template in AppOpsState.OpsTemplate (settings app)
 
@@ -315,6 +315,55 @@
     };
 
     /**
+     * This specifies the default mode for each operation.
+     */
+    private static int[] sOpDefaultMode = new int[] {
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+    };
+
+    /**
      * Retrieve the op switch that controls the given operation.
      * @hide
      */
@@ -339,6 +388,14 @@
     }
 
     /**
+     * Retrieve the default mode for the operation.
+     * @hide
+     */
+    public static int opToDefaultMode(int op) {
+        return sOpDefaultMode[op];
+    }
+
+    /**
      * Class holding all of the operation information associated with an app.
      * @hide
      */
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 0a1d3f9a..9a258dc 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1573,8 +1573,10 @@
          */
         if (mContext == null) {
             mContext = context;
-            mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
-                    Context.APP_OPS_SERVICE);
+            if (context != null) {
+                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
+                        Context.APP_OPS_SERVICE);
+            }
             mMyUid = Process.myUid();
             if (info != null) {
                 setReadPermission(info.readPermission);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f250029..5618cab 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2316,8 +2316,7 @@
         }
 
         @Override
-        public void close() throws IOException {
-            super.close();
+        public void releaseResources() {
             if (!mProviderReleased) {
                 ContentResolver.this.releaseProvider(mContentProvider);
                 mProviderReleased = true;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7925123..dcc6328 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3588,6 +3588,12 @@
      */
     public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
     /**
+     * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
+     * They can still propagate results through to later receivers, but they can not prevent
+     * later receivers from seeing the broadcast.
+     */
+    public static final int FLAG_RECEIVER_NO_ABORT = 0x08000000;
+    /**
      * If set, when sending a broadcast <i>before boot has completed</i> only
      * registered receivers will be called -- no BroadcastReceiver components
      * will be launched.  Sticky intent state will be recorded properly even
@@ -3600,14 +3606,14 @@
      *
      * @hide
      */
-    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
+    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x04000000;
     /**
      * Set when this broadcast is for a boot upgrade, a special mode that
      * allows the broadcast to be sent before the system is ready and launches
      * the app process with no providers running in it.
      * @hide
      */
-    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
+    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
 
     /**
      * @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/hardware/camera2/CameraProperties.java b/core/java/android/hardware/camera2/CameraProperties.java
index 58a1ee3..a2faf09f 100644
--- a/core/java/android/hardware/camera2/CameraProperties.java
+++ b/core/java/android/hardware/camera2/CameraProperties.java
@@ -415,6 +415,14 @@
      * platform opaque YUV/RGB streams to the GPU or video
      * encoders. Listed as width, height
      * </p>
+     * <p>
+     * The actual supported resolution list may be limited by
+     * consumer end points for different use cases. For example, for
+     * recording use case, the largest supported resolution may be
+     * limited by max supported size from encoder, for preview use
+     * case, the largest supported resolution may be limited by max
+     * resolution SurfaceTexture/SurfaceView can support.
+     * </p>
      */
     public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
             new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 40a3612..d0feaa3 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -255,6 +255,10 @@
         return mRequiresDeviceUnlock;
     }
 
+    public String getDescription() {
+        return mDescription;
+    }
+
     public CharSequence loadLabel(PackageManager pm) {
         return mService.loadLabel(pm);
     }
@@ -287,6 +291,11 @@
             Log.e(TAG, "AID " + aid + " is not correctly formatted.");
             return false;
         }
+        // Minimum AID length is 5 bytes, 10 hex chars
+        if (aidLength < 10) {
+            Log.e(TAG, "AID " + aid + " is shorter than 5 bytes.");
+            return false;
+        }
         return true;
     }
 
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 579971d..5a49b98 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -564,7 +564,11 @@
     @Override
     public void close() throws IOException {
         if (mWrapped != null) {
-            mWrapped.close();
+            try {
+                mWrapped.close();
+            } finally {
+                releaseResources();
+            }
         } else {
             closeWithStatus(Status.OK, null);
         }
@@ -579,7 +583,11 @@
      */
     public void closeWithError(String msg) throws IOException {
         if (mWrapped != null) {
-            mWrapped.closeWithError(msg);
+            try {
+                mWrapped.closeWithError(msg);
+            } finally {
+                releaseResources();
+            }
         } else {
             if (msg == null) {
                 throw new IllegalArgumentException("Message must not be null");
@@ -588,17 +596,22 @@
         }
     }
 
-    private void closeWithStatus(int status, String msg) throws IOException {
-        if (mWrapped != null) {
-            mWrapped.closeWithStatus(status, msg);
-        } else {
-            if (mClosed) return;
-            mClosed = true;
-            mGuard.close();
-            // Status MUST be sent before closing actual descriptor
-            writeCommStatusAndClose(status, msg);
-            IoUtils.closeQuietly(mFd);
-        }
+    private void closeWithStatus(int status, String msg) {
+        if (mClosed) return;
+        mClosed = true;
+        mGuard.close();
+        // Status MUST be sent before closing actual descriptor
+        writeCommStatusAndClose(status, msg);
+        IoUtils.closeQuietly(mFd);
+        releaseResources();
+    }
+
+    /**
+     * Called when the fd is being closed, for subclasses to release any other resources
+     * associated with it, such as acquired providers.
+     * @hide
+     */
+    public void releaseResources() {
     }
 
     private byte[] getOrCreateStatusBuffer() {
@@ -793,6 +806,9 @@
 
     @Override
     protected void finalize() throws Throwable {
+        if (mWrapped != null) {
+            releaseResources();
+        }
         if (mGuard != null) {
             mGuard.warnIfOpen();
         }
@@ -822,7 +838,11 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         if (mWrapped != null) {
-            mWrapped.writeToParcel(out, flags);
+            try {
+                mWrapped.writeToParcel(out, flags);
+            } finally {
+                releaseResources();
+            }
         } else {
             out.writeFileDescriptor(mFd);
             if (mCommFd != null) {
@@ -832,11 +852,8 @@
                 out.writeInt(0);
             }
             if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
-                try {
-                    // Not a real close, so emit no status
-                    closeWithStatus(Status.SILENCE, null);
-                } catch (IOException e) {
-                }
+                // Not a real close, so emit no status
+                closeWithStatus(Status.SILENCE, null);
             }
         }
     }
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index d889353..efe6b15 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -373,27 +373,208 @@
 
         // North America
 
-        /** North America Letter media size: 8.5" x 11" */
+        /** North America Letter media size: 8.5" x 11" (279mm x 216mm) */
         public static final MediaSize NA_LETTER =
                 new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
-        /** North America Government-Letter media size: 8.0" x 10.5" */
+        /** North America Government-Letter media size: 8.0" x 10.5" (203mm x 267mm) */
         public static final MediaSize NA_GOVT_LETTER =
                 new MediaSize("NA_GOVT_LETTER", "android",
                         R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
-        /** North America Legal media size: 8.5" x 14" */
+        /** North America Legal media size: 8.5" x 14" (216mm x 356mm) */
         public static final MediaSize NA_LEGAL =
                 new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
-        /** North America Junior Legal media size: 8.0" x 5.0" */
+        /** North America Junior Legal media size: 8.0" x 5.0" (203mm × 127mm) */
         public static final MediaSize NA_JUNIOR_LEGAL =
                 new MediaSize("NA_JUNIOR_LEGAL", "android",
                         R.string.mediaSize_na_junior_legal, 8000, 5000);
-        /** North America Ledger media size: 17" x 11" */
+        /** North America Ledger media size: 17" x 11" (432mm × 279mm) */
         public static final MediaSize NA_LEDGER =
                 new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
-        /** North America Tabloid media size: 11" x 17" */
+        /** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
         public static final MediaSize NA_TBLOID =
                 new MediaSize("NA_TABLOID", "android",
                         R.string.mediaSize_na_tabloid, 11000, 17000);
+        /** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
+        public static final MediaSize NA_INDEX_3X5 =
+                new MediaSize("NA_INDEX_3X5", "android",
+                        R.string.mediaSize_na_index_3x5, 3000, 5000);
+        /** North America Index Card 4x6 media size: 4" x 6" (102mm x 152mm) */
+        public static final MediaSize NA_INDEX_4X6 =
+                new MediaSize("NA_INDEX_4X6", "android",
+                        R.string.mediaSize_na_index_4x6, 4000, 6000);
+        /** North America Index Card 5x8 media size: 5" x 8" (127mm x 203mm) */
+        public static final MediaSize NA_INDEX_5X8 =
+                new MediaSize("NA_INDEX_5X8", "android",
+                        R.string.mediaSize_na_index_5x8, 5000, 8000);
+        /** North America Monarch media size: 7.25" x 10.5" (184mm x 267mm) */
+        public static final MediaSize NA_MONARCH =
+                new MediaSize("NA_MONARCH", "android",
+                        R.string.mediaSize_na_monarch, 7250, 10500);
+        /** North America Quarto media size: 8" x 10" (203mm x 254mm) */
+        public static final MediaSize NA_QUARTO =
+                new MediaSize("NA_QUARTO", "android",
+                        R.string.mediaSize_na_quarto, 8000, 10000);
+        /** North America Foolscap media size: 8" x 13" (203mm x 330mm) */
+        public static final MediaSize NA_FOOLSCAP =
+                new MediaSize("NA_FOOLSCAP", "android",
+                        R.string.mediaSize_na_foolscap, 8000, 13000);
+
+        // Chinese
+
+        /** Chinese ROC 8K media size: 270mm x 390mm (10.629" x 15.3543") */
+        public static final MediaSize ROC_8K =
+                new MediaSize("ROC_8K", "android",
+                        R.string.mediaSize_chinese_roc_8k, 10629, 15354);
+        /** Chinese ROC 16K media size: 195mm x 270mm (7.677" x 10.629") */
+        public static final MediaSize ROC_16K =
+                new MediaSize("ROC_16K", "android",
+                        R.string.mediaSize_chinese_roc_16k, 7677, 10629);
+
+        /** Chinese PRC 1 media size: 102mm x 165mm (4.015" x 6.496") */
+        public static final MediaSize PRC_1 =
+                new MediaSize("PRC_1", "android",
+                        R.string.mediaSize_chinese_prc_1, 4015, 6496);
+        /** Chinese PRC 2 media size: 102mm x 176mm (4.015" x 6.929") */
+        public static final MediaSize PRC_2 =
+                new MediaSize("PRC_2", "android",
+                        R.string.mediaSize_chinese_prc_2, 4015, 6929);
+        /** Chinese PRC 3 media size: 125mm x 176mm (4.921" x 6.929") */
+        public static final MediaSize PRC_3 =
+                new MediaSize("PRC_3", "android",
+                        R.string.mediaSize_chinese_prc_3, 4921, 6929);
+        /** Chinese PRC 4 media size: 110mm x 208mm (4.330" x 8.189") */
+        public static final MediaSize PRC_4 =
+                new MediaSize("PRC_4", "android",
+                        R.string.mediaSize_chinese_prc_4, 4330, 8189);
+        /** Chinese PRC 5 media size: 110mm x 220mm (4.330" x 8.661") */
+        public static final MediaSize PRC_5 =
+                new MediaSize("PRC_5", "android",
+                        R.string.mediaSize_chinese_prc_5, 4330, 8661);
+        /** Chinese PRC 6 media size: 120mm x 320mm (4.724" x 12.599") */
+        public static final MediaSize PRC_6 =
+                new MediaSize("PRC_6", "android",
+                        R.string.mediaSize_chinese_prc_6, 4724, 12599);
+        /** Chinese PRC 7 media size: 160mm x 230mm (6.299" x 9.055") */
+        public static final MediaSize PRC_7 =
+                new MediaSize("PRC_7", "android",
+                        R.string.mediaSize_chinese_prc_7, 6299, 9055);
+        /** Chinese PRC 8 media size: 120mm x 309mm (4.724" x 12.165") */
+        public static final MediaSize PRC_8 =
+                new MediaSize("PRC_8", "android",
+                        R.string.mediaSize_chinese_prc_8, 4724, 12165);
+        /** Chinese PRC 9 media size: 229mm x 324mm (9.016" x 12.756") */
+        public static final MediaSize PRC_9 =
+                new MediaSize("PRC_9", "android",
+                        R.string.mediaSize_chinese_prc_9, 9016, 12756);
+        /** Chinese PRC 10 media size: 324mm x 458mm (12.756" x 18.032") */
+        public static final MediaSize PRC_10 =
+                new MediaSize("PRC_10", "android",
+                        R.string.mediaSize_chinese_prc_10, 12756, 18032);
+
+        /** Chinese PRC 16k media size: 146mm x 215mm (5.749" x 8.465") */
+        public static final MediaSize PRC_16k =
+                new MediaSize("PRC_16k", "android",
+                        R.string.mediaSize_chinese_prc_16k, 5749, 8465);
+        /** Chinese Pa Kai media size: 267mm x 389mm (10.512" x 15.315") */
+        public static final MediaSize OM_PA_KAI =
+                new MediaSize("OM_PA_KAI", "android",
+                        R.string.mediaSize_chinese_om_pa_kai, 10512, 15315);
+        /** Chinese Dai Pa Kai media size: 275mm x 395mm (10.827" x 15.551") */
+        public static final MediaSize OM_DAI_PA_KAI =
+                new MediaSize("OM_DAI_PA_KAI", "android",
+                        R.string.mediaSize_chinese_om_dai_pa_kai, 10827, 15551);
+        /** Chinese Jurro Ku Kai media size: 198mm x 275mm (7.796" x 10.827") */
+        public static final MediaSize OM_JUURO_KU_KAI =
+                new MediaSize("OM_JUURO_KU_KAI", "android",
+                        R.string.mediaSize_chinese_om_jurro_ku_kai, 7796, 10827);
+
+        // Japanese
+
+        /** Japanese JIS B10 media size: 32mm x 45mm (1.259" x 1.772") */
+        public static final MediaSize JIS_B10 =
+                new MediaSize("JIS_B10", "android",
+                        R.string.mediaSize_japanese_jis_b10, 1259, 1772);
+        /** Japanese JIS B9 media size: 45mm x 64mm (1.772" x 2.52") */
+        public static final MediaSize JIS_B9 =
+                new MediaSize("JIS_B9", "android",
+                        R.string.mediaSize_japanese_jis_b9, 1772, 2520);
+        /** Japanese JIS B8 media size: 64mm x 91mm (2.52" x 3.583") */
+        public static final MediaSize JIS_B8 =
+                new MediaSize("JIS_B8", "android",
+                        R.string.mediaSize_japanese_jis_b8, 2520, 3583);
+        /** Japanese JIS B7 media size: 91mm x 128mm (3.583" x 5.049") */
+        public static final MediaSize JIS_B7 =
+                new MediaSize("JIS_B7", "android",
+                        R.string.mediaSize_japanese_jis_b7, 3583, 5049);
+        /** Japanese JIS B6 media size: 128mm x 182mm (5.049" x 7.165") */
+        public static final MediaSize JIS_B6 =
+                new MediaSize("JIS_B6", "android",
+                        R.string.mediaSize_japanese_jis_b6, 5049, 7165);
+        /** Japanese JIS B5 media size: 182mm x 257mm (7.165" x 10.118") */
+        public static final MediaSize JIS_B5 =
+                new MediaSize("JIS_B5", "android",
+                        R.string.mediaSize_japanese_jis_b5, 7165, 10118);
+        /** Japanese JIS B4 media size: 257mm x 364mm (10.118" x 14.331") */
+        public static final MediaSize JIS_B4 =
+                new MediaSize("JIS_B4", "android",
+                        R.string.mediaSize_japanese_jis_b4, 10118, 14331);
+        /** Japanese JIS B3 media size: 364mm x 515mm (14.331" x 20.276") */
+        public static final MediaSize JIS_B3 =
+                new MediaSize("JIS_B3", "android",
+                        R.string.mediaSize_japanese_jis_b3, 14331, 20276);
+        /** Japanese JIS B2 media size: 515mm x 728mm (20.276" x 28.661") */
+        public static final MediaSize JIS_B2 =
+                new MediaSize("JIS_B2", "android",
+                        R.string.mediaSize_japanese_jis_b2, 20276, 28661);
+        /** Japanese JIS B1 media size: 728mm x 1030mm (28.661" x 40.551") */
+        public static final MediaSize JIS_B1 =
+                new MediaSize("JIS_B1", "android",
+                        R.string.mediaSize_japanese_jis_b1, 28661, 40551);
+        /** Japanese JIS B0 media size: 1030mm x 1456mm (40.551" x 57.323") */
+        public static final MediaSize JIS_B0 =
+                new MediaSize("JIS_B0", "android",
+                        R.string.mediaSize_japanese_jis_b0, 40551, 57323);
+
+        /** Japanese JIS Exec media size: 216mm x 330mm (8.504" x 12.992") */
+        public static final MediaSize JIS_EXEC =
+                new MediaSize("JIS_EXEC", "android",
+                        R.string.mediaSize_japanese_jis_exec, 8504, 12992);
+
+        /** Japanese Chou4 media size: 90mm x 205mm (3.543" x 8.071") */
+        public static final MediaSize JPN_CHOU4 =
+                new MediaSize("JPN_CHOU4", "android",
+                        R.string.mediaSize_japanese_chou4, 3543, 8071);
+        /** Japanese Chou3 media size: 120mm x 235mm (4.724" x 9.252") */
+        public static final MediaSize JPN_CHOU3 =
+                new MediaSize("JPN_CHOU3", "android",
+                        R.string.mediaSize_japanese_chou3, 4724, 9252);
+        /** Japanese Chou2 media size: 111.1mm x 146mm (4.374" x 5.748") */
+        public static final MediaSize JPN_CHOU2 =
+                new MediaSize("JPN_CHOU2", "android",
+                        R.string.mediaSize_japanese_chou2, 4374, 5748);
+
+        /** Japanese Hagaki media size: 100mm x 148mm (3.937" x 5.827") */
+        public static final MediaSize JPN_HAGAKI =
+                new MediaSize("JPN_HAGAKI", "android",
+                        R.string.mediaSize_japanese_hagaki, 3937, 5827);
+        /** Japanese Oufuku media size: 148mm x 200mm (5.827" x 7.874") */
+        public static final MediaSize JPN_OUFUKU =
+                new MediaSize("JPN_OUFUKU", "android",
+                        R.string.mediaSize_japanese_oufuku, 5827, 7874);
+
+        /** Japanese Kahu media size: 240mm x 322.1mm (9.449" x 12.681") */
+        public static final MediaSize JPN_KAHU =
+                new MediaSize("JPN_KAHU", "android",
+                        R.string.mediaSize_japanese_kahu, 9449, 12681);
+        /** Japanese Kaku2 media size: 240mm x 332mm (9.449" x 13.071") */
+        public static final MediaSize JPN_KAKU2 =
+                new MediaSize("JPN_KAKU2", "android",
+                        R.string.mediaSize_japanese_kaku2, 9449, 13071);
+
+        /** Japanese You4 media size: 105mm x 235mm (4.134" x 9.252") */
+        public static final MediaSize JPN_YOU4 =
+                new MediaSize("JPN_YOU4", "android",
+                        R.string.mediaSize_japanese_you4, 4134, 9252);
 
         private final String mId;
         /**@hide */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c8312e3..6c6635d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4355,6 +4355,12 @@
         public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
 
         /**
+         * Specifies the package name currently configured to be the primary sms application
+         * @hide
+         */
+        public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
+
+        /**
          * Name of a package that the current user has explicitly allowed to see all of that
          * user's notifications.
          *
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index ba6f1d4..30bb447 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -56,7 +56,7 @@
                     if (event.getAction() == KeyEvent.ACTION_DOWN
                             && event.getRepeatCount() == 0
                             && MetaKeyKeyListener.getMetaState(buffer,
-                                        MetaKeyKeyListener.META_SELECTING, event) != 0) {
+                                        MetaKeyKeyListener.META_SELECTING) != 0) {
                         return widget.showContextMenu();
                     }
                 }
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 63607fa..4fede32 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -75,7 +75,7 @@
         }
 
         // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
-        if (getMetaState(content, META_ALT_ON, event) == 1) {
+        if (event.isAltPressed() || getMetaState(content, META_ALT_ON) == 1) {
             if (deleteLine(view, content)) {
                 return true;
             }
diff --git a/core/java/android/text/method/BaseMovementMethod.java b/core/java/android/text/method/BaseMovementMethod.java
index 155a2c4..113a4be 100644
--- a/core/java/android/text/method/BaseMovementMethod.java
+++ b/core/java/android/text/method/BaseMovementMethod.java
@@ -135,7 +135,7 @@
      */
     protected int getMovementMetaState(Spannable buffer, KeyEvent event) {
         // We ignore locked modifiers and SHIFT.
-        int metaState = MetaKeyKeyListener.getMetaState(buffer, event)
+        int metaState = (event.getMetaState() | MetaKeyKeyListener.getMetaState(buffer))
                 & ~(MetaKeyKeyListener.META_ALT_LOCKED | MetaKeyKeyListener.META_SYM_LOCKED);
         return KeyEvent.normalizeMetaState(metaState) & ~KeyEvent.META_SHIFT_MASK;
     }
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index bb8b0de..ce51fae 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -53,7 +53,7 @@
      * from the KeyEvent.
      */
     protected int lookup(KeyEvent event, Spannable content) {
-        int meta = getMetaState(content, event);
+        int meta = event.getMetaState() | getMetaState(content);
         int number = event.getNumber();
 
         /*
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e9db5fd..5ebb957 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -163,29 +163,6 @@
                getActive(text, SELECTING, META_SELECTING, META_SELECTING);
     }
 
-    /**
-     * Gets the state of the meta keys for a specific key event.
-     *
-     * For input devices that use toggled key modifiers, the `toggled' state
-     * is stored into the text buffer. This method retrieves the meta state
-     * for this event, accounting for the stored state. If the event has been
-     * created by a device that does not support toggled key modifiers, like
-     * a virtual device for example, the stored state is ignored.
-     *
-     * @param text the buffer in which the meta key would have been pressed.
-     * @param event the event for which to evaluate the meta state.
-     * @return an integer in which each bit set to one represents a pressed
-     *         or locked meta key.
-     */
-    public static final int getMetaState(final CharSequence text, final KeyEvent event) {
-        int metaState = event.getMetaState();
-        if (event.getKeyCharacterMap().getModifierBehavior()
-                == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
-            metaState |= getMetaState(text);
-        }
-        return metaState;
-    }
-
     // As META_SELECTING is @hide we should not mention it in public comments, hence the
     // omission in @param meta
     /**
@@ -215,37 +192,6 @@
         }
     }
 
-    /**
-     * Gets the state of a particular meta key to use with a particular key event.
-     *
-     * If the key event has been created by a device that does not support toggled
-     * key modifiers, like a virtual keyboard for example, only the meta state in
-     * the key event is considered.
-     *
-     * @param meta META_SHIFT_ON, META_ALT_ON, META_SYM_ON
-     * @param text the buffer in which the meta key would have been pressed.
-     * @param event the event for which to evaluate the meta state.
-     * @return 0 if inactive, 1 if active, 2 if locked.
-     */
-    public static final int getMetaState(final CharSequence text, final int meta,
-            final KeyEvent event) {
-        int metaState = event.getMetaState();
-        if (event.getKeyCharacterMap().getModifierBehavior()
-                == KeyCharacterMap.MODIFIER_BEHAVIOR_CHORDED_OR_TOGGLED) {
-            metaState |= getMetaState(text);
-        }
-        if (META_SELECTING == meta) {
-            // #getMetaState(long, int) does not support META_SELECTING, but we want the same
-            // behavior as #getMetaState(CharSequence, int) so we need to do it here
-            if ((metaState & META_SELECTING) != 0) {
-                // META_SELECTING is only ever set to PRESSED and can't be LOCKED, so return 1
-                return 1;
-            }
-            return 0;
-        }
-        return getMetaState(metaState, meta);
-    }
-
     private static int getActive(CharSequence text, Object meta,
                                  int on, int lock) {
         if (!(text instanceof Spanned)) {
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 988d566..5d4c732 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -41,7 +41,7 @@
     protected abstract char[] getAcceptedChars();
 
     protected int lookup(KeyEvent event, Spannable content) {
-        return event.getMatch(getAcceptedChars(), getMetaState(content, event));
+        return event.getMatch(getAcceptedChars(), event.getMetaState() | getMetaState(content));
     }
 
     public CharSequence filter(CharSequence source, int start, int end,
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 0bd46bc..98316ae 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -108,7 +108,7 @@
 
         // QWERTY keyboard normal case
 
-        int i = event.getUnicodeChar(getMetaState(content, event));
+        int i = event.getUnicodeChar(event.getMetaState() | getMetaState(content));
 
         if (!mFullKeyboard) {
             int count = event.getRepeatCount();
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index 4cc2c42..5f948bd 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -41,7 +41,6 @@
     private static boolean DBG = Transition.DBG && false;
 
     private static final String LOG_TAG = "Fade";
-    private static final String PROPNAME_ALPHA = "android:fade:alpha";
     private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
     private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";
 
@@ -90,7 +89,8 @@
             }
             return null;
         }
-        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", startAlpha,
+                endAlpha);
         if (DBG) {
             Log.d(LOG_TAG, "Created animator " + anim);
         }
@@ -102,8 +102,6 @@
     }
 
     private void captureValues(TransitionValues transitionValues) {
-        float alpha = transitionValues.view.getAlpha();
-        transitionValues.values.put(PROPNAME_ALPHA, alpha);
         int[] loc = new int[2];
         transitionValues.view.getLocationOnScreen(loc);
         transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
@@ -116,29 +114,6 @@
         captureValues(transitionValues);
     }
 
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        super.captureEndValues(transitionValues);
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
-        if (animator == null && startValues != null && endValues != null) {
-            boolean endVisible = isVisible(endValues);
-            final View endView = endValues.view;
-            float endAlpha = endView.getAlpha();
-            float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
-            if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
-                    (!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
-                animator = createAnimation(endView, startAlpha, endAlpha, null);
-            }
-        }
-        return animator;
-    }
-
     @Override
     public Animator onAppear(ViewGroup sceneRoot,
             TransitionValues startValues, int startVisibility,
@@ -152,40 +127,37 @@
             Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
                     startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
         }
-        // if alpha < 1, just fade it in from the current value
-        if (endView.getAlpha() == 1.0f) {
-            endView.setAlpha(0);
-            TransitionListener transitionListener = new TransitionListenerAdapter() {
-                boolean mCanceled = false;
-                float mPausedAlpha;
+        endView.setTransitionAlpha(0);
+        TransitionListener transitionListener = new TransitionListenerAdapter() {
+            boolean mCanceled = false;
+            float mPausedAlpha;
 
-                @Override
-                public void onTransitionCancel(Transition transition) {
-                    endView.setAlpha(1);
-                    mCanceled = true;
-                }
+            @Override
+            public void onTransitionCancel(Transition transition) {
+                endView.setTransitionAlpha(1);
+                mCanceled = true;
+            }
 
-                @Override
-                public void onTransitionEnd(Transition transition) {
-                    if (!mCanceled) {
-                        endView.setAlpha(1);
-                    }
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                if (!mCanceled) {
+                    endView.setTransitionAlpha(1);
                 }
+            }
 
-                @Override
-                public void onTransitionPause(Transition transition) {
-                    mPausedAlpha = endView.getAlpha();
-                    endView.setAlpha(1);
-                }
+            @Override
+            public void onTransitionPause(Transition transition) {
+                mPausedAlpha = endView.getTransitionAlpha();
+                endView.setTransitionAlpha(1);
+            }
 
-                @Override
-                public void onTransitionResume(Transition transition) {
-                    endView.setAlpha(mPausedAlpha);
-                }
-            };
-            addListener(transitionListener);
-        }
-        return createAnimation(endView, endView.getAlpha(), 1, null);
+            @Override
+            public void onTransitionResume(Transition transition) {
+                endView.setTransitionAlpha(mPausedAlpha);
+            }
+        };
+        addListener(transitionListener);
+        return createAnimation(endView, 0, 1, null);
     }
 
     @Override
@@ -236,7 +208,7 @@
             overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
             sceneRoot.getOverlay().add(overlayView);
             // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = view.getAlpha();
+            final float startAlpha = 1;
             float endAlpha = 0;
             final View finalView = view;
             final View finalOverlayView = overlayView;
@@ -245,7 +217,7 @@
             final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    finalView.setAlpha(startAlpha);
+                    finalView.setTransitionAlpha(startAlpha);
                     // TODO: restore view offset from overlay repositioning
                     if (finalViewToKeep != null) {
                         finalViewToKeep.setVisibility(finalVisibility);
@@ -276,7 +248,7 @@
             // VISIBLE for the duration of the transition
             viewToKeep.setVisibility((View.VISIBLE));
             // TODO: add automatic facility to Visibility superclass for keeping views around
-            final float startAlpha = view.getAlpha();
+            final float startAlpha = 1;
             float endAlpha = 0;
             final View finalView = view;
             final View finalOverlayView = overlayView;
@@ -291,8 +263,8 @@
                     if (finalViewToKeep != null && !mCanceled) {
                         finalViewToKeep.setVisibility(finalVisibility);
                     }
-                    mPausedAlpha = finalView.getAlpha();
-                    finalView.setAlpha(startAlpha);
+                    mPausedAlpha = finalView.getTransitionAlpha();
+                    finalView.setTransitionAlpha(startAlpha);
                 }
 
                 @Override
@@ -300,21 +272,21 @@
                     if (finalViewToKeep != null && !mCanceled) {
                         finalViewToKeep.setVisibility(View.VISIBLE);
                     }
-                    finalView.setAlpha(mPausedAlpha);
+                    finalView.setTransitionAlpha(mPausedAlpha);
                 }
 
                 @Override
                 public void onAnimationCancel(Animator animation) {
                     mCanceled = true;
                     if (mPausedAlpha >= 0) {
-                        finalView.setAlpha(mPausedAlpha);
+                        finalView.setTransitionAlpha(mPausedAlpha);
                     }
                 }
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     if (!mCanceled) {
-                        finalView.setAlpha(startAlpha);
+                        finalView.setTransitionAlpha(startAlpha);
                     }
                     // TODO: restore view offset from overlay repositioning
                     if (finalViewToKeep != null && !mCanceled) {
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 60b4708..4a99153 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -353,7 +353,7 @@
                 if (endValues.viewValues.get(view) != null) {
                     end = endValues.viewValues.get(view);
                     endCopy.remove(view);
-                } else {
+                } else if (id != View.NO_ID) {
                     end = endValues.idValues.get(id);
                     View removeView = null;
                     for (View viewToRemove : endCopy.keySet()) {
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index f72b36e..6fdd309 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -354,7 +354,7 @@
         clone.mTransitions = new ArrayList<Transition>();
         int numTransitions = mTransitions.size();
         for (int i = 0; i < numTransitions; ++i) {
-            clone.mTransitions.add((Transition) mTransitions.get(i).clone());
+            clone.addTransition((Transition) mTransitions.get(i).clone());
         }
         return clone;
     }
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index a0d39ca..f36c78f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -130,7 +130,7 @@
     private float mFocusX;
     private float mFocusY;
 
-    private boolean mDoubleTapScales;
+    private boolean mQuickScaleEnabled;
 
     private float mCurrSpan;
     private float mPrevSpan;
@@ -307,7 +307,7 @@
         final int action = event.getActionMasked();
 
         // Forward the event to check for double tap gesture
-        if (mDoubleTapScales) {
+        if (mQuickScaleEnabled) {
             mGestureDetector.onTouchEvent(event);
         }
 
@@ -456,8 +456,8 @@
      * @param scales true to enable quick scaling, false to disable
      */
     public void setQuickScaleEnabled(boolean scales) {
-        mDoubleTapScales = scales;
-        if (mDoubleTapScales && mGestureDetector == null) {
+        mQuickScaleEnabled = scales;
+        if (mQuickScaleEnabled && mGestureDetector == null) {
             GestureDetector.SimpleOnGestureListener gestureListener =
                     new GestureDetector.SimpleOnGestureListener() {
                         @Override
@@ -472,6 +472,14 @@
         }
     }
 
+  /**
+   * Return whether the quick scale gesture, in which the user performs a double tap followed by a
+   * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}.
+   */
+    public boolean isQuickScaleEnabled() {
+        return mQuickScaleEnabled;
+    }
+
     /**
      * Returns {@code true} if a scale gesture is in progress.
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a5db6ee..4680e76 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2894,6 +2894,13 @@
          */
         @ViewDebug.ExportedProperty
         float mAlpha = 1f;
+
+        /**
+         * The opacity of the view as manipulated by the Fade transition. This is a hidden
+         * property only used by transitions, which is composited with the other alpha
+         * values to calculate the final visual alpha value.
+         */
+        float mTransitionAlpha = 1f;
     }
 
     TransformationInfo mTransformationInfo;
@@ -5335,7 +5342,8 @@
                 View view = (View) current;
                 // We have attach info so this view is attached and there is no
                 // need to check whether we reach to ViewRootImpl on the way up.
-                if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) {
+                if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
+                        view.getVisibility() != VISIBLE) {
                     return false;
                 }
                 current = view.mParent;
@@ -9786,7 +9794,7 @@
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9813,7 +9821,7 @@
             } else {
                 mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 if (mDisplayList != null) {
-                    mDisplayList.setAlpha(alpha);
+                    mDisplayList.setAlpha(getFinalAlpha());
                 }
             }
         }
@@ -9821,6 +9829,51 @@
     }
 
     /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public void setTransitionAlpha(float alpha) {
+        ensureTransformationInfo();
+        if (mTransformationInfo.mTransitionAlpha != alpha) {
+            mTransformationInfo.mTransitionAlpha = alpha;
+            mPrivateFlags &= ~PFLAG_ALPHA_SET;
+            invalidateViewProperty(true, false);
+            if (mDisplayList != null) {
+                mDisplayList.setAlpha(getFinalAlpha());
+            }
+        }
+    }
+
+    /**
+     * Calculates the visual alpha of this view, which is a combination of the actual
+     * alpha value and the transitionAlpha value (if set).
+     */
+    private float getFinalAlpha() {
+        if (mTransformationInfo != null) {
+            return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
+        }
+        return 1;
+    }
+
+    /**
+     * This property is hidden and intended only for use by the Fade transition, which
+     * animates it to produce a visual translucency that does not side-effect (or get
+     * affected by) the real alpha property. This value is composited with the other
+     * alpha value (and the AlphaAnimation value, when that is present) to produce
+     * a final visual translucency result, which is what is passed into the DisplayList.
+     *
+     * @hide
+     */
+    public float getTransitionAlpha() {
+        return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
+    }
+
+    /**
      * Top position of this view relative to its parent.
      *
      * @return The top of this view, in pixels.
@@ -10913,7 +10966,7 @@
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
         return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
-                ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
+                getFinalAlpha() >= 1.0f;
     }
 
     /**
@@ -13868,7 +13921,7 @@
                 }
             }
             if (mTransformationInfo != null) {
-                alpha *= mTransformationInfo.mAlpha;
+                alpha *= getFinalAlpha();
                 if (alpha < 1) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (onSetAlpha(multipliedAlpha)) {
@@ -14057,8 +14110,8 @@
             }
         }
 
-        float alpha = useDisplayListProperties ? 1 : getAlpha();
-        if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
+        float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
+        if (transformToApply != null || alpha < 1 ||  !hasIdentityMatrix() ||
                 (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
@@ -14115,7 +14168,7 @@
                             layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                         }
                         if (useDisplayListProperties) {
-                            displayList.setAlpha(alpha * getAlpha());
+                            displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else  if (layerType == LAYER_TYPE_NONE) {
                             final int scrollX = hasDisplayList ? 0 : sx;
                             final int scrollY = hasDisplayList ? 0 : sy;
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index ad8b51d..f9298ea 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -990,10 +990,10 @@
             mStart = false;
             if (mDataCopy != null) {
                 mData = mDataCopy;
+                mAccess.mData.clear();
+                mAccess.mSize = 0;
             }
             mDataCopy = null;
-            mAccess.mData.clear();
-            mAccess.mSize = 0;
         }
 
         int size() {
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
     * @param totalQuota The total quota for all origins, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onExceededDatabaseQuota(String url, String databaseIdentifier,
             long quota, long estimatedDatabaseSize, long totalQuota,
             WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
     * @param quota the current maximum Application Cache size, in bytes
     * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
     *                     must be used to inform the WebView of the new quota.
+    * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+    *             Management API.
     */
-    // Note that the callback must always be executed at some point to ensure
-    // that the sleeping WebCore thread is woken up.
+    @Deprecated
     public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
             WebStorage.QuotaUpdater quotaUpdater) {
         quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7a38a16..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
     /**
      * Enum for controlling the layout of html.
      * <ul>
-     *   <li>NORMAL means no rendering changes.</li>
+     *   <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+     *       compatibility across different platforms and Android versions.</li>
      *   <li>SINGLE_COLUMN moves all content into one column that is the width of the
      *       view.</li>
-     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+     *   <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+     *       this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
      *   <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
      *       the text readable when viewing a wide-viewport layout in the overview mode.
      *       It is recommended to enable zoom support {@link #setSupportZoom} when
-     *       using this mode.</li>
+     *       using this mode. Supported from API level
+     *       {@link android.os.Build.VERSION_CODES#KITKAT}</li>
      * </ul>
      */
     // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
          */
         @Deprecated
         SINGLE_COLUMN,
-        NARROW_COLUMNS,
         /**
-         * @hide
+         * @deprecated This algorithm is now obsolete.
          */
+        @Deprecated
+        NARROW_COLUMNS,
         TEXT_AUTOSIZING
     }
 
@@ -510,7 +514,10 @@
      * and {@link #setUseWideViewPort} can be used.
      *
      * @param zoom the zoom density
+     * @deprecated This method is no longer supported, see the function documentation for
+     *             recommended alternatives.
      */
+    @Deprecated
     public void setDefaultZoom(ZoomDensity zoom) {
         throw new MustOverrideException();
     }
@@ -523,6 +530,7 @@
      *
      * @return the zoom density
      * @see #setDefaultZoom
+     * @deprecated Will only return the default value.
      */
     public ZoomDensity getDefaultZoom() {
         throw new MustOverrideException();
@@ -1059,10 +1067,13 @@
      *
      * @param databasePath a path to the directory where databases should be
      *                     saved.
+     * @deprecated Database paths are managed by the implementation and calling this method
+     *             will have no effect.
      */
     // This will update WebCore when the Sync runs in the C++ side.
     // Note that the WebCore Database Tracker only allows the path to be set
     // once.
+    @Deprecated
     public synchronized void setDatabasePath(String databasePath) {
         throw new MustOverrideException();
     }
@@ -1161,7 +1172,9 @@
      *
      * @return the String path to the database storage API databases
      * @see #setDatabasePath
+     * @deprecated Database paths are managed by the implementation this method is obsolete.
      */
+    @Deprecated
     public synchronized String getDatabasePath() {
         throw new MustOverrideException();
     }
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
      * See
      * {@link WebChromeClient#onExceededDatabaseQuota} and
      * {@link WebChromeClient#onReachedMaxAppCacheSize}.
+     * @deprecated This class is obsolete and no longer used.
      */
-    // We primarily want this to allow us to call back the sleeping WebCore
-    // thread from outside the WebViewCore class (as the native call is
-    // private). It is imperative that the setDatabaseQuota method is
-    // executed after a decision to either allow or deny new quota is made,
-    // otherwise the WebCore thread will remain asleep.
+    @Deprecated
     public interface QuotaUpdater {
         /**
          * Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 15331dc..20fb1a7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1058,9 +1058,20 @@
      * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
      * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
      * picture does not include fixed position elements or scrollable divs.
+     * <p>
+     * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+     * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+     * additional conversion at a cost in memory and performance. Also the
+     * {@link android.graphics.Picture#createFromStream} and
+     * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+     * returned object.
+     *
+     * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+     * {@link #saveWebArchive} to save the content to a file.
      *
      * @return a picture that captures the current contents of this WebView
      */
+    @Deprecated
     public Picture capturePicture() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
@@ -1342,7 +1353,10 @@
     /**
      * Informs this WebView that memory is low so that it can free any available
      * memory.
+     * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+     *             to system memory pressure.
      */
+    @Deprecated
     public void freeMemory() {
         checkThread();
         if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index de2be75..0957ab4 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -391,7 +391,7 @@
         mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                 UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics);
 
-        LayoutInflater layoutInflater = (LayoutInflater) mContext
+        LayoutInflater layoutInflater = (LayoutInflater) context
                 .getSystemService(Service.LAYOUT_INFLATER_SERVICE);
         View content = layoutInflater.inflate(R.layout.calendar_view, null, false);
         addView(content);
@@ -874,7 +874,6 @@
         }
         mFirstDayOfWeek = firstDayOfWeek;
         mAdapter.init();
-        mAdapter.notifyDataSetChanged();
         setUpHeader();
     }
 
@@ -937,7 +936,7 @@
     }
 
     private void updateDateTextSize() {
-        TypedArray dateTextAppearance = getContext().obtainStyledAttributes(
+        TypedArray dateTextAppearance = mContext.obtainStyledAttributes(
                 mDateTextAppearanceResId, R.styleable.TextAppearance);
         mDateTextSize = dateTextAppearance.getDimensionPixelSize(
                 R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
@@ -1004,7 +1003,7 @@
      */
     private void setUpAdapter() {
         if (mAdapter == null) {
-            mAdapter = new WeeksAdapter(getContext());
+            mAdapter = new WeeksAdapter();
             mAdapter.registerDataSetObserver(new DataSetObserver() {
                 @Override
                 public void onChanged() {
@@ -1333,19 +1332,16 @@
      * </p>
      */
     private class WeeksAdapter extends BaseAdapter implements OnTouchListener {
+        private final Calendar mSelectedDate = Calendar.getInstance();
+        private final GestureDetector mGestureDetector;
 
         private int mSelectedWeek;
 
-        private GestureDetector mGestureDetector;
-
         private int mFocusedMonth;
 
-        private final Calendar mSelectedDate = Calendar.getInstance();
-
         private int mTotalWeekCount;
 
-        public WeeksAdapter(Context context) {
-            mContext = context;
+        public WeeksAdapter() {
             mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener());
             init();
         }
@@ -1360,6 +1356,7 @@
                 || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) {
                 mTotalWeekCount++;
             }
+            notifyDataSetChanged();
         }
 
         /**
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 19cc3c2..e4956dd 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1099,6 +1099,16 @@
     }
 
     @Override
+    public int computeVerticalScrollOffset() {
+        return mCurrentScrollOffset;
+    }
+
+    @Override
+    public int computeVerticalScrollRange() {
+        return mSelectorIndices.length * mSelectorElementHeight;
+    }
+
+    @Override
     public int getSolidColor() {
         return mSolidColor;
     }
diff --git a/core/java/com/android/internal/app/IProcessStats.aidl b/core/java/com/android/internal/app/IProcessStats.aidl
index 047424d..6fadf2f 100644
--- a/core/java/com/android/internal/app/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/IProcessStats.aidl
@@ -22,5 +22,6 @@
 
 interface IProcessStats {
     byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
+    ParcelFileDescriptor getStatsOverTime(long minTime);
     int getCurrentMemoryState();
 }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index d3fe34e..1475e2c 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -166,7 +166,7 @@
     static final String CSV_SEP = "\t";
 
     // Current version of the parcel format.
-    private static final int PARCEL_VERSION = 11;
+    private static final int PARCEL_VERSION = 12;
     // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
     private static final int MAGIC = 0x50535453;
 
@@ -1076,10 +1076,8 @@
         return table;
     }
 
-    private void writeCompactedLongArray(Parcel out, long[] array) {
-        final int N = array.length;
-        out.writeInt(N);
-        for (int i=0; i<N; i++) {
+    private void writeCompactedLongArray(Parcel out, long[] array, int num) {
+        for (int i=0; i<num; i++) {
             long val = array[i];
             if (val < 0) {
                 Slog.w(TAG, "Time val negative: " + val);
@@ -1096,16 +1094,17 @@
         }
     }
 
-    private void readCompactedLongArray(Parcel in, int version, long[] array) {
+    private void readCompactedLongArray(Parcel in, int version, long[] array, int num) {
         if (version <= 10) {
             in.readLongArray(array);
             return;
         }
-        final int N = in.readInt();
-        if (N != array.length) {
-            throw new RuntimeException("bad array lengths");
+        final int alen = array.length;
+        if (num > alen) {
+            throw new RuntimeException("bad array lengths: got " + num + " array is " + alen);
         }
-        for (int i=0; i<N; i++) {
+        int i;
+        for (i=0; i<num; i++) {
             int val = in.readInt();
             if (val >= 0) {
                 array[i] = val;
@@ -1114,6 +1113,10 @@
                 array[i] = (((long)~val)<<32) | bottom;
             }
         }
+        while (i < alen) {
+            array[i] = 0;
+            i++;
+        }
     }
 
     private void writeCommonString(Parcel out, String name) {
@@ -1203,19 +1206,17 @@
         out.writeInt(mLongs.size());
         out.writeInt(mNextLong);
         for (int i=0; i<(mLongs.size()-1); i++) {
-            writeCompactedLongArray(out, mLongs.get(i));
+            long[] array = mLongs.get(i);
+            writeCompactedLongArray(out, array, array.length);
         }
         long[] lastLongs = mLongs.get(mLongs.size() - 1);
-        for (int i=0; i<mNextLong; i++) {
-            out.writeLong(lastLongs[i]);
-            if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]);
-        }
+        writeCompactedLongArray(out, lastLongs, mNextLong);
 
         if (mMemFactor != STATE_NOTHING) {
             mMemFactorDurations[mMemFactor] += now - mStartTime;
             mStartTime = now;
         }
-        writeCompactedLongArray(out, mMemFactorDurations);
+        writeCompactedLongArray(out, mMemFactorDurations, mMemFactorDurations.length);
 
         out.writeInt(NPROC);
         for (int ip=0; ip<NPROC; ip++) {
@@ -1276,23 +1277,25 @@
         return true;
     }
 
-    static byte[] readFully(InputStream stream) throws IOException {
+    static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
         int pos = 0;
-        int avail = stream.available();
-        byte[] data = new byte[avail];
+        final int initialAvail = stream.available();
+        byte[] data = new byte[initialAvail > 0 ? (initialAvail+1) : 16384];
         while (true) {
             int amt = stream.read(data, pos, data.length-pos);
-            //Log.i("foo", "Read " + amt + " bytes at " + pos
-            //        + " of avail " + data.length);
-            if (amt <= 0) {
-                //Log.i("foo", "**** FINISHED READING: pos=" + pos
-                //        + " len=" + data.length);
+            if (DEBUG) Slog.i("foo", "Read " + amt + " bytes at " + pos
+                    + " of avail " + data.length);
+            if (amt < 0) {
+                if (DEBUG) Slog.i("foo", "**** FINISHED READING: pos=" + pos
+                        + " len=" + data.length);
+                outLen[0] = pos;
                 return data;
             }
             pos += amt;
-            avail = stream.available();
-            if (avail > data.length-pos) {
-                byte[] newData = new byte[pos+avail];
+            if (pos >= data.length) {
+                byte[] newData = new byte[pos+16384];
+                if (DEBUG) Slog.i(TAG, "Copying " + pos + " bytes to new array len "
+                        + newData.length);
                 System.arraycopy(data, 0, newData, 0, pos);
                 data = newData;
             }
@@ -1301,9 +1304,10 @@
 
     public void read(InputStream stream) {
         try {
-            byte[] raw = readFully(stream);
+            int[] len = new int[1];
+            byte[] raw = readFully(stream, len);
             Parcel in = Parcel.obtain();
-            in.unmarshall(raw, 0, raw.length);
+            in.unmarshall(raw, 0, len[0]);
             in.setDataPosition(0);
             stream.close();
 
@@ -1358,17 +1362,14 @@
             while (i >= mLongs.size()) {
                 mLongs.add(new long[LONGS_SIZE]);
             }
-            readCompactedLongArray(in, version, mLongs.get(i));
+            readCompactedLongArray(in, version, mLongs.get(i), LONGS_SIZE);
         }
         long[] longs = new long[LONGS_SIZE];
         mNextLong = NEXTLONG;
-        for (int i=0; i<NEXTLONG; i++) {
-            longs[i] = in.readLong();
-            if (DEBUG) Slog.d(TAG, "Reading last long #" + i + ": " + longs[i]);
-        }
+        readCompactedLongArray(in, version, longs, NEXTLONG);
         mLongs.add(longs);
 
-        readCompactedLongArray(in, version, mMemFactorDurations);
+        readCompactedLongArray(in, version, mMemFactorDurations, mMemFactorDurations.length);
 
         int NPROC = in.readInt();
         if (NPROC < 0) {
@@ -1669,7 +1670,8 @@
         return ss;
     }
 
-    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) {
+    public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
+            boolean dumpAll) {
         long totalTime = dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
                 mStartTime, now);
         ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
@@ -1693,7 +1695,7 @@
                     pw.print("  * "); pw.print(pkgName); pw.print(" / ");
                             UserHandle.formatUid(pw, uid); pw.println(":");
                 }
-                if (dumpAll) {
+                if (!dumpSummary || dumpAll) {
                     for (int iproc=0; iproc<NPROCS; iproc++) {
                         ProcessState proc = pkgState.mProcesses.valueAt(iproc);
                         pw.print("      Process ");
@@ -1730,16 +1732,16 @@
                     ServiceState svc = pkgState.mServices.valueAt(isvc);
                     dumpServiceStats(pw, "        ", "          ", "    ", "Running", svc,
                             svc.mRunCount, ServiceState.SERVICE_RUN, svc.mRunState,
-                            svc.mRunStartTime, now, totalTime, dumpAll);
+                            svc.mRunStartTime, now, totalTime, !dumpSummary || dumpAll);
                     dumpServiceStats(pw, "        ", "          ", "    ", "Started", svc,
                             svc.mStartedCount, ServiceState.SERVICE_STARTED, svc.mStartedState,
-                            svc.mStartedStartTime, now, totalTime, dumpAll);
+                            svc.mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
                     dumpServiceStats(pw, "        ", "          ", "      ", "Bound", svc,
                             svc.mBoundCount, ServiceState.SERVICE_BOUND, svc.mBoundState,
-                            svc.mBoundStartTime, now, totalTime, dumpAll);
+                            svc.mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
                     dumpServiceStats(pw, "        ", "          ", "  ", "Executing", svc,
                             svc.mExecCount, ServiceState.SERVICE_EXEC, svc.mExecState,
-                            svc.mExecStartTime, now, totalTime, dumpAll);
+                            svc.mExecStartTime, now, totalTime, !dumpSummary || dumpAll);
                     if (dumpAll) {
                         pw.print("        mActive="); pw.println(svc.mActive);
                     }
@@ -1783,8 +1785,12 @@
             }
 
             pw.println();
-            pw.println("Summary:");
-            dumpSummaryLocked(pw, reqPackage, now);
+            if (dumpSummary) {
+                pw.println("Summary:");
+                dumpSummaryLocked(pw, reqPackage, now);
+            } else {
+                dumpTotalsLocked(pw, now);
+            }
         } else {
             pw.println();
             dumpTotalsLocked(pw, now);
@@ -2514,7 +2520,7 @@
         private ProcessState pullFixedProc(ArrayMap<String, ProcessState> pkgList, int index) {
             ProcessState proc = pkgList.valueAt(index);
             if (mDead && proc.mCommonProcess != proc) {
-                // Somehow we try to continue to use a process state that is dead, because
+                // Somehow we are contining to use a process state that is dead, because
                 // it was not being told it was active during the last commit.  We can recover
                 // from this by generating a fresh new state, but this is bad because we
                 // are losing whatever data we had in the old process state.
@@ -2529,7 +2535,7 @@
                 PackageState pkg = mStats.mPackages.get(pkgList.keyAt(index), proc.mUid);
                 if (pkg == null) {
                     throw new IllegalStateException("No existing package "
-                            + pkgList.keyAt(index) + " for multi-proc" + proc.mName);
+                            + pkgList.keyAt(index) + " for multi-proc " + proc.mName);
                 }
                 proc = pkg.mProcesses.get(proc.mName);
                 if (proc == null) {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 969c94ba..7efcb6e 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1639,6 +1639,8 @@
 
         @Override
         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
             mExpandedActionView = item.getActionView();
             mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
             mCurrentExpandedItem = item;
@@ -1666,6 +1668,8 @@
 
         @Override
         public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            TransitionManager.beginDelayedTransition(ActionBarView.this, sTransition);
+
             // Do this before detaching the actionview from the hierarchy, in case
             // it needs to dismiss the soft keyboard, etc.
             if (mExpandedActionView instanceof CollapsibleActionView) {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index f9bb233..9c20de2 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -3,6 +3,7 @@
 #include "BitmapFactory.h"
 #include "NinePatchPeeker.h"
 #include "SkData.h"
+#include "SkFrontBufferedStream.h"
 #include "SkImageDecoder.h"
 #include "SkImageRef_ashmem.h"
 #include "SkImageRef_GlobalPool.h"
@@ -120,7 +121,7 @@
     }
 }
 
-static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
+static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
         int sampleSize, bool ditherImage) {
 
     SkImageRef* pr;
@@ -465,13 +466,17 @@
         jobject padding, jobject options) {
 
     jobject bitmap = NULL;
-    SkAutoTUnref<SkStreamRewindable> stream(GetRewindableStream(env, is, storage));
+    SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
 
     if (stream.get()) {
+        // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+        // trying to determine the stream's format. Currently the most is 64, read by
+        // SkImageDecoder_libwebp.
+        // FIXME: Get this number from SkImageDecoder
+        SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
+        SkASSERT(bufferedStream.get() != NULL);
         // for now we don't allow purgeable with java inputstreams
-        // FIXME: GetRewindableStream may have made a copy, in which case
-        // purgeable should be allowed.
-        bitmap = doDecode(env, stream, padding, options, false, false);
+        bitmap = doDecode(env, bufferedStream, padding, options, false, false);
     }
     return bitmap;
 }
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index f773f59..da8f083 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -5,18 +5,12 @@
 #include "SkStream.h"
 #include "SkTypes.h"
 #include "Utils.h"
-#include <androidfw/Asset.h>
 
-static jmethodID    gInputStream_resetMethodID;
-static jmethodID    gInputStream_markMethodID;
-static jmethodID    gInputStream_markSupportedMethodID;
 static jmethodID    gInputStream_readMethodID;
 static jmethodID    gInputStream_skipMethodID;
 
-class RewindableJavaStream;
-
 /**
- *  Non-rewindable wrapper for a Java InputStream.
+ *  Wrapper for a Java InputStream.
  */
 class JavaInputStreamAdaptor : public SkStream {
 public:
@@ -64,25 +58,6 @@
     }
 
 private:
-    // Does not override rewind, since a JavaInputStreamAdaptor's interface
-    // does not support rewinding. RewindableJavaStream, which is a friend,
-    // will be able to call this method to rewind.
-    bool doRewind() {
-        JNIEnv* env = fEnv;
-
-        fBytesRead = 0;
-        fIsAtEnd = false;
-
-        env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
-        if (env->ExceptionCheck()) {
-            env->ExceptionDescribe();
-            env->ExceptionClear();
-            SkDebugf("------- reset threw an exception\n");
-            return false;
-        }
-        return true;
-    }
-
     size_t doRead(void* buffer, size_t size) {
         JNIEnv* env = fEnv;
         size_t bytesRead = 0;
@@ -148,9 +123,6 @@
     size_t      fCapacity;
     size_t      fBytesRead;
     bool        fIsAtEnd;
-
-    // Allows access to doRewind and fBytesRead.
-    friend class RewindableJavaStream;
 };
 
 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
@@ -190,123 +162,6 @@
     return adaptor_to_mem_stream(adaptor.get());
 }
 
-/**
- *  Wrapper for a Java InputStream which is rewindable and
- *  has a length.
- */
-class RewindableJavaStream : public SkStreamRewindable {
-public:
-    // RewindableJavaStream takes ownership of adaptor.
-    RewindableJavaStream(JavaInputStreamAdaptor* adaptor, size_t length)
-        : fAdaptor(adaptor)
-        , fLength(length) {
-        SkASSERT(fAdaptor != NULL);
-    }
-
-    virtual ~RewindableJavaStream() {
-        fAdaptor->unref();
-    }
-
-    virtual bool rewind() {
-        return fAdaptor->doRewind();
-    }
-
-    virtual size_t read(void* buffer, size_t size) {
-        return fAdaptor->read(buffer, size);
-    }
-
-    virtual bool isAtEnd() const {
-        return fAdaptor->isAtEnd();
-    }
-
-    virtual size_t getLength() const {
-        return fLength;
-    }
-
-    virtual bool hasLength() const {
-        return true;
-    }
-
-    virtual SkStreamRewindable* duplicate() const {
-        // Duplicating this stream requires rewinding and
-        // reading, which modify this Stream (and could
-        // fail, leaving this one invalid).
-        SkASSERT(false);
-        return NULL;
-    }
-
-private:
-    JavaInputStreamAdaptor* fAdaptor;
-    const size_t            fLength;
-};
-
-static jclass   gByteArrayInputStream_Clazz;
-static jfieldID gCountField;
-static jfieldID gPosField;
-
-/**
- *  If jstream is a ByteArrayInputStream, return its remaining length. Otherwise
- *  return 0.
- */
-static size_t get_length_from_byte_array_stream(JNIEnv* env, jobject jstream) {
-    if (env->IsInstanceOf(jstream, gByteArrayInputStream_Clazz)) {
-        // Return the remaining length, to keep the same behavior of using the rest of the
-        // stream.
-        return env->GetIntField(jstream, gCountField) - env->GetIntField(jstream, gPosField);
-    }
-    return 0;
-}
-
-/**
- *  If jstream is a class that has a length, return it. Otherwise
- *  return 0.
- *  Only checks for a set of subclasses.
- */
-static size_t get_length_if_supported(JNIEnv* env, jobject jstream) {
-    size_t len = get_length_from_byte_array_stream(env, jstream);
-    if (len > 0) {
-        return len;
-    }
-    return 0;
-}
-
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
-                                        jbyteArray storage) {
-    SkAutoTUnref<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
-    if (NULL == adaptor.get()) {
-        return NULL;
-    }
-
-    const size_t length = get_length_if_supported(env, stream);
-    if (length > 0 && env->CallBooleanMethod(stream, gInputStream_markSupportedMethodID)) {
-        // Set the readLimit for mark to the end of the stream, so it can
-        // be rewound regardless of how much has been read.
-        env->CallVoidMethod(stream, gInputStream_markMethodID, length);
-        // RewindableJavaStream will unref adaptor when it is destroyed.
-        return new RewindableJavaStream(static_cast<JavaInputStreamAdaptor*>(adaptor.detach()),
-                                        length);
-    }
-
-    return adaptor_to_mem_stream(adaptor.get());
-}
-
-static jclass       gAssetInputStream_Clazz;
-static jmethodID    gGetAssetIntMethodID;
-
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject jstream) {
-    if (!env->IsInstanceOf(jstream, gAssetInputStream_Clazz)) {
-        return NULL;
-    }
-
-    jint jasset = env->CallIntMethod(jstream, gGetAssetIntMethodID);
-    android::Asset* a = reinterpret_cast<android::Asset*>(jasset);
-    if (NULL == a) {
-        jniThrowNullPointerException(env, "NULL native asset");
-        return NULL;
-    }
-    return new android::AssetStreamAdaptor(a);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static jmethodID    gOutputStream_writeMethodID;
@@ -382,13 +237,6 @@
     return clazz;
 }
 
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
-                                const char fieldname[], const char type[]) {
-    jfieldID id = env->GetFieldID(clazz, fieldname, type);
-    SkASSERT(!env->ExceptionCheck());
-    return id;
-}
-
 static jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
                                   const char methodname[], const char type[]) {
     jmethodID id = env->GetMethodID(clazz, methodname, type);
@@ -398,25 +246,9 @@
 
 int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
     jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
-    gInputStream_resetMethodID = getMethodIDCheck(env, inputStream_Clazz, "reset", "()V");
-    gInputStream_markMethodID = getMethodIDCheck(env, inputStream_Clazz, "mark", "(I)V");
-    gInputStream_markSupportedMethodID = getMethodIDCheck(env, inputStream_Clazz, "markSupported", "()Z");
     gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
     gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
 
-    gByteArrayInputStream_Clazz = findClassCheck(env, "java/io/ByteArrayInputStream");
-    // Ref gByteArrayInputStream_Clazz so we can continue to refer to it when
-    // calling IsInstance.
-    gByteArrayInputStream_Clazz = (jclass) env->NewGlobalRef(gByteArrayInputStream_Clazz);
-    gCountField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "count", "I");
-    gPosField = getFieldIDCheck(env, gByteArrayInputStream_Clazz, "pos", "I");
-
-    gAssetInputStream_Clazz = findClassCheck(env, "android/content/res/AssetManager$AssetInputStream");
-    // Ref gAssetInputStream_Clazz so we can continue to refer to it when
-    // calling IsInstance.
-    gAssetInputStream_Clazz = (jclass) env->NewGlobalRef(gAssetInputStream_Clazz);
-    gGetAssetIntMethodID = getMethodIDCheck(env, gAssetInputStream_Clazz, "getAssetInt", "()I");
-
     jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
     gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
     gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
index fcc0c9a..ecd270f 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h
@@ -4,10 +4,6 @@
 //#include <android_runtime/AndroidRuntime.h>
 #include "jni.h"
 
-namespace android {
-    class AssetStreamAdaptor;
-}
-
 class SkMemoryStream;
 class SkStream;
 class SkStreamRewindable;
@@ -15,6 +11,7 @@
 
 /**
  *  Return an adaptor from a Java InputStream to an SkStream.
+ *  Does not support rewind.
  *  @param env JNIEnv object.
  *  @param stream Pointer to Java InputStream.
  *  @param storage Java byte array for retrieving data from the
@@ -28,7 +25,7 @@
                                        jbyteArray storage);
 
 /**
- *  Copy a Java InputStream.
+ *  Copy a Java InputStream. The result will be rewindable.
  *  @param env JNIEnv object.
  *  @param stream Pointer to Java InputStream.
  *  @param storage Java byte array for retrieving data from the
@@ -39,32 +36,6 @@
 SkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
                                         jbyteArray storage);
 
-/**
- *  Get a rewindable stream from a Java InputStream.
- *  @param env JNIEnv object.
- *  @param stream Pointer to Java InputStream.
- *  @param storage Java byte array for retrieving data from the
- *      Java InputStream.
- *  @return SkStreamRewindable Either a wrapper around the Java
- *      InputStream, if possible, or a copy which is rewindable.
- *      Since it may be a wrapper, must not be used after the
- *      caller returns, like the result of CreateJavaInputStreamAdaptor.
- */
-SkStreamRewindable* GetRewindableStream(JNIEnv* env, jobject stream,
-                                        jbyteArray storage);
-
-/**
- *  If the Java InputStream is an AssetInputStream, return an adaptor.
- *  This should not be used after the calling function returns, since
- *  the caller may close the asset. Returns NULL if the stream is
- *  not an AssetInputStream.
- *  @param env JNIEnv object.
- *  @param stream Pointer to Java InputStream.
- *  @return AssetStreamAdaptor representing the InputStream, or NULL.
- *      Must not be held onto.
- */
-android::AssetStreamAdaptor* CheckForAssetStream(JNIEnv* env, jobject stream);
-
 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
                                          jbyteArray storage);
 #endif
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 2eae841..feb2dec 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -1,4 +1,5 @@
 #include "ScopedLocalRef.h"
+#include "SkFrontBufferedStream.h"
 #include "SkMovie.h"
 #include "SkStream.h"
 #include "GraphicsJNI.h"
@@ -81,23 +82,33 @@
     c->drawBitmap(b, sx, sy, p);
 }
 
+static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jint native_asset) {
+    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
+    if (asset == NULL) return NULL;
+    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset));
+    SkMovie* moov = SkMovie::DecodeStream(stream.get());
+    return create_jmovie(env, moov);
+}
+
 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
 
     NPE_CHECK_RETURN_ZERO(env, istream);
 
-    SkStreamRewindable* strm = CheckForAssetStream(env, istream);
-    jbyteArray byteArray = NULL;
-    ScopedLocalRef<jbyteArray> scoper(env, NULL);
-    if (NULL == strm) {
-        byteArray = env->NewByteArray(16*1024);
-        scoper.reset(byteArray);
-        strm = GetRewindableStream(env, istream, byteArray);
-    }
+    jbyteArray byteArray = env->NewByteArray(16*1024);
+    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
+    SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
     if (NULL == strm) {
         return 0;
     }
 
-    SkMovie* moov = SkMovie::DecodeStream(strm);
+    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
+    // trying to determine the stream's format. The only decoder for movies is GIF, which
+    // will only read 6.
+    // FIXME: Get this number from SkImageDecoder
+    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+    SkASSERT(bufferedStream.get() != NULL);
+
+    SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
     strm->unref();
     return create_jmovie(env, moov);
 }
@@ -135,7 +146,9 @@
     {   "setTime",  "(I)Z", (void*)movie_setTime  },
     {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
                             (void*)movie_draw  },
-    { "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
+    { "nativeDecodeAsset", "(I)Landroid/graphics/Movie;",
+                            (void*)movie_decodeAsset },
+    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
                             (void*)movie_decodeStream },
     { "nativeDestructor","(I)V", (void*)movie_destructor },
     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 499a930..6898ab0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1103,6 +1103,13 @@
         android:description="@string/permdesc_use_sip"
         android:label="@string/permlab_use_sip" />
 
+    <!-- Allows an application to request CallHandlerService implementations. -->
+    <permission android:name="android.permission.BIND_CALL_SERVICE"
+        android:permissionGroup="android.permission-group.PHONE_CALLS"
+        android:protectionLevel="system|signature"
+        android:description="@string/permdesc_bind_call_service"
+        android:label="@string/permlab_bind_call_service" />
+
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
@@ -2100,6 +2107,13 @@
         android:description="@string/permdesc_captureSecureVideoOutput"
         android:protectionLevel="signature|system" />
 
+    <!--@hide Allows an application to know what content is playing and control its playback.
+         <p>Not for use by third-party applications due to privacy of media consumption</p>  -->
+    <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
+        android:label="@string/permlab_mediaContentControl"
+        android:description="@string/permdesc_mediaContentControl"
+        android:protectionLevel="signature|system" />
+
     <!-- Required to be able to disable the device (very dangerous!).
     <p>Not for use by third-party applications.. -->
     <permission android:name="android.permission.BRICK"
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
index 584ce05..7f79718 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
index ed317f7..951be79 100644
--- a/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
index 40bd746..47f7c29 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
index c49bc84..841c964 100644
--- a/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
index 958d023..fd2b63a 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
index 3464f3d..4fa62d7 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
index 3464f3d..242cee9 100644
--- a/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
index 5dc3673..3ffd433 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
index c0d8a3d..6065eb7 100644
--- a/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
index a920132..63ec738 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
index f6a8b45..1d80d5c 100644
--- a/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
index 18c527d..9aed106 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
index 478f2e7..c5e4694 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
index b0be28d..0fe4b14 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
index ec3c748..aaced6e 100644
--- a/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
index a929e09..185f9f7 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
index 013ca85..5d695d9 100644
--- a/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
index 7b0e089..de15a23 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
index 692d705..beda050 100644
--- a/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-hdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
index 677069a..9206f57 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
index 677069a..bef235b 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6b5fa5a..63204eb 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
index 6b5fa5a..7b79f3f 100644
--- a/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..da023d3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..e9afcc9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
index 5654cd6..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
index 5654cd6..e852a45 100644
--- a/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
index e20b02d..1a0bf0d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
index e20b02d..c9e662d 100644
--- a/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 0c689ff..4e40eda 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index f3999204..f1b7036 100644
--- a/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-hdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
index dc20a8d..f06d898 100644
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
index 272a2a1..0638e58 100644
--- a/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
index 84560c5..6d2a8a4 100644
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
index e101d50..bb43a46 100644
--- a/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-hdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
index ea54380..88717cc 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
index ea54380..c759ca4 100644
--- a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
index 6278eef..fe5850c 100644
--- a/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
index aadc6f8..b59edc8 100644
--- a/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
index 9389a08..2eaa6e1 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
index 1109c20..83b3315 100644
--- a/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
index 3a8cebc..2b8541c 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
index e9f5f06..e51e72a 100644
--- a/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
index eb7a1fd..1940216 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
index 7e4eb5e..c10b235 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
index 7e4eb5e..db9eab0 100644
--- a/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
index 194f58e..45252b1 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
index 2a7d0d5..1090816 100644
--- a/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
index dff7c00..a740800 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
index 70c705f..faa95fc 100644
--- a/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
index 5985e3c..bc82b1a 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
index 2085290..ab3a79b 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
index 4b62750..9b169d4 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
index 000a9c4..29ebf09 100644
--- a/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
index 4bc4a30..a703645 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
index dd14aec..42876ce 100644
--- a/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
index 2f1f004..c8ffef4 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
index 4bea36b..8be8533 100644
--- a/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-mdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
index 045dc9a..5e55f6b 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
index 045dc9a..791eda5 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
index 6c4aa16..646ed1c 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
index 6c4aa16..08ea670 100644
--- a/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..d120ab1
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..3226ab7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
index 6e77525..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
index 6e77525..b6427cc 100644
--- a/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
index 13cb131..5f97f2b 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
index 13cb131..779d10e 100644
--- a/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index eee058f..a70615a 100644
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index 1ac24be..e7dd785 100644
--- a/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-mdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
index 2fa15e7..561ac55 100644
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
index a964b22..05ffe3f 100644
--- a/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
index b82d1ac..363531a 100644
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
index f9b5f64..d62c04b 100644
--- a/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-mdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
index 670dc2e..92ba340 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
index 670dc2e..e099458 100644
--- a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
index 155c4fc..cdb7b19 100644
--- a/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
index b1223fe..b27c88d 100644
--- a/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-mdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
index c85f135..ebb439d5 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
index 50461d2..c497bf1 100644
--- a/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
index ce4b578..30b884e 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
index 8f03489..511f125 100644
--- a/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
index a0d64a3..0544d32 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
index 930b5f2..8a751c3 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
index 930b5f2..4294246 100644
--- a/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
index 60aede8..bda54ee 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
index 614d27a..812e1b5 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
index f402bd1..6a0ee8d 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
index 041e5cc..4bedd5c 100644
--- a/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
index 0804faf..e711d9d 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
index c649599..4bdf427 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
index 149f90d..79567ad 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
index 4145493..65d472f 100644
--- a/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
index 85253f7..614f428 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
index efd26b0..f80f9b3 100644
--- a/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
index e2305cb..840967c 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
index 6643deb..d7f7ee4 100644
--- a/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 9d16f321..a1b4e40 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
index 9d16f321..ba9f6a0 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
index fde3ac3..4afca86 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
index fde3ac3..eb79128 100644
--- a/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..4baaed3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..5532e88
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
index e4b3393..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
index e4b3393..5326b45 100644
--- a/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
index ee5eb6f..e9e7c18 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
index ee5eb6f..74e3843 100644
--- a/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 75c5996..16c1e00 100644
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index a2d6ca1..92a298b 100644
--- a/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
index a3c7711..fe701d8 100644
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
index 2a21210..efec27b 100644
--- a/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
index aecf6bd..eb44f17 100644
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
index 3273a22..dfceeed 100644
--- a/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
index 4acb32b..64a2e52 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
index 4acb32b..5110439 100644
--- a/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
index e862cb1..1df4a4d 100644
--- a/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
index f1eb673..574dbef 100644
--- a/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
index a54cfbf3..5ba273a 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
index 5afea71..32942b9 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
index f4f58b7..70ee78f 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
index c270562..5bd562e 100644
--- a/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_check_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
index e3d3eb1..e05017c 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
index 19706e0..a476b99 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
index af8eebb..cfa776c 100644
--- a/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_default_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
index 9bc460f..181f0a5 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
index 96c63b1..536c618 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
index de76d56..3bb4ed0 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
index d7eee84..1171dcb 100644
--- a/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_radio_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
index 899e577..03c26f0 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
index aaa6826..f601b3b 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
index e15fc63..dc5233b 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
index cc82a54..2afb586 100644
--- a/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
index b756e79..d7416c0 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
index 89bf5b4..47587d2 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_off_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
index 50e4940..b258503 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
index 0b77905..703e502 100644
--- a/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/btn_star_on_pressed_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
index 2e21a6f..966511e 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
index 1a346c9..b6cd6a28 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_off_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
index d0c2151..33eb011 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
index fab8dc1..8d55f44 100644
--- a/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/btn_toggle_on_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
new file mode 100644
index 0000000..c6079cd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
new file mode 100644
index 0000000..230d649
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/list_longpressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
index 7bfdd34..2d4f2300 100644
--- a/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
index 13f76de..bd707b0 100644
--- a/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
index a1b5ed2..922cff7 100644
--- a/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
index 7cfb33d..0f58325 100644
--- a/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/list_selected_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
index 8a67108..432436f 100644
--- a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
index f84557f..b18aed6 100644
--- a/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/quickcontact_badge_overlay_pressed_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
index 103a2c3..5cb3d60 100644
--- a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
index 4e76add..91528b4 100644
--- a/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_ab_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
index d8b02e0..37e1cdc 100644
--- a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_dark_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
index 807f2c1..2990407 100644
--- a/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_pressed_holo_light_am.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
index bdcfc74..94ab960 100644
--- a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
index 302b4e2..b795052 100644
--- a/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
index 8987d993d..c2ee05f 100644
--- a/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
index 92419c4..7faf667 100644
--- a/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
+++ b/core/res/res/drawable-xxhdpi/tab_unselected_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_cab_done_holo_dark.xml b/core/res/res/drawable/btn_cab_done_holo_dark.xml
index 14f5777..f865ddd 100644
--- a/core/res/res/drawable/btn_cab_done_holo_dark.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_dark.xml
@@ -17,7 +17,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
           android:autoMirrored="true">
     <item android:state_pressed="true"
-        android:drawable="@drawable/btn_cab_done_pressed_holo_dark" />
+        android:drawable="@drawable/list_pressed_holo_dark" />
     <item android:state_focused="true" android:state_enabled="true"
         android:drawable="@drawable/btn_cab_done_focused_holo_dark" />
     <item android:state_enabled="true"
diff --git a/core/res/res/drawable/btn_cab_done_holo_light.xml b/core/res/res/drawable/btn_cab_done_holo_light.xml
index a9a634f..6d85fc4 100644
--- a/core/res/res/drawable/btn_cab_done_holo_light.xml
+++ b/core/res/res/drawable/btn_cab_done_holo_light.xml
@@ -17,7 +17,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
           android:autoMirrored="true">
     <item android:state_pressed="true"
-        android:drawable="@drawable/btn_cab_done_pressed_holo_light" />
+        android:drawable="@drawable/list_pressed_holo_light" />
     <item android:state_focused="true" android:state_enabled="true"
         android:drawable="@drawable/btn_cab_done_focused_holo_light" />
     <item android:state_enabled="true"
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
index 7c68426..288c778 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_dark.xml
@@ -16,5 +16,5 @@
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@android:drawable/list_pressed_holo_dark"  />
-    <item android:drawable="@android:drawable/list_longpressed_holo"  />
+    <item android:drawable="@android:drawable/list_longpressed_holo_dark"  />
 </transition>
diff --git a/core/res/res/drawable/list_selector_background_transition_holo_light.xml b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
index fc08a84..b729e1f 100644
--- a/core/res/res/drawable/list_selector_background_transition_holo_light.xml
+++ b/core/res/res/drawable/list_selector_background_transition_holo_light.xml
@@ -16,5 +16,5 @@
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@android:drawable/list_pressed_holo_light"  />
-    <item android:drawable="@android:drawable/list_longpressed_holo"  />
+    <item android:drawable="@android:drawable/list_longpressed_holo_light"  />
 </transition>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 80810d5..b20f5ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1821,7 +1821,9 @@
         <attr name="value" />
     </declare-styleable>
 
-    <attr name="keyset" />
+    <!-- Groups signing keys into a {@code KeySet} for easier reference in
+            other APIs. However, currently no APIs use this. -->
+    <attr name="keySet" />
     <declare-styleable name="PublicKey">
         <attr name="value" />
     </declare-styleable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c5d4810..ef7f2b7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2058,7 +2058,7 @@
     =============================================================== -->
   <eat-comment />
 
-  <public type="attr" name="keyset" />
+  <public type="attr" name="keySet" />
   <public type="attr" name="targetId" />
   <public type="attr" name="fromScene" />
   <public type="attr" name="toScene" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 98368a1..56b8ca4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1433,6 +1433,11 @@
     <string name="permdesc_captureSecureVideoOutput">Allows the app to capture and redirect secure video output.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_mediaContentControl">control media playback and metadata access</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_mediaContentControl">Allows the app to control media playback and access the media information (title, author...).</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
@@ -1898,6 +1903,11 @@
     <string name="permdesc_use_sip">Allows the app to use the SIP service to make/receive Internet calls.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bind_call_service">interact with in-call screen</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bind_call_service">Allows the app to control when and how the user sees the in-call screen.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readNetworkUsageHistory">read historical network usage</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
@@ -4296,19 +4306,111 @@
     <!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
     <string name="mediaSize_iso_c10">ISO C10</string>
 
-    <!-- North America Letter media (paper) size: 8.5" × 11" -->
+    <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
     <string name="mediaSize_na_letter">Letter</string>
-    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" -->
+    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
     <string name="mediaSize_na_gvrnmt_letter">Government Letter</string>
-    <!-- North America Legal media (paper) size: 8.5" × 14" -->
+    <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
     <string name="mediaSize_na_legal">Legal</string>
-    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" -->
+    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
     <string name="mediaSize_na_junior_legal">Junior Legal</string>
-    <!-- North America Ledger media (paper) size: 17" × 11" -->
+    <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
     <string name="mediaSize_na_ledger">Ledger</string>
-    <!-- North America Tabloid media (paper) size: 11" × 17" -->
+    <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
     <string name="mediaSize_na_tabloid">Tabloid</string>
 
+    <!-- North America Index Card 3x5 media (paper) size: 3" x 5" (76mm x 127mm) -->
+    <string name="mediaSize_na_index_3x5">Index Card 3x5</string>
+    <!-- North America Index Card 4x6 media (paper) size: 4" x 6" (102mm x 152mm) -->
+    <string name="mediaSize_na_index_4x6">Index Card 4x6</string>
+    <!-- North America Index Card 5x8 media (paper) size: 5" x 8" (127mm x 203mm) -->
+    <string name="mediaSize_na_index_5x8">Index Card 5x8</string>
+    <!-- North America Monarch media (paper) size: 7.25" x 10.5" (184mm x 267mm) -->
+    <string name="mediaSize_na_monarch">Monarch</string>
+    <!-- North America Quarto media (paper) size: 8" x 10" (203mm x 254mm) -->
+    <string name="mediaSize_na_quarto">Quarto</string>
+    <!-- North America Foolscap media (paper) size: 8" x 13" (203mm x 330mm) -->
+    <string name="mediaSize_na_foolscap">Foolscap</string>
+
+    <!-- Chinese Roc 8k media (paper) size: 270mm x 390mm (10.629" x 15.3543") -->
+    <string name="mediaSize_chinese_roc_8k">ROC 8K</string>
+    <!-- Chinese Roc 16k media (paper) size: 195mm x 270mm (7.677" x 10.629") -->
+    <string name="mediaSize_chinese_roc_16k">ROC 16K</string>
+
+    <!-- Chinese PRC 1 media (paper) size: 102mm x 165mm (4.015" x 6.496") -->
+    <string name="mediaSize_chinese_prc_1">PRC 1</string>
+    <!-- Chinese PRC 2 media (paper) size: 102mm x 176mm (4.015" x 6.929") -->
+    <string name="mediaSize_chinese_prc_2">PRC 2</string>
+    <!-- Chinese PRC 3 media (paper) size: 125mm x 176mm (4.921" x 6.929") -->
+    <string name="mediaSize_chinese_prc_3">PRC 3</string>
+    <!-- Chinese PRC 4 media (paper) size: 110mm x 208mm (4.330" x 8.189") -->
+    <string name="mediaSize_chinese_prc_4">PRC 4</string>
+    <!-- Chinese PRC 5 media (paper) size: 110mm x 220mm (4.330" x 8.661") -->
+    <string name="mediaSize_chinese_prc_5">PRC 5</string>
+    <!-- Chinese PRC 6 media (paper) size: 120mm x 320mm (4.724" x 12.599") -->
+    <string name="mediaSize_chinese_prc_6">PRC 6</string>
+    <!-- Chinese PRC 7 media (paper) size: 160mm x 230mm (6.299" x 9.055") -->
+    <string name="mediaSize_chinese_prc_7">PRC 7</string>
+    <!-- Chinese PRC 8 media (paper) size: 120mm x 309mm (4.724" x 12.165") -->
+    <string name="mediaSize_chinese_prc_8">PRC 8</string>
+    <!-- Chinese PRC 9 media (paper) size: 229mm x 324mm (9.016" x 12.756") -->
+    <string name="mediaSize_chinese_prc_9">PRC 9</string>
+    <!-- Chinese PRC 10 media (paper) size: 324mm x 458mm (12.756" x 18.032") -->
+    <string name="mediaSize_chinese_prc_10">PRC 10</string>
+
+    <!-- Chinese RPC 16K media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+    <string name="mediaSize_chinese_prc_16k">PRC 16K</string>
+    <!-- Chinese Pa Kai media (paper) size: 146mm x 215mm (5.749" x 8.465") -->
+    <string name="mediaSize_chinese_om_pa_kai">Pa Kai</string>
+    <!-- Chinese Dai Pa Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+    <string name="mediaSize_chinese_om_dai_pa_kai">Dai Pa Kai</string>
+    <!-- Chinese Jurro Ku Kai media (paper) size: 275mm x 395mm (10.827" x 15.551") -->
+    <string name="mediaSize_chinese_om_jurro_ku_kai">Jurro Ku Kai</string>
+
+    <!-- Japanese JIS B10 media (paper) size: 32mm x 45mm (1.259" x 1.772") -->
+    <string name="mediaSize_japanese_jis_b10">JIS B10</string>
+    <!-- Japanese JIS B9 media (paper) size: 45mm x 64mm (1.772" x 2.52") -->
+    <string name="mediaSize_japanese_jis_b9">JIS B9</string>
+    <!-- Japanese JIS B8 media (paper) size: 64mm x 91mm (2.52" x 3.583") -->
+    <string name="mediaSize_japanese_jis_b8">JIS B8</string>
+    <!-- Japanese JIS B7 media (paper) size: 91mm x 128mm (3.583" x 5.049") -->
+    <string name="mediaSize_japanese_jis_b7">JIS B7</string>
+    <!-- Japanese JIS B6 media (paper) size: 128mm x 182mm (5.049" x 7.165") -->
+    <string name="mediaSize_japanese_jis_b6">JIS B6</string>
+    <!-- Japanese JIS B5 media (paper) size: 182mm x 257mm (7.165" x 10.118") -->
+    <string name="mediaSize_japanese_jis_b5">JIS B5</string>
+    <!-- Japanese JIS B4 media (paper) size: 257mm x 364mm (10.118" x 14.331") -->
+    <string name="mediaSize_japanese_jis_b4">JIS B4</string>
+    <!-- Japanese JIS B3 media (paper) size: 364mm x 515mm (14.331" x 20.276") -->
+    <string name="mediaSize_japanese_jis_b3">JIS B3</string>
+    <!-- Japanese JIS B2 media (paper) size: 515mm x 728mm (20.276" x 28.661") -->
+    <string name="mediaSize_japanese_jis_b2">JIS B2</string>
+    <!-- Japanese JIS B1 media (paper) size: 728mm x 1030mm (28.661" x 40.551") -->
+    <string name="mediaSize_japanese_jis_b1">JIS B1</string>
+    <!-- Japanese JIS B0 media (paper) size: 1030mm x 1456mm (40.551" x 57.323") -->
+    <string name="mediaSize_japanese_jis_b0">JIS B0</string>
+
+    <!-- Japanese JIS Exec media (paper) size: 216mm x 330mm (8.504" x 12.992") -->
+    <string name="mediaSize_japanese_jis_exec">JIS Exec</string>
+
+    <!-- Japanese Chou4 media (paper) size: 90mm x 205mm (3.543" x 8.071") -->
+    <string name="mediaSize_japanese_chou4">Chou4</string>
+    <!-- Japanese Chou3 media (paper) size: 120mm x 235mm (4.724" x 9.252") -->
+    <string name="mediaSize_japanese_chou3">Chou3</string>
+    <!-- Japanese Chou2 media (paper) size: 111.1mm x 146mm (4.374" x 5.748") -->
+    <string name="mediaSize_japanese_chou2">Chou2</string>
+
+    <!-- Japanese Hagaki media (paper) size: 100mm x 148mm (3.937" x 5.827") -->
+    <string name="mediaSize_japanese_hagaki">Hagaki </string>
+    <!-- Japanese Oufuku media (paper) size: 148mm x 200mm (5.827" x 7.874") -->
+    <string name="mediaSize_japanese_oufuku">Oufuku </string>
+    <!-- Japanese Kahu media (paper) size: 240mm x 322.1mm (9.449" x 12.681") -->
+    <string name="mediaSize_japanese_kahu">Kahu</string>
+    <!-- Japanese Kaku2 media (paper) size: 240mm x 332mm (9.449" x 13.071") -->
+    <string name="mediaSize_japanese_kaku2">Kaku2</string>
+    <!-- Japanese You4 media (paper) size: 105mm x 235mm (4.134" x 9.252") -->
+    <string name="mediaSize_japanese_you4">You4</string>
+
     <!-- Write fail reason: printing was cancelled.[CHAR LIMIT=none] -->
     <string name="write_fail_reason_cancelled">Cancelled</string>
     <!-- Write fail reason: couldn't write the printed content. [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9cb0a37..e82c0e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -878,6 +878,48 @@
   <java-symbol type="string" name="mediaSize_na_junior_legal" />
   <java-symbol type="string" name="mediaSize_na_ledger" />
   <java-symbol type="string" name="mediaSize_na_tabloid" />
+  <java-symbol type="string" name="mediaSize_na_index_3x5" />
+  <java-symbol type="string" name="mediaSize_na_index_4x6" />
+  <java-symbol type="string" name="mediaSize_na_index_5x8" />
+  <java-symbol type="string" name="mediaSize_na_monarch" />
+  <java-symbol type="string" name="mediaSize_na_quarto" />
+  <java-symbol type="string" name="mediaSize_na_foolscap" />
+  <java-symbol type="string" name="mediaSize_chinese_roc_8k" />
+  <java-symbol type="string" name="mediaSize_chinese_roc_16k" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_1" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_2" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_3" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_4" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_5" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_6" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_7" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_8" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_9" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_10" />
+  <java-symbol type="string" name="mediaSize_chinese_prc_16k" />
+  <java-symbol type="string" name="mediaSize_chinese_om_pa_kai" />
+  <java-symbol type="string" name="mediaSize_chinese_om_dai_pa_kai" />
+  <java-symbol type="string" name="mediaSize_chinese_om_jurro_ku_kai" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b10" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b9" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b8" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b7" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b6" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b5" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b4" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b3" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b2" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b1" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_b0" />
+  <java-symbol type="string" name="mediaSize_japanese_jis_exec" />
+  <java-symbol type="string" name="mediaSize_japanese_chou4" />
+  <java-symbol type="string" name="mediaSize_japanese_chou3" />
+  <java-symbol type="string" name="mediaSize_japanese_chou2" />
+  <java-symbol type="string" name="mediaSize_japanese_hagaki" />
+  <java-symbol type="string" name="mediaSize_japanese_oufuku" />
+  <java-symbol type="string" name="mediaSize_japanese_kahu" />
+  <java-symbol type="string" name="mediaSize_japanese_kaku2" />
+  <java-symbol type="string" name="mediaSize_japanese_you4" />
   <java-symbol type="string" name="reason_unknown" />
   <java-symbol type="string" name="restr_pin_enter_admin_pin" />
   <java-symbol type="string" name="restr_pin_enter_pin" />
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 23606a1..c8ace44 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -569,10 +569,7 @@
                 final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
                 bm = nativeDecodeAsset(asset, outPadding, opts);
             } else {
-                byte [] tempStorage = null;
-                if (opts != null) tempStorage = opts.inTempStorage;
-                if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
-                bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+                bm = decodeStreamInternal(is, outPadding, opts);
             }
 
             if (bm == null && opts != null && opts.inBitmap != null) {
@@ -588,6 +585,18 @@
     }
 
     /**
+     * Private helper function for decoding an InputStream natively. Buffers the input enough to
+     * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
+     */
+    private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+        // ASSERT(is != null);
+        byte [] tempStorage = null;
+        if (opts != null) tempStorage = opts.inTempStorage;
+        if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
+        return nativeDecodeStream(is, tempStorage, outPadding, opts);
+    }
+
+    /**
      * Decode an input stream into a bitmap. If the input stream is null, or
      * cannot be used to decode a bitmap, the function returns null.
      * The stream's position will be where ever it was after the encoded data
@@ -624,13 +633,8 @@
                 bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
             } else {
                 FileInputStream fis = new FileInputStream(fd);
-                // FIXME: If nativeDecodeStream grabbed the pointer to tempStorage
-                // from Options, this code would not need to be duplicated.
-                byte [] tempStorage = null;
-                if (opts != null) tempStorage = opts.inTempStorage;
-                if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
                 try {
-                    bm = nativeDecodeStream(fis, tempStorage, outPadding, opts);
+                    bm = decodeStreamInternal(fis, outPadding, opts);
                 } finally {
                     try {
                         fis.close();
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 4a33453..9419faf 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -16,12 +16,13 @@
 
 package android.graphics;
 
+import android.content.res.AssetManager;
 import java.io.InputStream;
 import java.io.FileInputStream;
 
 public class Movie {
     private final int mNativeMovie;
-    
+
     private Movie(int nativeMovie) {
         if (nativeMovie == 0) {
             throw new RuntimeException("native movie creation failed");
@@ -42,7 +43,20 @@
         draw(canvas, x, y, null);
     }
 
-    public static native Movie decodeStream(InputStream is);
+    public static Movie decodeStream(InputStream is) {
+        if (is == null) {
+            return null;
+        }
+        if (is instanceof AssetManager.AssetInputStream) {
+            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
+            return nativeDecodeAsset(asset);
+        }
+
+        return nativeDecodeStream(is);
+    }
+
+    private static native Movie nativeDecodeAsset(int asset);
+    private static native Movie nativeDecodeStream(InputStream is);
     public static native Movie decodeByteArray(byte[] data, int offset,
                                                int length);
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index c0b77c7..7eb7028 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -275,6 +275,11 @@
         DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
         buffer.writeCommand(0, "multiDraw");
         buffer.writeCommand(1, op->name());
+
+#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
+        renderer.eventMark("multiDraw");
+        renderer.eventMark(op->name());
+#endif
         status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
 
 #if DEBUG_MERGE_BEHAVIOR
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index a17942e..b052461 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -813,12 +813,15 @@
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
             const DeferredDisplayState& state) {
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
-        deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
+        deferInfo.mergeId = getAtlasEntry() ?
+                (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
 
+        // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
         // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
         // MergingDrawBatch::canMergeWith()
         // TODO: support clipped bitmaps by handling them in SET_TEXTURE
-        deferInfo.mergeable = state.mMatrix.isSimple() && !state.mClipSideFlags &&
+        deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
+                !state.mClipSideFlags &&
                 OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
                 (mBitmap->getConfig() != SkBitmap::kA8_Config);
     }
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 65e7eae..1948778 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -110,6 +110,10 @@
                 mType |= kTypeRectToRect;
             }
         }
+
+        if (m00 > 0.0f && m11 > 0.0f) {
+            mType |= kTypePositiveScale;
+        }
     }
     return mType;
 }
@@ -122,6 +126,10 @@
     return getType() & kTypeRectToRect;
 }
 
+bool Matrix4::positiveScale() const {
+    return getType() & kTypePositiveScale;
+}
+
 bool Matrix4::changesBounds() const {
     return getType() & (kTypeScale | kTypeAffine | kTypePerspective);
 }
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 5116203..e2c5b20 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -64,7 +64,8 @@
         kTypeAffine = 0x4,
         kTypePerspective = 0x8,
         kTypeRectToRect = 0x10,
-        kTypeUnknown = 0x20,
+        kTypePositiveScale = 0x20,
+        kTypeUnknown = 0x40,
     };
 
     static const int sGeometryMask = 0xf;
@@ -183,6 +184,7 @@
     bool isIdentity() const;
     bool isPerspective() const;
     bool rectToRect() const;
+    bool positiveScale() const;
 
     bool changesBounds() const;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2066f69..89a82fd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1628,14 +1628,7 @@
 
     Rect r(left, top, right, bottom);
     currentTransform().mapRect(r);
-
-    if (snapOut) {
-        // snapOut is generally used to account for 1 pixel ramp (in window coordinates)
-        // outside of the provided rect boundaries in tessellated AA geometry
-        r.snapOutToPixelBoundaries();
-    } else {
-        r.snapToPixelBoundaries();
-    }
+    r.snapGeometryToPixelBoundaries(snapOut);
 
     Rect clipRect(*mSnapshot->clipRect);
     clipRect.snapToPixelBoundaries();
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 9e4670e..7814a01 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -20,6 +20,7 @@
 #include <utils/Trace.h>
 
 #include "Program.h"
+#include "Vertex.h"
 
 namespace android {
 namespace uirenderer {
@@ -172,7 +173,7 @@
             // up and to the left.
             // This offset value is based on an assumption that some hardware may use as
             // little as 12.4 precision, so we offset by slightly more than 1/16.
-            p.translate(.065, .065);
+            p.translate(Vertex::gGeometryFudgeFactor, Vertex::gGeometryFudgeFactor);
             glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
         }
         mProjection = projectionMatrix;
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 7605307..dabd8d4 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -21,6 +21,8 @@
 
 #include <utils/Log.h>
 
+#include "Vertex.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -171,17 +173,37 @@
     }
 
     /**
-     * Similar to snapToPixelBoundaries, but used for AA geometry with a ramp perimeter.
+     * Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding
+     * errors.
      *
-     * We inset the data by a fudge factor of slightly over 1/16 (similar to when drawing non-AA
-     * lines) before rounding out so that insignificant amounts of ramp geometry (esp. from rounding
-     * errors) are ignored.
+     * This function should be used whenever estimating the damage rect of geometry already mapped
+     * into layer space.
      */
-    void snapOutToPixelBoundaries() {
-        left = floorf(left + 0.065f);
-        top = floorf(top + 0.065f);
-        right = ceilf(right - 0.065f);
-        bottom = ceilf(bottom - 0.065f);
+    void snapGeometryToPixelBoundaries(bool snapOut) {
+        if (snapOut) {
+            /* For AA geometry with a ramp perimeter, don't snap by rounding - AA geometry will have
+             * a 0.5 pixel perimeter not accounted for in its bounds. Instead, snap by
+             * conservatively rounding out the bounds with floor/ceil.
+             *
+             * In order to avoid changing integer bounds with floor/ceil due to rounding errors
+             * inset the bounds first by the fudge factor. Very small fraction-of-a-pixel errors
+             * from this inset will only incur similarly small errors in output, due to transparency
+             * in extreme outside of the geometry.
+             */
+            left = floorf(left + Vertex::gGeometryFudgeFactor);
+            top = floorf(top + Vertex::gGeometryFudgeFactor);
+            right = ceilf(right - Vertex::gGeometryFudgeFactor);
+            bottom = ceilf(bottom - Vertex::gGeometryFudgeFactor);
+        } else {
+            /* For other geometry, we do the regular rounding in order to snap, but also outset the
+             * bounds by a fudge factor. This ensures that ambiguous geometry (e.g. a non-AA Rect
+             * with top left at (0.5, 0.5)) will err on the side of a larger damage rect.
+             */
+            left = floorf(left + 0.5f - Vertex::gGeometryFudgeFactor);
+            top = floorf(top + 0.5f - Vertex::gGeometryFudgeFactor);
+            right = floorf(right + 0.5f + Vertex::gGeometryFudgeFactor);
+            bottom = floorf(bottom + 0.5f + Vertex::gGeometryFudgeFactor);
+        }
     }
 
     void snapToPixelBoundaries() {
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c06762f..790d4fc 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -26,6 +26,15 @@
  * Simple structure to describe a vertex with a position and a texture.
  */
 struct Vertex {
+    /**
+     * Fudge-factor used to disambiguate geometry pixel positioning.
+     *
+     * Used to offset lines and points to avoid ambiguous intersection with pixel centers (see
+     * Program::set()), and used to make geometry damage rect calculation conservative (see
+     * Rect::snapGeometryToPixelBoundaries())
+     */
+    static const float gGeometryFudgeFactor = 0.0656f;
+
     float position[2];
 
     static inline void set(Vertex* vertex, float x, float y) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 845baaf..a4009cf 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -323,6 +323,12 @@
     public static final int FLAG_FIXED_VOLUME = 1 << 5;
 
     /**
+     * Indicates the volume set/adjust call is for Bluetooth absolute volume
+     * @hide
+     */
+    public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
+
+    /**
      * Ringer mode that will be silent and will not vibrate. (This overrides the
      * vibrate setting.)
      *
@@ -438,6 +444,19 @@
 
     /**
      * @hide
+     * @param KeyEvent
+     */
+    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
+        IAudioService service = getService();
+        try {
+            service.dispatchMediaKeyEvent(keyEvent);
+        } catch (RemoteException e) {
+            Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e);
+        }
+    }
+
+    /**
+     * @hide
      */
     public void preDispatchKeyEvent(KeyEvent event, int stream) {
         /*
@@ -2229,6 +2248,49 @@
 
     /**
      * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param rctlr
+     * @return true if the {@link RemoteController} was successfully registered, false if an
+     *     error occurred, due to an internal system error, or insufficient permissions.
+     */
+    public boolean registerRemoteController(RemoteController rctlr) {
+        if (rctlr == null) {
+            return false;
+        }
+        IAudioService service = getService();
+        try {
+            boolean reg = service.registerRemoteControlDisplay(rctlr.getRcDisplay(),
+                    // passing a negative value for art work width and height
+                    //   as they are still unknown at this stage
+                    /*w*/-1, /*h*/ -1);
+            rctlr.setIsRegistered(reg);
+            return reg;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
+            return false;
+        }
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param rctlr
+     */
+    public void unregisterRemoteController(RemoteController rctlr) {
+        if (rctlr == null) {
+            return;
+        }
+        IAudioService service = getService();
+        try {
+            service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
+            rctlr.setIsRegistered(false);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
+        }
+    }
+
+    /**
+     * @hide
      * Registers a remote control display that will be sent information by remote control clients.
      * Use this method if your IRemoteControlDisplay is not going to display artwork, otherwise
      * use {@link #registerRemoteControlDisplay(IRemoteControlDisplay, int, int)} to pass the
@@ -2257,8 +2319,6 @@
         }
         IAudioService service = getService();
         try {
-            // passing a negative value for art work width and height as they are unknown at
-            // this stage
             service.registerRemoteControlDisplay(rcd, w, h);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerRemoteControlDisplay " + e);
@@ -2351,13 +2411,15 @@
 
     /**
      * @hide
-     * Notify the user of a RemoteControlClient that it should update its metadata
+     * Notify the user of a RemoteControlClient that it should update its metadata with the
+     * new value for the given key.
      * @param generationId the RemoteControlClient generation counter for which this request is
      *         issued. Requests for an older generation than current one will be ignored.
      * @param key the metadata key for which a new value exists
      * @param value the new metadata value
      */
-    public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
+    public void updateRemoteControlClientMetadata(int generationId, int key,
+            Rating value) {
         IAudioService service = getService();
         try {
             service.updateRemoteControlClientMetadata(generationId, key, value);
@@ -2397,20 +2459,6 @@
         }
     }
 
-    /**
-     * @hide
-     * Notifies AudioService of the volume set on the A2DP device as a callback, so AudioService
-     * is able to update the UI.
-     */
-    public void avrcpUpdateVolume(int oldVolume, int volume) {
-        IAudioService service = getService();
-        try {
-            service.avrcpUpdateVolume(oldVolume, volume);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in avrcpUpdateVolume", e);
-        }
-    }
-
      /**
       * {@hide}
       */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index b72551a..3425c91 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -843,6 +843,13 @@
         boolean adjustVolume = true;
         int step;
 
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
         if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return;
@@ -892,15 +899,18 @@
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
         if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+
             // Check if volume update should be send to AVRCP
-            synchronized (mA2dpAvrcpLock) {
-                if (mA2dp != null && mAvrcpAbsVolSupported) {
-                    mA2dp.adjustAvrcpAbsoluteVolume(direction);
-                    return;
-                    // No need to send volume update, because we will update the volume with a
-                    // callback from Avrcp.
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
+                    }
                 }
             }
+
             if ((direction == AudioManager.ADJUST_RAISE) &&
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
@@ -985,6 +995,13 @@
         final int device = getDeviceForStream(streamType);
         int oldIndex;
 
+        // skip a2dp absolute volume control request when the device
+        // is not an a2dp device
+        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
+            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
+            return;
+        }
+
         if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
                 callingPackage) != AppOpsManager.MODE_ALLOWED) {
             return;
@@ -998,12 +1015,13 @@
 
             index = rescaleIndex(index * 10, streamType, streamTypeAlias);
 
-            synchronized (mA2dpAvrcpLock) {
-                if (mA2dp != null && mAvrcpAbsVolSupported) {
-                    mA2dp.setAvrcpAbsoluteVolume(index);
-                    return;
-                    // No need to send volume update, because we will update the volume with a
-                    // callback from Avrcp.
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
+                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
+                synchronized (mA2dpAvrcpLock) {
+                    if (mA2dp != null && mAvrcpAbsVolSupported) {
+                        mA2dp.setAvrcpAbsoluteVolume(index);
+                    }
                 }
             }
 
@@ -2835,7 +2853,12 @@
             int index;
             if (isMuted()) {
                 index = 0;
-            } else {
+            } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
+                       (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                       mAvrcpAbsVolSupported) {
+                index = (mIndexMax + 5)/10;
+            }
+            else {
                 index = (getIndex(device) + 5)/10;
             }
             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
@@ -3650,6 +3673,9 @@
     private void makeA2dpDeviceAvailable(String address) {
         // enable A2DP before notifying A2DP connection to avoid unecessary processing in
         // audio policy manager
+        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         setBluetoothA2dpOnInt(true);
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -3666,6 +3692,9 @@
 
     // must be called synchronized on mConnectedDevices
     private void makeA2dpDeviceUnavailableNow(String address) {
+        synchronized (mA2dpAvrcpLock) {
+            mAvrcpAbsVolSupported = false;
+        }
         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                 AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 address);
@@ -3706,19 +3735,6 @@
             address = "";
         }
 
-        // Disable absolute volume, if device is disconnected
-        synchronized (mA2dpAvrcpLock) {
-            if (state == BluetoothProfile.STATE_DISCONNECTED && mAvrcpAbsVolSupported) {
-                mAvrcpAbsVolSupported = false;
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        getDeviceForStream(AudioSystem.STREAM_MUSIC),
-                        0,
-                        mStreamStates[AudioSystem.STREAM_MUSIC],
-                        0);
-            }
-        }
         synchronized (mConnectedDevices) {
             boolean isConnected =
                 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
@@ -3773,27 +3789,12 @@
         // address is not used for now, but may be used when multiple a2dp devices are supported
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = support;
-            if (support) {
-                VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
-                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-                streamState.setIndex(streamState.getMaxIndex(), device);
-                sendMsg(mAudioHandler,
-                        MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_QUEUE,
-                        device,
-                        0,
-                        streamState,
-                        0);
-            }
+            VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
         }
     }
 
-    public void avrcpUpdateVolume(int oldVolume, int volume) {
-        mStreamStates[AudioSystem.STREAM_MUSIC].
-                        setIndex(volume, getDeviceForStream(AudioSystem.STREAM_MUSIC));
-        sendVolumeUpdate(AudioSystem.STREAM_MUSIC, oldVolume, volume, AudioManager.FLAG_SHOW_UI);
-    }
-
     private boolean handleDeviceConnection(boolean connected, int device, String params) {
         synchronized (mConnectedDevices) {
             boolean isConnected = (mConnectedDevices.containsKey(device) &&
@@ -4142,8 +4143,17 @@
     //==========================================================================================
     // RemoteControlDisplay / RemoteControlClient / Remote info
     //==========================================================================================
-    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
-        mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
+        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
+            mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
+            return true;
+        } else {
+            Log.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
+                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
+                    " to register IRemoteControlDisplay");
+            return false;
+        }
     }
 
     public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
@@ -4189,7 +4199,7 @@
         mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
     }
 
-    public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
+    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
         mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
     }
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fe060f8..e3b87dd 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
 import android.media.IRemoteControlDisplay;
 import android.media.IRemoteVolumeObserver;
 import android.media.IRingtonePlayer;
+import android.media.Rating;
 import android.net.Uri;
 import android.view.KeyEvent;
 
@@ -100,8 +101,6 @@
 
     oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
 
-    oneway void avrcpUpdateVolume(int oldVolume, int volume);
-
     void setSpeakerphoneOn(boolean on);
 
     boolean isSpeakerphoneOn();
@@ -142,7 +141,7 @@
      * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
      *   display doesn't need to receive artwork.
      */
-    oneway void   registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
+    boolean registerRemoteControlDisplay(in IRemoteControlDisplay rcd, int w, int h);
     /**
      * Unregister an IRemoteControlDisplay.
      * No effect if the IRemoteControlDisplay hasn't been successfully registered.
@@ -180,13 +179,14 @@
      */
      void setRemoteControlClientPlaybackPosition(int generationId, long timeMs);
      /**
-      * Notify the user of a RemoteControlClient that it should update its metadata
+      * Notify the user of a RemoteControlClient that it should update its metadata with the
+      * new value for the given key.
       * @param generationId the RemoteControlClient generation counter for which this request is
       *         issued. Requests for an older generation than current one will be ignored.
       * @param key the metadata key for which a new value exists
       * @param value the new metadata value
       */
-     void updateRemoteControlClientMetadata(int generationId, int key, long value);
+     void updateRemoteControlClientMetadata(int generationId, int key, in Rating value);
 
     /**
      * Do not use directly, use instead
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
index dd729b4..48079f2 100644
--- a/media/java/android/media/IRemoteControlClient.aidl
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -17,6 +17,7 @@
 
 import android.graphics.Bitmap;
 import android.media.IRemoteControlDisplay;
+import android.media.Rating;
 
 /**
  * @hide
@@ -49,5 +50,5 @@
     void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h);
     void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync);
     void seekTo(int clientGeneration, long timeMs);
-    void updateMetadata(int clientGeneration, int key, long value);
+    void updateMetadata(int clientGeneration, int key, in Rating value);
 }
\ No newline at end of file
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index aee8362..1bd32c4 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -20,6 +20,7 @@
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.view.Surface;
 
 import java.lang.ref.WeakReference;
@@ -82,7 +83,8 @@
      * @param format
      *            The format of the Image that this reader will produce. This
      *            must be one of the {@link android.graphics.ImageFormat} or
-     *            {@link android.graphics.PixelFormat} constants.
+     *            {@link android.graphics.PixelFormat} constants. Note that
+     *            not all formats is supported, like ImageFormat.NV21.
      * @param maxImages
      *            The maximum number of images the user will want to
      *            access simultaneously. This should be as small as possible to limit
@@ -115,6 +117,11 @@
                 "Maximum outstanding image count must be at least 1");
         }
 
+        if (format == ImageFormat.NV21) {
+            throw new IllegalArgumentException(
+                    "NV21 format is not supported");
+        }
+
         mNumPlanes = getNumPlanesFromFormat();
 
         nativeInit(new WeakReference<ImageReader>(this), width, height, format, maxImages);
@@ -377,17 +384,21 @@
      * @throws IllegalArgumentException
      *            If no handler specified and the calling thread has no looper.
      */
-   public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
-        mImageListener = listener;
-
-        Looper looper;
-        mHandler = handler;
-        if (listener != null && mHandler == null) {
-            if ((looper = Looper.myLooper()) != null) {
-                mHandler = new Handler();
+    public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
+        synchronized (mListenerLock) {
+            if (listener != null) {
+                Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+                if (looper == null) {
+                    throw new IllegalArgumentException(
+                            "handler is null but the current thread is not a looper");
+                }
+                if (mListenerHandler == null || mListenerHandler.getLooper() != looper) {
+                    mListenerHandler = new ListenerHandler(looper);
+                }
+                mListener = listener;
             } else {
-                throw new IllegalArgumentException(
-                        "Looper doesn't exist in the calling thread");
+                mListener = null;
+                mListenerHandler = null;
             }
         }
     }
@@ -426,6 +437,7 @@
      */
     @Override
     public void close() {
+        setOnImageAvailableListener(null, null);
         nativeClose();
     }
 
@@ -474,6 +486,9 @@
 
     /**
      * Called from Native code when an Event happens.
+     *
+     * This may be called from an arbitrary Binder thread, so access to the ImageReader must be
+     * synchronized appropriately.
      */
     private static void postEventFromNative(Object selfRef) {
         @SuppressWarnings("unchecked")
@@ -483,16 +498,16 @@
             return;
         }
 
-        if (ir.mHandler != null && ir.mImageListener != null) {
-            ir.mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    ir.mImageListener.onImageAvailable(ir);
-                }
-              });
+        final Handler handler;
+        synchronized (ir.mListenerLock) {
+            handler = ir.mListenerHandler;
+        }
+        if (handler != null) {
+            handler.sendEmptyMessage(0);
         }
     }
 
+
     private final int mWidth;
     private final int mHeight;
     private final int mFormat;
@@ -500,14 +515,35 @@
     private final int mNumPlanes;
     private final Surface mSurface;
 
-    private Handler mHandler;
-    private OnImageAvailableListener mImageListener;
+    private final Object mListenerLock = new Object();
+    private OnImageAvailableListener mListener;
+    private ListenerHandler mListenerHandler;
 
     /**
      * This field is used by native code, do not access or modify.
      */
     private long mNativeContext;
 
+    /**
+     * This custom handler runs asynchronously so callbacks don't get queued behind UI messages.
+     */
+    private final class ListenerHandler extends Handler {
+        public ListenerHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            OnImageAvailableListener listener;
+            synchronized (mListenerLock) {
+                listener = mListener;
+            }
+            if (listener != null) {
+                listener.onImageAvailable(ImageReader.this);
+            }
+        }
+    }
+
     private class SurfaceImage extends android.media.Image {
         public SurfaceImage() {
             mIsImageValid = false;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1250cbc..5175830 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -20,7 +20,9 @@
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
 import android.media.MediaFormat;
+import android.os.Bundle;
 import android.view.Surface;
+
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Map;
@@ -576,7 +578,7 @@
      * Change a video encoder's target bitrate on the fly. The value is an
      * Integer object containing the new bitrate in bps.
      */
-    public static final String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+    public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
 
     /**
      * Temporarily suspend/resume encoding of input data. While suspended
@@ -598,7 +600,7 @@
     /**
      * Communicate additional parameter changes to the component instance.
      */
-    public final void setParameters(Map<String, Object> params) {
+    public final void setParameters(Bundle params) {
         if (params == null) {
             return;
         }
@@ -607,9 +609,9 @@
         Object[] values = new Object[params.size()];
 
         int i = 0;
-        for (Map.Entry<String, Object> entry: params.entrySet()) {
-            keys[i] = entry.getKey();
-            values[i] = entry.getValue();
+        for (final String key: params.keySet()) {
+            keys[i] = key;
+            values[i] = params.get(key);
             ++i;
         }
 
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index ab686e6..143ddf2 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -138,7 +138,7 @@
     private static final int MSG_PROMOTE_RCC = 6;
     private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
     private static final int MSG_RCC_SEEK_REQUEST = 8;
-    private static final int MSG_RCC_UPDATE_METADATA_LONG = 9;
+    private static final int MSG_RCC_UPDATE_METADATA = 9;
 
     // sendMsg() flags
     /** If the msg is already queued, replace it with this one. */
@@ -206,9 +206,9 @@
                             msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
                     break;
 
-                case MSG_RCC_UPDATE_METADATA_LONG:
-                    onUpdateRemoteControlClientMetadataLong(msg.arg1 /*genId*/, msg.arg2 /*key*/,
-                            ((Long)msg.obj).longValue() /* value */);
+                case MSG_RCC_UPDATE_METADATA:
+                    onUpdateRemoteControlClientMetadata(msg.arg1 /*genId*/, msg.arg2 /*key*/,
+                            (Rating) msg.obj /* value */);
                     break;
 
                 case MSG_PROMOTE_RCC:
@@ -720,11 +720,7 @@
         }
     }
 
-    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
-        if (keyEvent == null) {
-            return false;
-        }
-        final int keyCode = keyEvent.getKeyCode();
+    protected static boolean isMediaKeyCode(int keyCode) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_MUTE:
             case KeyEvent.KEYCODE_HEADSETHOOK:
@@ -740,11 +736,17 @@
             case KeyEvent.KEYCODE_MEDIA_CLOSE:
             case KeyEvent.KEYCODE_MEDIA_EJECT:
             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-                break;
+                return true;
             default:
                 return false;
         }
-        return true;
+    }
+
+    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
+        if (keyEvent == null) {
+            return false;
+        }
+        return MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode());
     }
 
     /**
@@ -2080,20 +2082,20 @@
         }
     }
 
-    protected void updateRemoteControlClientMetadata(int genId, int key, long value) {
-        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA_LONG, SENDMSG_QUEUE,
-                genId /* arg1 */, key /* arg2 */, Long.valueOf(value) /* obj */, 0 /* delay */);
+    protected void updateRemoteControlClientMetadata(int genId, int key, Rating value) {
+        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA, SENDMSG_QUEUE,
+                genId /* arg1 */, key /* arg2 */, value /* obj */, 0 /* delay */);
     }
 
-    private void onUpdateRemoteControlClientMetadataLong(int genId, int key, long value) {
-        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadataLong(genId=" + genId +
-                ", what=" + key + ",val=" + value + ")");
+    private void onUpdateRemoteControlClientMetadata(int genId, int key, Rating value) {
+        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadata(genId=" + genId +
+                ", what=" + key + ",rating=" + value + ")");
         synchronized(mRCStack) {
             synchronized(mCurrentRcLock) {
                 if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
                     try {
                         switch (key) {
-                            case RemoteControlClient.MetadataEditor.LONG_KEY_RATING_BY_USER:
+                            case MediaMetadataEditor.RATING_KEY_BY_USER:
                                 mCurrentRcClient.updateMetadata(genId, key, value);
                                 break;
                             default:
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 16ae43d..0f7906e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -85,8 +85,8 @@
     public static final String KEY_MIME = "mime";
 
     /**
-     * A key describing the language of the content.
-     * The associated value is a string.
+     * A key describing the language of the content, using either ISO 639-1
+     * or 639-2/T codes.  The associated value is a string.
      */
     public static final String KEY_LANGUAGE = "language";
 
@@ -222,26 +222,36 @@
     public static final String KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
 
     /**
-     * A key for boolean AUTOSELECT field. Tracks with AUTOSELECT=true are
-     * considered when automatically selecting a track without specific user
-     * choice (as defined by HLS).
-     * @hide
+     * A key for boolean AUTOSELECT behavior for the track. Tracks with AUTOSELECT=true
+     * are considered when automatically selecting a track without specific user
+     * choice, based on the current locale.
+     * This is currently only used for subtitle tracks, when the user selected
+     * 'Default' for the captioning locale.
+     * The associated value is an integer, where non-0 means TRUE.  This is an optional
+     * field; if not specified, AUTOSELECT defaults to TRUE.
      */
-    public static final String KEY_AUTOSELECT = "autoselect";
+    public static final String KEY_IS_AUTOSELECT = "is-autoselect";
 
     /**
-     * A key for boolean DEFAULT field. The track with DEFAULT=true is selected
-     * in the absence of a specific user choice (as defined by HLS).
-     * @hide
+     * A key for boolean DEFAULT behavior for the track. The track with DEFAULT=true is
+     * selected in the absence of a specific user choice.
+     * This is currently only used for subtitle tracks, when the user selected
+     * 'Default' for the captioning locale.
+     * The associated value is an integer, where non-0 means TRUE.  This is an optional
+     * field; if not specified, DEFAULT is considered to be FALSE.
      */
-    public static final String KEY_DEFAULT = "default";
+    public static final String KEY_IS_DEFAULT = "is-default";
+
 
     /**
-     * A key for boolean FORCED field for subtitle tracks. True if it is a
-     * forced subtitle track.
-     * @hide
+     * A key for the FORCED field for subtitle tracks. True if it is a
+     * forced subtitle track.  Forced subtitle tracks are essential for the
+     * content and are shown even when the user turns off Captions.  They
+     * are used for example to translate foreign/alien dialogs or signs.
+     * The associated value is an integer, where non-0 means TRUE.  This is an
+     * optional field; if not specified, FORCED defaults to FALSE.
      */
-    public static final String KEY_FORCED = "forced";
+    public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
 
     /* package private */ MediaFormat(Map<String, Object> map) {
         mMap = map;
@@ -370,9 +380,10 @@
     /**
      * Creates a minimal subtitle format.
      * @param mime The mime type of the content.
-     * @param language The language of the content.  Specify "und" if language
-     *        information is only included in the content (similarly, if there
-     *        are multiple language tracks in the content.)
+     * @param language The language of the content, using either ISO 639-1 or 639-2/T
+     *        codes.  Specify null or "und" if language information is only included
+     *        in the content.  (This will also work if there are multiple language
+     *        tracks in the content.)
      */
     public static final MediaFormat createSubtitleFormat(
             String mime,
diff --git a/media/java/android/media/MediaMetadataEditor.java b/media/java/android/media/MediaMetadataEditor.java
new file mode 100644
index 0000000..373ba11
--- /dev/null
+++ b/media/java/android/media/MediaMetadataEditor.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+/**
+ * An abstract class for editing and storing metadata that can be published by
+ * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)}
+ * method to instantiate a {@link RemoteControlClient.MetadataEditor} object.
+ */
+public abstract class MediaMetadataEditor {
+
+    private final static String TAG = "MediaMetadataEditor";
+    /**
+     * @hide
+     */
+    protected MediaMetadataEditor() {
+    }
+
+    // Public keys for metadata used by RemoteControlClient and RemoteController.
+    // Note that these keys are defined here, and not in MediaMetadataRetriever
+    // because they are not supported by the MediaMetadataRetriever features.
+    /**
+     * The metadata key for the content artwork / album art.
+     */
+    public final static int BITMAP_KEY_ARTWORK =
+            RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK;
+
+    /**
+     * The metadata key for the content's average rating, not the user's rating.
+     * The value associated with this key is a {@link Rating} instance.
+     * @see #RATING_KEY_BY_USER
+     */
+    public final static int RATING_KEY_BY_OTHERS = 101;
+
+    /**
+     * The metadata key for the content's user rating.
+     * The value associated with this key is a {@link Rating} instance.
+     * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
+     * receiving user rating values through the
+     * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
+     */
+    public final static int RATING_KEY_BY_USER = 0x10000001;
+
+    /**
+     * @hide
+     * Editable key mask
+     */
+    public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
+
+
+    /**
+     * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance
+     * was created or since {@link #clear()} was called.
+     */
+    public abstract void apply();
+
+
+    /**
+     * @hide
+     * Mask of editable keys.
+     */
+    protected long mEditableKeys;
+
+    /**
+     * @hide
+     */
+    protected boolean mMetadataChanged = false;
+
+    /**
+     * @hide
+     */
+    protected boolean mApplied = false;
+
+    /**
+     * @hide
+     */
+    protected boolean mArtworkChanged = false;
+
+    /**
+     * @hide
+     */
+    protected Bitmap mEditorArtwork;
+
+    /**
+     * @hide
+     */
+    protected Bundle mEditorMetadata;
+
+
+    /**
+     * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
+     * created or since this method was last called.
+     * Note that clearing the metadata doesn't reset the editable keys
+     * (use {@link #removeEditableKeys()} instead).
+     */
+    public synchronized void clear() {
+        if (mApplied) {
+            Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor");
+            return;
+        }
+        mEditorMetadata.clear();
+        mEditorArtwork = null;
+    }
+
+    /**
+     * Flags the given key as being editable.
+     * This should only be used by metadata publishers, such as {@link RemoteControlClient},
+     * which will declare the metadata field as eligible to be updated, with new values
+     * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
+     * @param key the type of metadata that can be edited. The supported key is
+     *     {@link #RATING_KEY_BY_USER}.
+     */
+    public synchronized void addEditableKey(int key) {
+        if (mApplied) {
+            Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
+            return;
+        }
+        // only one editable key at the moment, so we're not wasting memory on an array
+        // of editable keys to check the validity of the key, just hardcode the supported key.
+        if (key == RATING_KEY_BY_USER) {
+            mEditableKeys |= (KEY_EDITABLE_MASK & key);
+            mMetadataChanged = true;
+        } else {
+            Log.e(TAG, "Metadata key " + key + " cannot be edited");
+        }
+    }
+
+    /**
+     * Causes all metadata fields to be read-only.
+     */
+    public synchronized void removeEditableKeys() {
+        if (mApplied) {
+            Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor");
+            return;
+        }
+        if (mEditableKeys != 0) {
+            mEditableKeys = 0;
+            mMetadataChanged = true;
+        }
+    }
+
+    /**
+     * Retrieves the keys flagged as editable.
+     * @return null if there are no editable keys, or an array containing the keys.
+     */
+    public synchronized int[] getEditableKeys() {
+        // only one editable key supported here
+        if (mEditableKeys == RATING_KEY_BY_USER) {
+            int[] keys = { RATING_KEY_BY_USER };
+            return keys;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Adds textual information.
+     * Note that none of the information added after {@link #apply()} has been called,
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key The identifier of a the metadata field to set. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
+     * @param value The text for the given key, or {@code null} to signify there is no valid
+     *      information for the field.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     */
+    public synchronized MediaMetadataEditor putString(int key, String value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+            throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+        }
+        mEditorMetadata.putString(String.valueOf(key), value);
+        mMetadataChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds numerical information.
+     * Note that none of the information added after {@link #apply()} has been called
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key the identifier of a the metadata field to set. Valid values are
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
+     *      expressed in milliseconds),
+     *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+     * @param value The long value for the given key
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     */
+    public synchronized MediaMetadataEditor putLong(int key, long value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+            throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+        }
+        mEditorMetadata.putLong(String.valueOf(key), value);
+        mMetadataChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds image.
+     * @param key the identifier of the bitmap to set. The only valid value is
+     *      {@link #BITMAP_KEY_ARTWORK}
+     * @param bitmap The bitmap for the artwork, or null if there isn't any.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     * @see android.graphics.Bitmap
+     */
+    public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        if (key != BITMAP_KEY_ARTWORK) {
+            throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+        }
+        mEditorArtwork = bitmap;
+        mArtworkChanged = true;
+        return this;
+    }
+
+    /**
+     * Adds information stored as an instance.
+     * Note that none of the information added after {@link #apply()} has been called
+     * will be available to consumers of metadata stored by the MediaMetadataEditor.
+     * @param key the identifier of a the metadata field to set. Valid keys for a:
+     *     <ul>
+     *     <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
+     *     <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
+     *     <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
+     *     <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
+     *         and {@link #RATING_KEY_BY_USER}.</li>
+     *     </ul>
+     * @param value the metadata to add.
+     * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
+     *      calls together.
+     * @throws IllegalArgumentException
+     */
+    public synchronized MediaMetadataEditor putObject(int key, Object value)
+            throws IllegalArgumentException {
+        if (mApplied) {
+            Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
+            return this;
+        }
+        switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+            case METADATA_TYPE_LONG:
+                if (value instanceof Long) {
+                    return putLong(key, ((Long)value).longValue());
+                } else {
+                    throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
+                }
+            case METADATA_TYPE_STRING:
+                if ((value == null) || (value instanceof String)) {
+                    return putString(key, (String) value);
+                } else {
+                    throw(new IllegalArgumentException("Not a String for key "+ key));
+                }
+            case METADATA_TYPE_RATING:
+                mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
+                mMetadataChanged = true;
+                break;
+            case METADATA_TYPE_BITMAP:
+                if ((value == null) || (value instanceof Bitmap))  {
+                    return putBitmap(key, (Bitmap) value);
+                } else {
+                    throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
+                }
+            default:
+                throw(new IllegalArgumentException("Invalid key "+ key));
+        }
+        return this;
+    }
+
+
+    /**
+     * Returns the long value for the key.
+     * @param key one of the keys supported in {@link #putLong(int, long)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the long value for the key, or the supplied default value if the key is not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized long getLong(int key, long defaultValue)
+            throws IllegalArgumentException {
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
+            throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
+        }
+        return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
+    }
+
+    /**
+     * Returns the {@link String} value for the key.
+     * @param key one of the keys supported in {@link #putString(int, String)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the {@link String} value for the key, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized String getString(int key, String defaultValue)
+            throws IllegalArgumentException {
+        if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
+            throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
+        }
+        return mEditorMetadata.getString(String.valueOf(key), defaultValue);
+    }
+
+    /**
+     * Returns the {@link Bitmap} value for the key.
+     * @param key the {@link #BITMAP_KEY_ARTWORK} key
+     * @param defaultValue the value returned if the key is not present
+     * @return the {@link Bitmap} value for the key, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
+            throws IllegalArgumentException {
+        if (key != BITMAP_KEY_ARTWORK) {
+            throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
+        }
+        return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+    }
+
+    /**
+     * Returns an object representation of the value for the key
+     * @param key one of the keys supported in {@link #putObject(int, Object)}
+     * @param defaultValue the value returned if the key is not present
+     * @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
+     *     {@link Rating} depending on the key value, or the supplied default value if the key is
+     *     not present
+     * @throws IllegalArgumentException
+     */
+    public synchronized Object getObject(int key, Object defaultValue)
+            throws IllegalArgumentException {
+        switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
+            case METADATA_TYPE_LONG:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getLong(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_STRING:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getString(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_RATING:
+                if (mEditorMetadata.containsKey(String.valueOf(key))) {
+                    return mEditorMetadata.getParcelable(String.valueOf(key));
+                } else {
+                    return defaultValue;
+                }
+            case METADATA_TYPE_BITMAP:
+                // only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
+                if (key == BITMAP_KEY_ARTWORK) {
+                    return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
+                } // else: fall through to invalid key handling
+            default:
+                throw(new IllegalArgumentException("Invalid key "+ key));
+        }
+    }
+
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_INVALID = -1;
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_LONG = 0;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_STRING = 1;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_BITMAP = 2;
+
+    /**
+     * @hide
+     */
+    protected static final int METADATA_TYPE_RATING = 3;
+
+    /**
+     * @hide
+     */
+    protected static final SparseIntArray METADATA_KEYS_TYPE;
+
+    static {
+        METADATA_KEYS_TYPE = new SparseIntArray(17);
+        // NOTE: if adding to the list below, make sure you increment the array initialization size
+        // keys with long values
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
+        // keys with String values
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(
+                MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
+        METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
+        // keys with Bitmap values
+        METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
+        // keys with Rating values
+        METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
+        METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
+    }
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7acf8af..deba2cc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1606,9 +1606,9 @@
             } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
                 mFormat = MediaFormat.createSubtitleFormat(
                     MEDIA_MIMETYPE_TEXT_VTT, language);
-                mFormat.setInteger(MediaFormat.KEY_AUTOSELECT, in.readInt());
-                mFormat.setInteger(MediaFormat.KEY_DEFAULT, in.readInt());
-                mFormat.setInteger(MediaFormat.KEY_FORCED, in.readInt());
+                mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
+                mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
+                mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
             } else {
                 mFormat = new MediaFormat();
                 mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
@@ -1638,9 +1638,9 @@
             dest.writeString(getLanguage());
 
             if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_AUTOSELECT));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_DEFAULT));
-                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_FORCED));
+                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT));
+                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT));
+                dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE));
             }
         }
 
@@ -1765,15 +1765,21 @@
     @Override
     public void onSubtitleTrackSelected(SubtitleTrack track) {
         if (mSelectedSubtitleTrackIndex >= 0) {
-            deselectTrack(mSelectedSubtitleTrackIndex);
+            try {
+                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
+            } catch (IllegalStateException e) {
+            }
+            mSelectedSubtitleTrackIndex = -1;
         }
-        mSelectedSubtitleTrackIndex = -1;
         setOnSubtitleDataListener(null);
         for (int i = 0; i < mInbandSubtitleTracks.length; i++) {
             if (mInbandSubtitleTracks[i] == track) {
                 Log.v(TAG, "Selecting subtitle track " + i);
-                selectTrack(i);
                 mSelectedSubtitleTrackIndex = i;
+                try {
+                    selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
+                } catch (IllegalStateException e) {
+                }
                 setOnSubtitleDataListener(mSubtitleDataListener);
                 break;
             }
@@ -2046,13 +2052,30 @@
 
     private void selectOrDeselectTrack(int index, boolean select)
             throws IllegalStateException {
-        // ignore out-of-band tracks
-        TrackInfo[] trackInfo = getInbandTrackInfo();
-        if (index >= trackInfo.length &&
-                index < trackInfo.length + mOutOfBandSubtitleTracks.size()) {
+        // handle subtitle track through subtitle controller
+        SubtitleTrack track = null;
+        if (index < mInbandSubtitleTracks.length) {
+            track = mInbandSubtitleTracks[index];
+        } else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
+            track = mOutOfBandSubtitleTracks.get(index - mInbandSubtitleTracks.length);
+        }
+
+        if (mSubtitleController != null && track != null) {
+            if (select) {
+                mSubtitleController.selectTrack(track);
+            } else if (mSubtitleController.getSelectedTrack() == track) {
+                mSubtitleController.selectTrack(null);
+            } else {
+                Log.w(TAG, "trying to deselect track that was not selected");
+            }
             return;
         }
 
+        selectOrDeselectInbandTrack(index, select);
+    }
+
+    private void selectOrDeselectInbandTrack(int index, boolean select)
+            throws IllegalStateException {
         Parcel request = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         try {
diff --git a/media/java/android/media/Rating.aidl b/media/java/android/media/Rating.aidl
new file mode 100644
index 0000000..1dc336a
--- /dev/null
+++ b/media/java/android/media/Rating.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable Rating;
diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java
new file mode 100644
index 0000000..82c0392
--- /dev/null
+++ b/media/java/android/media/Rating.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class to encapsulate rating information used as content metadata.
+ * A rating is defined by its rating style (see {@link #RATING_HEART},
+ * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+ * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
+ * be defined as "unrated"), both of which are defined when the rating instance is constructed
+ * through one of the factory methods.
+ */
+public final class Rating implements Parcelable {
+
+    private final static String TAG = "Rating";
+
+    /**
+     * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
+     * indicate the content referred to is a favorite (or not).
+     */
+    public final static int RATING_HEART = 1;
+
+    /**
+     * A rating style for "thumb up" vs "thumb down".
+     */
+    public final static int RATING_THUMB_UP_DOWN = 2;
+
+    /**
+     * A rating style with 0 to 3 stars.
+     */
+    public final static int RATING_3_STARS = 3;
+
+    /**
+     * A rating style with 0 to 4 stars.
+     */
+    public final static int RATING_4_STARS = 4;
+
+    /**
+     * A rating style with 0 to 5 stars.
+     */
+    public final static int RATING_5_STARS = 5;
+
+    /**
+     * A rating style expressed as a percentage.
+     */
+    public final static int RATING_PERCENTAGE = 6;
+
+    private final static float RATING_NOT_RATED = -1.0f;
+
+    private final int mRatingStyle;
+
+    private final float mRatingValue;
+
+    private Rating(int ratingStyle, float rating) {
+        mRatingStyle = ratingStyle;
+        mRatingValue = rating;
+    }
+
+
+    /**
+     * @hide
+     */
+    @Override
+    public String toString () {
+        return "Rating:style=" + mRatingStyle + " rating="
+                + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
+    }
+
+    @Override
+    public int describeContents() {
+        return mRatingStyle;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRatingStyle);
+        dest.writeFloat(mRatingValue);
+    }
+
+    public static final Parcelable.Creator<Rating> CREATOR
+            = new Parcelable.Creator<Rating>() {
+        /**
+         * Rebuilds a Rating previously stored with writeToParcel().
+         * @param p    Parcel object to read the Rating from
+         * @return a new Rating created from the data in the parcel
+         */
+        public Rating createFromParcel(Parcel p) {
+            return new Rating(p.readInt(), p.readFloat());
+        }
+        public Rating[] newArray(int size) {
+            return new Rating[size];
+        }
+    };
+
+    /**
+     * Return a Rating instance with no rating.
+     * Create and return a new Rating instance with no rating known for the given
+     * rating style.
+     * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+     *    or {@link #RATING_PERCENTAGE}.
+     * @return null if an invalid rating style is passed, a new Rating instance otherwise.
+     */
+    public static Rating newUnratedRating(int ratingStyle) {
+        switch(ratingStyle) {
+            case RATING_HEART:
+            case RATING_THUMB_UP_DOWN:
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+            case RATING_PERCENTAGE:
+                return new Rating(ratingStyle, RATING_NOT_RATED);
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Return a Rating instance with a heart-based rating.
+     * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
+     * and a heart-based rating.
+     * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
+     * @return a new Rating instance.
+     */
+    public static Rating newHeartRating(boolean hasHeart) {
+        return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
+    }
+
+    /**
+     * Return a Rating instance with a thumb-based rating.
+     * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
+     * rating style, and a "thumb up" or "thumb down" rating.
+     * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
+     * @return a new Rating instance.
+     */
+    public static Rating newThumbRating(boolean thumbIsUp) {
+        return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
+    }
+
+    /**
+     * Return a Rating instance with a star-based rating.
+     * Create and return a new Rating instance with one of the star-base rating styles
+     * and the given integer or fractional number of stars. Non integer values can for instance
+     * be used to represent an average rating value, which might not be an integer number of stars.
+     * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
+     *     {@link #RATING_5_STARS}.
+     * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
+     *     the rating style.
+     * @return null if the rating style is invalid, or the rating is out of range,
+     *     a new Rating instance otherwise.
+     */
+    public static Rating newStarRating(int starRatingStyle, float starRating) {
+        float maxRating = -1.0f;
+        switch(starRatingStyle) {
+            case RATING_3_STARS:
+                maxRating = 3.0f;
+                break;
+            case RATING_4_STARS:
+                maxRating = 4.0f;
+                break;
+            case RATING_5_STARS:
+                maxRating = 5.0f;
+                break;
+            default:
+                Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
+                        return null;
+        }
+        if ((starRating < 0.0f) || (starRating > maxRating)) {
+            Log.e(TAG, "Trying to set out of range star-based rating");
+            return null;
+        }
+        return new Rating(starRatingStyle, starRating);
+    }
+
+    /**
+     * Return a Rating instance with a percentage-based rating.
+     * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
+     * rating style, and a rating of the given percentage.
+     * @param percent the value of the rating
+     * @return null if the rating is out of range, a new Rating instance otherwise.
+     */
+    public static Rating newPercentageRating(float percent) {
+        if ((percent < 0.0f) || (percent > 100.0f)) {
+            Log.e(TAG, "Invalid percentage-based rating value");
+            return null;
+        } else {
+            return new Rating(RATING_PERCENTAGE, percent);
+        }
+    }
+
+    /**
+     * Return whether there is a rating value available.
+     * @return true if the instance was not created with {@link #newUnratedRating(int)}.
+     */
+    public boolean isRated() {
+        return mRatingValue >= 0.0f;
+    }
+
+    /**
+     * Return the rating style.
+     * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
+     *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
+     *    or {@link #RATING_PERCENTAGE}.
+     */
+    public int getRatingStyle() {
+        return mRatingStyle;
+    }
+
+    /**
+     * Return whether the rating is "heart selected".
+     * @return true if the rating is "heart selected", false if the rating is "heart unselected",
+     *    if the rating style is not {@link #RATING_HEART} or if it is unrated.
+     */
+    public boolean hasHeart() {
+        if (mRatingStyle != RATING_HEART) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    /**
+     * Return whether the rating is "thumb up".
+     * @return true if the rating is "thumb up", false if the rating is "thumb down",
+     *    if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
+     */
+    public boolean isThumbUp() {
+        if (mRatingStyle != RATING_THUMB_UP_DOWN) {
+            return false;
+        } else {
+            return (mRatingValue == 1.0f);
+        }
+    }
+
+    /**
+     * Return the star-based rating value.
+     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+     *    not star-based, or if it is unrated.
+     */
+    public float getStarRating() {
+        switch (mRatingStyle) {
+            case RATING_3_STARS:
+            case RATING_4_STARS:
+            case RATING_5_STARS:
+                if (isRated()) {
+                    return mRatingValue;
+                }
+            default:
+                return -1.0f;
+        }
+    }
+
+    /**
+     * Return the percentage-based rating value.
+     * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
+     *    not percentage-based, or if it is unrated.
+     */
+    public float getPercentRating() {
+        if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
+            return -1.0f;
+        } else {
+            return mRatingValue;
+        }
+    }
+}
\ No newline at end of file
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 58f5d55..7613c89 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -297,8 +298,8 @@
      * Flag indicating a RemoteControlClient supports ratings.
      * This flag must be set in order for components that display the RemoteControlClient
      * information, to display ratings information, and, if ratings are declared editable
-     * (by calling {@link MetadataEditor#addEditableKey(int)} with the
-     * {@link MetadataEditor#LONG_KEY_RATING_BY_USER} key), it will enable the user to rate
+     * (by calling {@link MediaMetadataEditor#addEditableKey(int)} with the
+     * {@link MediaMetadataEditor#RATING_KEY_BY_USER} key), it will enable the user to rate
      * the media, with values being received through the interface set with
      * {@link #setMetadataUpdateListener(OnMetadataUpdateListener)}.
      * @see #setTransportControlFlags(int)
@@ -385,27 +386,6 @@
         mEventHandler = new EventHandler(this, looper);
     }
 
-    private static final int[] METADATA_KEYS_TYPE_STRING = {
-        MediaMetadataRetriever.METADATA_KEY_ALBUM,
-        MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
-        MediaMetadataRetriever.METADATA_KEY_TITLE,
-        MediaMetadataRetriever.METADATA_KEY_ARTIST,
-        MediaMetadataRetriever.METADATA_KEY_AUTHOR,
-        MediaMetadataRetriever.METADATA_KEY_COMPILATION,
-        MediaMetadataRetriever.METADATA_KEY_COMPOSER,
-        MediaMetadataRetriever.METADATA_KEY_DATE,
-        MediaMetadataRetriever.METADATA_KEY_GENRE,
-        MediaMetadataRetriever.METADATA_KEY_TITLE,
-        MediaMetadataRetriever.METADATA_KEY_WRITER };
-    private static final int[] METADATA_KEYS_TYPE_LONG = {
-        MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
-        MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
-        MediaMetadataRetriever.METADATA_KEY_DURATION,
-        MediaMetadataRetriever.METADATA_KEY_YEAR,
-        MetadataEditor.LONG_KEY_RATING_TYPE,
-        MetadataEditor.LONG_KEY_RATING_BY_OTHERS,
-        MetadataEditor.LONG_KEY_RATING_BY_USER};
-
     /**
      * Class used to modify metadata in a {@link RemoteControlClient} object.
      * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
@@ -414,28 +394,7 @@
      * for the associated client. Once the metadata has been "applied", you cannot reuse this
      * instance of the MetadataEditor.
      */
-    public class MetadataEditor {
-        /**
-         * Mask of editable keys.
-         */
-        private long mEditableKeys;
-        /**
-         * @hide
-         */
-        protected boolean mMetadataChanged;
-        /**
-         * @hide
-         */
-        protected boolean mArtworkChanged;
-        /**
-         * @hide
-         */
-        protected Bitmap mEditorArtwork;
-        /**
-         * @hide
-         */
-        protected Bundle mEditorMetadata;
-        private boolean mApplied = false;
+    public class MetadataEditor extends MediaMetadataEditor {
 
         // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
         private MetadataEditor() { }
@@ -450,73 +409,10 @@
          * The metadata key for the content artwork / album art.
          */
         public final static int BITMAP_KEY_ARTWORK = 100;
-        /**
-         * The metadata key qualifying the content rating.
-         * The value associated with this key may be: {@link #RATING_HEART},
-         * {@link #RATING_THUMB_UP_DOWN}, or a non-null positive integer expressing a maximum
-         * number of "stars" for the rating, for which a typical value is 3 or 5.
-         */
-        public final static int LONG_KEY_RATING_TYPE = 101;
-        /**
-         * The metadata key for the content's average rating, not the user's rating.
-         * The value associated with this key may be: an integer value between 0 and 100,
-         * or {@link #RATING_NOT_RATED} to express that no average rating is available.
-         * <p></p>
-         * Note that a rating value up to 100 is not incompatible with a rating type using up
-         * to 5 stars for instance, as the average may be an non-integer number of stars.
-         * <p></p>
-         * When the rating type is:
-         * <ul>
-         * <li>{@link #RATING_HEART}, a rating of 51 to 100 means "heart selected",</li>
-         * <li>{@link #RATING_THUMB_UP_DOWN}, a rating of 0 to 50 means "thumb down",
-         *     51 to 100 means "thumb up"</li>
-         * <li>a non-null positive integer, the rating value is mapped to the number of stars, e.g.
-         *     with a maximum of 5 stars, a rating of 0 maps to 0 stars, 1 to 20 maps to 1 star,
-         *     21 to 40 maps to 2 stars, etc.</li>
-         * </ul>
-         * @see #LONG_KEY_RATING_BY_USER
-         */
-        public final static int LONG_KEY_RATING_BY_OTHERS = 102;
-
-        // editable keys
-        /**
-         * @hide
-         * Editable key mask
-         */
-        public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
-        /**
-         * The metadata key for the content's user rating.
-         * The value associated with this key may be: an integer value between 0 and 100,
-         * or {@link #RATING_NOT_RATED} to express that the user hasn't rated this content.
-         * Rules for the interpretation of the rating value according to the rating style are
-         * the same as for {@link #LONG_KEY_RATING_BY_OTHERS}.
-         * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
-         * receiving user rating values through the
-         * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
-         */
-        public final static int LONG_KEY_RATING_BY_USER = 0x10000001;
-
-        /**
-         * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
-         * indicate the content referred to is a favorite (or not).
-         * @see #LONG_KEY_RATING_TYPE
-         */
-        public final static long RATING_HEART = -1;
-        /**
-         * A rating style for "thumb up" vs "thumb down".
-         * @see #LONG_KEY_RATING_TYPE
-         */
-        public final static long RATING_THUMB_UP_DOWN = -2;
-        /**
-         * A rating value indicating no rating is available.
-         * @see #LONG_KEY_RATING_BY_OTHERS
-         * @see #LONG_KEY_RATING_BY_USER
-         */
-        public final static long RATING_NOT_RATED = -101;
 
         /**
          * @hide
-         * TODO(jmtrivi) have lockscreen and music move to the new key name
+         * TODO(jmtrivi) have lockscreen move to the new key name and remove
          */
         public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
 
@@ -543,15 +439,7 @@
          */
         public synchronized MetadataEditor putString(int key, String value)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
-                throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
-            }
-            mEditorMetadata.putString(String.valueOf(key), value);
-            mMetadataChanged = true;
+            super.putString(key, value);
             return this;
         }
 
@@ -564,9 +452,7 @@
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
          *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
          *      expressed in milliseconds),
-         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR},
-         *      {@link #LONG_KEY_RATING_BY_OTHERS}, {@link #LONG_KEY_RATING_BY_USER},
-         *      {@link #LONG_KEY_RATING_TYPE}.
+         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
          * @param value The long value for the given key
          * @return Returns a reference to the same MetadataEditor object, so you can chain put
          *      calls together.
@@ -574,15 +460,7 @@
          */
         public synchronized MetadataEditor putLong(int key, long value)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
-                throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
-            }
-            mEditorMetadata.putLong(String.valueOf(key), value);
-            mMetadataChanged = true;
+            super.putLong(key, value);
             return this;
         }
 
@@ -596,69 +474,22 @@
          * @throws IllegalArgumentException
          * @see android.graphics.Bitmap
          */
+        @Override
         public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
                 throws IllegalArgumentException {
-            if (mApplied) {
-                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
-                return this;
-            }
-            if (key != BITMAP_KEY_ARTWORK) {
-                throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
-            }
-            mEditorArtwork = bitmap;
-            mArtworkChanged = true;
+            super.putBitmap(key, bitmap);
             return this;
         }
 
         /**
-         * Clears all the metadata that has been set since the MetadataEditor instance was
-         *     created with {@link RemoteControlClient#editMetadata(boolean)}.
+         * Clears all the metadata that has been set since the MetadataEditor instance was created
+         * (with {@link RemoteControlClient#editMetadata(boolean)}).
          * Note that clearing the metadata doesn't reset the editable keys
-         * (use {@link #clearEditableKeys()} instead).
+         * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
          */
+        @Override
         public synchronized void clear() {
-            if (mApplied) {
-                Log.e(TAG, "Can't clear a previously applied MetadataEditor");
-                return;
-            }
-            mEditorMetadata.clear();
-            mEditorArtwork = null;
-        }
-
-        /**
-         * Flag the given key as being editable.
-         * This will declare the metadata field as eligible to be updated, with new values
-         * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
-         * @param key the type of metadata that can be edited. The supported key is
-         *     {@link #LONG_KEY_RATING_BY_USER}.
-         */
-        public synchronized void addEditableKey(int key) {
-            if (mApplied) {
-                Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
-                return;
-            }
-            // only one editable key at the moment, so we're not wasting memory on an array
-            // of editable keys to check the validity of the key, just hardcode the supported key.
-            if (key == MetadataEditor.LONG_KEY_RATING_BY_USER) {
-                mEditableKeys |= (MetadataEditor.KEY_EDITABLE_MASK & key);
-                mMetadataChanged = true;
-            } else {
-                Log.e(TAG, "Metadata key " + key + " cannot be edited");
-            }
-        }
-
-        /**
-         * Causes all metadata fields to be read-only.
-         */
-        public synchronized void clearEditableKeys() {
-            if (mApplied) {
-                Log.e(TAG, "Can't clear editable keys of a previously applied MetadataEditor");
-                return;
-            }
-            if (mEditableKeys != 0) {
-                mEditableKeys = 0;
-                mMetadataChanged = true;
-            }
+            super.clear();
         }
 
         /**
@@ -881,30 +712,17 @@
     /**
      * Interface definition for a callback to be invoked when one of the metadata values has
      * been updated.
+     * Implement this interface to receive metadata updates after registering your listener
+     * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
      */
-    public interface OnMetadataUpdateListener  {
+    public interface OnMetadataUpdateListener {
         /**
          * Called on the implementer to notify that the metadata field for the given key has
-         * been updated to the new value of type <code>long</long>.
-         * @param key the identifier of the updated metadata field of type <code>long</long>.
-         * @param newValue the new <code>long</long> value for the key
+         * been updated to the new value.
+         * @param key the identifier of the updated metadata field.
+         * @param newValue the Object storing the new value for the key.
          */
-        void onMetadataUpdateLong(int key, long newValue);
-        /**
-         * Called on the implementer to notify that the metadata field for the given key has
-         * been updated to the new <code>String</long>.
-         * @param key the identifier of the updated metadata field of type <code>String</long>.
-         * @param newValue the new <code>String</long> value for the key
-         */
-        void onMetadataUpdateString(int key, String newValue);
-        /**
-         * Called on the implementer to notify that the metadata field for the given key has
-         * been updated to the new {@link android.graphics.Bitmap}.
-         * @param key the identifier of the updated metadata field of type
-         *     {@link android.graphics.Bitmap}.
-         * @param newValue the new {@link android.graphics.Bitmap} for the key
-         */
-        void onMetadataUpdateBitmap(int key, Bitmap newValue);
+        public abstract void onMetadataUpdate(int key, Object newValue);
     }
 
     /**
@@ -1338,12 +1156,11 @@
             }
         }
 
-        public void updateMetadata(int generationId, int key, long value) {
+        public void updateMetadata(int generationId, int key, Rating value) {
             // only post messages, we can't block here
             if (mEventHandler != null) {
                 mEventHandler.sendMessage(mEventHandler.obtainMessage(
-                        MSG_UPDATE_METADATA_LONG, generationId /* arg1 */, key /* arg2*/,
-                        new Long(value)));
+                        MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
             }
         }
     };
@@ -1389,7 +1206,7 @@
     private final static int MSG_SEEK_TO = 10;
     private final static int MSG_POSITION_DRIFT_CHECK = 11;
     private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
-    private final static int MSG_UPDATE_METADATA_LONG = 13;
+    private final static int MSG_UPDATE_METADATA = 13;
 
     private class EventHandler extends Handler {
         public EventHandler(RemoteControlClient rcc, Looper looper) {
@@ -1443,8 +1260,8 @@
                 case MSG_DISPLAY_WANTS_POS_SYNC:
                     onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
                     break;
-                case MSG_UPDATE_METADATA_LONG:
-                    onUpdateMetadata(msg.arg1, msg.arg2, ((Long)msg.obj).longValue());
+                case MSG_UPDATE_METADATA:
+                    onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
                     break;
                 default:
                     Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
@@ -1725,10 +1542,10 @@
         }
     }
 
-    private void onUpdateMetadata(int generationId, int key, long value) {
+    private void onUpdateMetadata(int generationId, int key, Object value) {
         synchronized (mCacheLock) {
             if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
-                mMetadataUpdateListener.onMetadataUpdateLong(key, value);
+                mMetadataUpdateListener.onMetadataUpdate(key, value);
             }
         }
     }
@@ -1771,24 +1588,6 @@
         return bitmap;
     }
 
-    /**
-     *  Fast routine to go through an array of allowed keys and return whether the key is part
-     *  of that array
-     * @param key the key value
-     * @param validKeys the array of valid keys for a given type
-     * @return true if the key is part of the array, false otherwise
-     */
-    private static boolean validTypeForKey(int key, int[] validKeys) {
-        try {
-            for (int i = 0 ; ; i++) {
-                if (key == validKeys[i]) {
-                    return true;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            return false;
-        }
-    }
 
     /**
      * Returns whether, for the given playback state, the playback position is expected to
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
new file mode 100644
index 0000000..6266160
--- /dev/null
+++ b/media/java/android/media/RemoteController.java
@@ -0,0 +1,796 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.media.IRemoteControlDisplay;
+import android.media.MediaMetadataEditor;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ * CANDIDATE FOR PUBLIC API
+ * The RemoteController class is used to control media playback, display and update media metadata
+ * and playback status, published by applications using the {@link RemoteControlClient} class.
+ * <p>
+ * A RemoteController shall be registered through
+ * {@link AudioManager#registerRemoteController(RemoteController)} in order for the system to send
+ * media event updates to the listener set in
+ * {@link #setOnClientUpdateListener(OnClientUpdateListener)}. This listener is a subclass of
+ * the {@link OnClientUpdateListener} abstract class. Override its methods to receive the
+ * information published by the active {@link RemoteControlClient} instances.
+ * By default an {@link OnClientUpdateListener} implementation will not receive bitmaps for album
+ * art. Use {@link #setBitmapConfiguration(boolean, int, int)} to receive images as well.
+ * <p>
+ * A RemoteController can also be used without being registered, when it is only meant to send
+ * media key events (for play or stop events for instance),
+ * with {@link #sendMediaKeyEvent(KeyEvent)}.
+ */
+public class RemoteController
+{
+    private final static int MAX_BITMAP_DIMENSION = 512;
+    private final static int TRANSPORT_UNKNOWN = 0;
+    private RcDisplay mRcd;
+    private final static String TAG = "RemoteController";
+    private final static boolean DEBUG = false;
+    private final static Object mGenLock = new Object();
+    private final static Object mInfoLock = new Object();
+    private Context mContext;
+    private AudioManager mAudioManager;
+    private MetadataEditor mMetadataEditor;
+
+    /**
+     * Synchronized on mGenLock
+     */
+    private int mClientGenerationIdCurrent = 0;
+
+    /**
+     * Synchronized on mInfoLock
+     */
+    private boolean mIsRegistered = false;
+    private PendingIntent mClientPendingIntentCurrent;
+    private OnClientUpdateListener mOnClientUpdateListener;
+    private PlaybackInfo mLastPlaybackInfo;
+    private int mLastTransportControlFlags = TRANSPORT_UNKNOWN;
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param ctxt non-null {@link Context}
+     * @throws java.lang.IllegalArgumentException
+     */
+    public RemoteController(Context ctxt) throws IllegalArgumentException {
+        if (ctxt == null) {
+            throw new IllegalArgumentException("Invalid null Context");
+        }
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else {
+            mEventHandler = null;
+            Log.e(TAG, "RemoteController() couldn't find main application thread");
+        }
+        mContext = ctxt;
+        mRcd = new RcDisplay();
+        mAudioManager = (AudioManager) ctxt.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param looper
+     * @param ctxt non-null {@link Context}
+     * @throws java.lang.IllegalArgumentException
+     */
+    public RemoteController(Looper looper, Context ctxt) throws IllegalArgumentException {
+        if (ctxt == null) {
+            throw new IllegalArgumentException("Invalid null Context");
+        }
+        mEventHandler = new EventHandler(this, looper);
+        mContext = ctxt;
+        mRcd = new RcDisplay();
+        mAudioManager = (AudioManager) ctxt.getSystemService(Context.AUDIO_SERVICE);
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     */
+    public static abstract class OnClientUpdateListener {
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param clearing
+         */
+        public void onClientReset(boolean clearing) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param state
+         */
+        public void onClientPlaybackStateUpdate(int state) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param state
+         * @param stateChangeTimeMs
+         * @param currentPosMs
+         * @param speed
+         */
+        public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
+                long currentPosMs, float speed) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param transportControlFlags
+         * @param posCapabilities
+         */
+        public void onClientTransportControlUpdate(int transportControlFlags) { }
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         * @param metadataEditor
+         */
+        public void onClientMetadataUpdate(MetadataEditor metadataEditor) { }
+    };
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param l
+     */
+    public void setOnClientUpdateListener(OnClientUpdateListener l) {
+        synchronized(mInfoLock) {
+            mOnClientUpdateListener = l;
+            if (!mIsRegistered) {
+                // since the object is not registered, it hasn't received any information from
+                // RemoteControlClients yet, so we can exit here.
+                return;
+            }
+            if (mLastPlaybackInfo != null) {
+                sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+                        mClientGenerationIdCurrent /*arg1*/, 0,
+                        mLastPlaybackInfo /*obj*/, 0 /*delay*/);
+            }
+            if (mLastTransportControlFlags != TRANSPORT_UNKNOWN) {
+                sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+                        mClientGenerationIdCurrent /*arg1*/, mLastTransportControlFlags /*arg2*/,
+                        null /*obj*/, 0 /*delay*/);
+            }
+            if (mMetadataEditor != null) {
+                sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                        mClientGenerationIdCurrent /*arg1*/, 0 /*arg2*/,
+                        mMetadataEditor /*obj*/, 0 /*delay*/);
+            }
+        }
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Send a simulated key event for a media button.
+     * May be used without registering the RemoteController
+     * with {@link AudioManager#registerRemoteController(RemoteController)}. To simulate a key
+     * press, you must first send a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then
+     * another event with the {@link KeyEvent#ACTION_UP} action.
+     * <p> When used from a registered RemoteController, the key event will be sent to the
+     * application currently promoted to publish its media metadata and playback state (there may be
+     * none under some circumstances). With an unregistered RemoteController, the key event will be
+     * sent to the current media key event consumer
+     * (see {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}).
+     * @param keyEvent a {@link KeyEvent} instance whose key code is one of
+     *     {@link KeyEvent.KEYCODE_MUTE},
+     *     {@link KeyEvent.KEYCODE_HEADSETHOOK},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PLAY},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PAUSE},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE},
+     *     {@link KeyEvent.KEYCODE_MEDIA_STOP},
+     *     {@link KeyEvent.KEYCODE_MEDIA_NEXT},
+     *     {@link KeyEvent.KEYCODE_MEDIA_PREVIOUS},
+     *     {@link KeyEvent.KEYCODE_MEDIA_REWIND},
+     *     {@link KeyEvent.KEYCODE_MEDIA_RECORD},
+     *     {@link KeyEvent.KEYCODE_MEDIA_FAST_FORWARD},
+     *     {@link KeyEvent.KEYCODE_MEDIA_CLOSE},
+     *     {@link KeyEvent.KEYCODE_MEDIA_EJECT},
+     *     or {@link KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK}.
+     */
+    public int sendMediaKeyEvent(KeyEvent keyEvent) {
+        if (!MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode())) {
+            Log.e(TAG, "Cannot use sendMediaKeyEvent() for a non-media key event");
+            return ERROR_BAD_VALUE;
+        }
+        boolean registered = false;
+        final PendingIntent pi;
+        synchronized(mInfoLock) {
+            registered = mIsRegistered;
+            pi = mClientPendingIntentCurrent;
+        }
+        if (registered) {
+            if (pi != null) {
+                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+                intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                try {
+                    pi.send(mContext, 0, intent);
+                } catch (CanceledException e) {
+                    Log.e(TAG, "Error sending intent for media button down: ", e);
+                    return ERROR;
+                }
+            } else {
+                Log.i(TAG, "No-op when sending key click, no receiver right now");
+                return ERROR;
+            }
+        } else {
+            mAudioManager.dispatchMediaKeyEvent(keyEvent);
+        }
+        return SUCCESS;
+    }
+
+
+    // Error codes
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Successful operation.
+     */
+    public  static final int SUCCESS            = 0;
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Unspecified error.
+     */
+    public  static final int ERROR              = -1;
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Operation failed due to bad parameter value.
+     */
+    public  static final int ERROR_BAD_VALUE    = -2;
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * @param timeMs
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int seekTo(long timeMs) {
+        if (timeMs < 0) {
+            return ERROR_BAD_VALUE;
+        }
+        final int genId;
+        synchronized (mGenLock) {
+            genId = mClientGenerationIdCurrent;
+        }
+        mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
+        return SUCCESS;
+    }
+
+
+    /**
+     * @hide
+     * must be called on a registered RemoteController
+     * @param wantBitmap
+     * @param width
+     * @param height
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setBitmapConfiguration(boolean wantBitmap, int width, int height) {
+        synchronized (mInfoLock) {
+            if (!mIsRegistered) {
+                Log.e(TAG, "Cannot specify bitmap configuration on unregistered RemoteController");
+                return ERROR;
+            }
+        }
+        if (wantBitmap) {
+            if ((width > 0) && (height > 0)) {
+                if (width > MAX_BITMAP_DIMENSION) { width = MAX_BITMAP_DIMENSION; }
+                if (height > MAX_BITMAP_DIMENSION) { height = MAX_BITMAP_DIMENSION; }
+                mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, width, height);
+            } else {
+                Log.e(TAG, "Invalid dimensions");
+                return ERROR_BAD_VALUE;
+            }
+        } else {
+            mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, -1, -1);
+        }
+        return SUCCESS;
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * must be called on a registered RemoteController
+     * @param width
+     * @param height
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setBitmapConfiguration(int width, int height) {
+        return setBitmapConfiguration(true, width, height);
+    }
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * must be called on a registered RemoteController
+     * @return {@link #SUCCESS}, {@link #ERROR}
+     */
+    public int setBitmapConfigurationNone() {
+        return setBitmapConfiguration(false, -1, -1);
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Default playback position synchronization mode where the RemoteControlClient is not
+     * asked regularly for its playback position to see if it has drifted from the estimated
+     * position.
+     */
+    public static final int POSITION_SYNCHRONIZATION_NONE = 0;
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * The playback position synchronization mode where the RemoteControlClient instances which
+     * expose their playback position to the framework, will be regularly polled to check
+     * whether any drift has been noticed between their estimated position and the one they report.
+     * Note that this mode should only ever be used when needing to display very accurate playback
+     * position, as regularly polling a RemoteControlClient for its position may have an impact
+     * on battery life (if applicable) when this query will trigger network transactions in the
+     * case of remote playback.
+     */
+    public static final int POSITION_SYNCHRONIZATION_CHECK = 1;
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Set the playback position synchronization mode.
+     * Must be called on a registered RemoteController.
+     * @param sync {@link #POSITION_SYNCHRONIZATION_NONE} or {@link #POSITION_SYNCHRONIZATION_CHECK}
+     * @return {@link #SUCCESS}, {@link #ERROR} or {@link #ERROR_BAD_VALUE}
+     */
+    public int setSynchronizationMode(int sync) {
+        if ((sync != POSITION_SYNCHRONIZATION_NONE) || (sync != POSITION_SYNCHRONIZATION_CHECK)) {
+            Log.e(TAG, "Unknown synchronization mode");
+            return ERROR_BAD_VALUE;
+        }
+        if (!mIsRegistered) {
+            Log.e(TAG, "Cannot set synchronization mode on an unregistered RemoteController");
+            return ERROR;
+        }
+        mAudioManager.remoteControlDisplayWantsPlaybackPositionSync(mRcd,
+                POSITION_SYNCHRONIZATION_CHECK == sync);
+        return SUCCESS;
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Creates a {@link MetadataEditor} for updating metadata values of the editable keys of
+     * the current {@link RemoteControlClient}.
+     * @return a new MetadataEditor instance.
+     */
+    public MetadataEditor editMetadata() {
+        MetadataEditor editor = new MetadataEditor();
+        editor.mEditorMetadata = new Bundle();
+        editor.mEditorArtwork = null;
+        editor.mMetadataChanged = true;
+        editor.mArtworkChanged = true;
+        editor.mEditableKeys = 0;
+        return editor;
+    }
+
+
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC API
+     * Used to read the metadata published by a {@link RemoteControlClient}, or send a
+     * {@link RemoteControlClient} new values for keys that can be edited.
+     */
+    public class MetadataEditor extends MediaMetadataEditor {
+        /**
+         * @hide
+         */
+        protected MetadataEditor() { }
+
+        /**
+         * @hide
+         */
+        protected MetadataEditor(Bundle metadata, long editableKeys) {
+            mEditorMetadata = metadata;
+            mEditableKeys = editableKeys;
+            mEditorArtwork = null;
+            mMetadataChanged = true;
+            mArtworkChanged = true;
+            mApplied = false;
+        }
+
+        /**
+         * @hide
+         * CANDIDATE FOR PUBLIC API
+         */
+        public synchronized void apply() {
+            // "applying" a metadata bundle in RemoteController is only for sending edited
+            // key values back to the RemoteControlClient, so here we only care about the only
+            // editable key we support: RATING_KEY_BY_USER
+            if (!mMetadataChanged) {
+                return;
+            }
+            final int genId;
+            synchronized(mGenLock) {
+                genId = mClientGenerationIdCurrent;
+            }
+            synchronized(mInfoLock) {
+                if (mEditorMetadata.containsKey(
+                        String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+                    Rating rating = (Rating) getObject(
+                            MediaMetadataEditor.RATING_KEY_BY_USER, null);
+                    mAudioManager.updateRemoteControlClientMetadata(genId,
+                          MediaMetadataEditor.RATING_KEY_BY_USER,
+                          rating);
+                } else {
+                    Log.e(TAG, "no metadata to apply");
+                }
+                // NOT setting mApplied to true as this type of MetadataEditor will be applied
+                // multiple times, whenever the user of a RemoteController needs to change the
+                // metadata (e.g. user changes the rating of a song more than once during playback)
+                mApplied = false;
+            }
+        }
+
+    }
+
+
+    //==================================================
+    // Implementation of IRemoteControlDisplay interface
+    private class RcDisplay extends IRemoteControlDisplay.Stub {
+        /**
+         * @hide
+         */
+        public void setCurrentClientId(int genId, PendingIntent clientMediaIntent,
+                boolean clearing) {
+            boolean isNew = false;
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    mClientGenerationIdCurrent = genId;
+                    isNew = true;
+                }
+            }
+            if (clientMediaIntent != null) {
+                sendMsg(mEventHandler, MSG_NEW_PENDING_INTENT, SENDMSG_REPLACE,
+                        genId /*arg1*/, 0, clientMediaIntent /*obj*/, 0 /*delay*/);
+            }
+            if (isNew || clearing) {
+                sendMsg(mEventHandler, MSG_CLIENT_RESET, SENDMSG_REPLACE,
+                        genId /*arg1*/, clearing ? 1 : 0, null /*obj*/, 0 /*delay*/);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public void setPlaybackState(int genId, int state,
+                long stateChangeTimeMs, long currentPosMs, float speed) {
+            if (DEBUG) {
+                Log.d(TAG, "> new playback state: genId="+genId
+                        + " state="+ state
+                        + " changeTime="+ stateChangeTimeMs
+                        + " pos=" + currentPosMs
+                        + "ms speed=" + speed);
+            }
+
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            final PlaybackInfo playbackInfo =
+                    new PlaybackInfo(state, stateChangeTimeMs, currentPosMs, speed);
+            sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE,
+                    genId /*arg1*/, 0, playbackInfo /*obj*/, 0 /*delay*/);
+
+        }
+
+        /**
+         * @hide
+         */
+        public void setTransportControlInfo(int genId, int transportControlFlags,
+                int posCapabilities) {
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE,
+                    genId /*arg1*/, transportControlFlags /*arg2*/,
+                    null /*obj*/, 0 /*delay*/);
+        }
+
+        /**
+         * @hide
+         */
+        public void setMetadata(int genId, Bundle metadata) {
+            if (DEBUG) { Log.e(TAG, "setMetadata("+genId+")"); }
+            if (metadata == null) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+
+        /**
+         * @hide
+         */
+        public void setArtwork(int genId, Bitmap artwork) {
+            if (DEBUG) { Log.v(TAG, "setArtwork("+genId+")"); }
+            if (artwork == null) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            Bundle metadata = new Bundle(1);
+            metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), artwork);
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+
+        /**
+         * @hide
+         */
+        public void setAllMetadata(int genId, Bundle metadata, Bitmap artwork) {
+            if (DEBUG) { Log.e(TAG, "setAllMetadata("+genId+")"); }
+            if ((metadata == null) && (artwork == null)) {
+                return;
+            }
+            synchronized(mGenLock) {
+                if (mClientGenerationIdCurrent != genId) {
+                    return;
+                }
+            }
+            if (metadata == null) {
+                metadata = new Bundle(1);
+            }
+            if (artwork != null) {
+                metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+                        artwork);
+            }
+            sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE,
+                    genId /*arg1*/, 0 /*arg2*/,
+                    metadata /*obj*/, 0 /*delay*/);
+        }
+    }
+
+    //==================================================
+    // Event handling
+    private EventHandler mEventHandler;
+    private final static int MSG_NEW_PENDING_INTENT = 0;
+    private final static int MSG_NEW_PLAYBACK_INFO =  1;
+    private final static int MSG_NEW_TRANSPORT_INFO = 2;
+    private final static int MSG_NEW_METADATA       = 3; // msg always has non-null obj parameter
+    private final static int MSG_CLIENT_RESET       = 4;
+
+    private class EventHandler extends Handler {
+
+        public EventHandler(RemoteController rc, Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case MSG_NEW_PENDING_INTENT:
+                    onNewPendingIntent(msg.arg1, (PendingIntent) msg.obj);
+                    break;
+                case MSG_NEW_PLAYBACK_INFO:
+                    onNewPlaybackInfo(msg.arg1, (PlaybackInfo) msg.obj);
+                    break;
+                case MSG_NEW_TRANSPORT_INFO:
+                    onNewTransportInfo(msg.arg1, msg.arg2);
+                    break;
+                case MSG_NEW_METADATA:
+                    onNewMetadata(msg.arg1, (Bundle)msg.obj);
+                    break;
+                case MSG_CLIENT_RESET:
+                    onClientReset(msg.arg1, msg.arg2 == 1);
+                    break;
+                default:
+                    Log.e(TAG, "unknown event " + msg.what);
+            }
+        }
+    }
+
+    /** If the msg is already queued, replace it with this one. */
+    private static final int SENDMSG_REPLACE = 0;
+    /** If the msg is already queued, ignore this one and leave the old. */
+    private static final int SENDMSG_NOOP = 1;
+    /** If the msg is already queued, queue this one and leave the old. */
+    private static final int SENDMSG_QUEUE = 2;
+
+    private static void sendMsg(Handler handler, int msg, int existingMsgPolicy,
+            int arg1, int arg2, Object obj, int delayMs) {
+        if (handler == null) {
+            Log.e(TAG, "null event handler, will not deliver message " + msg);
+            return;
+        }
+        if (existingMsgPolicy == SENDMSG_REPLACE) {
+            handler.removeMessages(msg);
+        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
+            return;
+        }
+        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
+    }
+
+    private void onNewPendingIntent(int genId, PendingIntent pi) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        synchronized(mInfoLock) {
+            mClientPendingIntentCurrent = pi;
+        }
+    }
+
+    private void onNewPlaybackInfo(int genId, PlaybackInfo pi) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = this.mOnClientUpdateListener;
+            mLastPlaybackInfo = pi;
+        }
+        if (l != null) {
+            if (pi.mCurrentPosMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+                l.onClientPlaybackStateUpdate(pi.mState);
+            } else {
+                l.onClientPlaybackStateUpdate(pi.mState, pi.mStateChangeTimeMs, pi.mCurrentPosMs,
+                        pi.mSpeed);
+            }
+        }
+    }
+
+    private void onNewTransportInfo(int genId, int transportControlFlags) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            mLastTransportControlFlags = transportControlFlags;
+        }
+        if (l != null) {
+            l.onClientTransportControlUpdate(transportControlFlags);
+        }
+    }
+
+    /**
+     * @param genId
+     * @param metadata guaranteed to be always non-null
+     */
+    private void onNewMetadata(int genId, Bundle metadata) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        final MetadataEditor metadataEditor;
+        // prepare the received Bundle to be used inside a MetadataEditor
+        final long editableKeys = metadata.getLong(
+                String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK), 0);
+        if (editableKeys != 0) {
+            metadata.remove(String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK));
+        }
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+            if ((mMetadataEditor != null) && (mMetadataEditor.mEditorMetadata != null)) {
+                if (mMetadataEditor.mEditorMetadata != metadata) {
+                    // existing metadata, merge existing and new
+                    mMetadataEditor.mEditorMetadata.putAll(metadata);
+                }
+            } else {
+                mMetadataEditor = new MetadataEditor(metadata, editableKeys);
+            }
+            metadataEditor = mMetadataEditor;
+        }
+        if (l != null) {
+            l.onClientMetadataUpdate(metadataEditor);
+        }
+    }
+
+    private void onClientReset(int genId, boolean clearing) {
+        synchronized(mGenLock) {
+            if (mClientGenerationIdCurrent != genId) {
+                return;
+            }
+        }
+        final OnClientUpdateListener l;
+        synchronized(mInfoLock) {
+            l = mOnClientUpdateListener;
+        }
+        if (l != null) {
+            l.onClientReset(clearing);
+        }
+    }
+
+
+    //==================================================
+    private static class PlaybackInfo {
+        int mState;
+        long mStateChangeTimeMs;
+        long mCurrentPosMs;
+        float mSpeed;
+
+        PlaybackInfo(int state, long stateChangeTimeMs, long currentPosMs, float speed) {
+            mState = state;
+            mStateChangeTimeMs = stateChangeTimeMs;
+            mCurrentPosMs = currentPosMs;
+            mSpeed = speed;
+        }
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to mark this instance as registered.
+     * @param registered
+     */
+    protected void setIsRegistered(boolean registered) {
+        synchronized (mInfoLock) {
+            mIsRegistered = registered;
+        }
+    }
+
+    /**
+     * @hide
+     * Used by AudioManager to access binder to be registered/unregistered inside MediaFocusControl
+     * @return
+     */
+    protected RcDisplay getRcDisplay() {
+        return mRcd;
+    }
+}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index e83c5ba..8090561 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -38,6 +38,21 @@
     private boolean mShowing;
     private CaptioningManager mCaptioningManager;
 
+    private CaptioningManager.CaptioningChangeListener mCaptioningChangeListener =
+        new CaptioningManager.CaptioningChangeListener() {
+            /** @hide */
+            @Override
+            public void onEnabledChanged(boolean enabled) {
+                selectDefaultTrack();
+            }
+
+            /** @hide */
+            @Override
+            public void onLocaleChanged(Locale locale) {
+                selectDefaultTrack();
+            }
+        };
+
     /**
      * Creates a subtitle controller for a media playback object that implements
      * the MediaTimeProvider interface.
@@ -58,15 +73,24 @@
             (CaptioningManager)context.getSystemService(Context.CAPTIONING_SERVICE);
     }
 
+    @Override
+    protected void finalize() throws Throwable {
+        mCaptioningManager.removeCaptioningChangeListener(
+                mCaptioningChangeListener);
+        super.finalize();
+    }
+
     /**
      * @return the available subtitle tracks for this media. These include
      * the tracks found by {@link MediaPlayer} as well as any tracks added
      * manually via {@link #addTrack}.
      */
     public SubtitleTrack[] getTracks() {
-        SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
-        mTracks.toArray(tracks);
-        return tracks;
+        synchronized(mTracks) {
+            SubtitleTrack[] tracks = new SubtitleTrack[mTracks.size()];
+            mTracks.toArray(tracks);
+            return tracks;
+        }
     }
 
     /**
@@ -88,6 +112,8 @@
      * in-band data from the {@link MediaPlayer}.  However, this does
      * not change the subtitle visibility.
      *
+     * Must be called from the UI thread.
+     *
      * @param track The subtitle track to select.  This must be one of the
      *              tracks in {@link #getTracks}.
      * @return true if the track was successfully selected.
@@ -107,7 +133,9 @@
         }
 
         mSelectedTrack = track;
-        mAnchor.setSubtitleWidget(getRenderingWidget());
+        if (mAnchor != null) {
+            mAnchor.setSubtitleWidget(getRenderingWidget());
+        }
 
         if (mSelectedTrack != null) {
             mSelectedTrack.setTimeProvider(mTimeProvider);
@@ -123,56 +151,123 @@
     /**
      * @return the default subtitle track based on system preferences, or null,
      * if no such track exists in this manager.
+     *
+     * Supports HLS-flags: AUTOSELECT, FORCED & DEFAULT.
+     *
+     * 1. If captioning is disabled, only consider FORCED tracks. Otherwise,
+     * consider all tracks, but prefer non-FORCED ones.
+     * 2. If user selected "Default" caption language:
+     *   a. If there is a considered track with DEFAULT=yes, returns that track
+     *      (favor the first one in the current language if there are more than
+     *      one default tracks, or the first in general if none of them are in
+     *      the current language).
+     *   b. Otherwise, if there is a track with AUTOSELECT=yes in the current
+     *      language, return that one.
+     *   c. If there are no default tracks, and no autoselectable tracks in the
+     *      current language, return null.
+     * 3. If there is a track with the caption language, select that one.  Prefer
+     * the one with AUTOSELECT=no.
+     *
+     * The default values for these flags are DEFAULT=no, AUTOSELECT=yes
+     * and FORCED=no.
+     *
+     * Must be called from the UI thread.
      */
     public SubtitleTrack getDefaultTrack() {
-        Locale locale = mCaptioningManager.getLocale();
+        SubtitleTrack bestTrack = null;
+        int bestScore = -1;
 
-        for (SubtitleTrack track: mTracks) {
-            MediaFormat format = track.getFormat();
-            String language = format.getString(MediaFormat.KEY_LANGUAGE);
-            // TODO: select track with best renderer.  For now, we select first
-            // track with local's language or first track if locale has none
-            if (locale == null ||
-                locale.getLanguage().equals("") ||
-                locale.getISO3Language().equals(language) ||
-                locale.getLanguage().equals(language)) {
-                return track;
+        Locale selectedLocale = mCaptioningManager.getLocale();
+        Locale locale = selectedLocale;
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+        boolean selectForced = !mCaptioningManager.isEnabled();
+
+        synchronized(mTracks) {
+            for (SubtitleTrack track: mTracks) {
+                MediaFormat format = track.getFormat();
+                String language = format.getString(MediaFormat.KEY_LANGUAGE);
+                boolean forced =
+                    format.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0;
+                boolean autoselect =
+                    format.getInteger(MediaFormat.KEY_IS_AUTOSELECT, 1) != 0;
+                boolean is_default =
+                    format.getInteger(MediaFormat.KEY_IS_DEFAULT, 0) != 0;
+
+                boolean languageMatches =
+                    (locale == null ||
+                    locale.getLanguage().equals("") ||
+                    locale.getISO3Language().equals(language) ||
+                    locale.getLanguage().equals(language));
+                // is_default is meaningless unless caption language is 'default'
+                int score = (forced ? 0 : 8) +
+                    (((selectedLocale == null) && is_default) ? 4 : 0) +
+                    (autoselect ? 0 : 2) + (languageMatches ? 1 : 0);
+
+                if (selectForced && !forced) {
+                    continue;
+                }
+
+                // we treat null locale/language as matching any language
+                if ((selectedLocale == null && is_default) ||
+                    (languageMatches &&
+                     (autoselect || forced || selectedLocale != null))) {
+                    if (score > bestScore) {
+                        bestScore = score;
+                        bestTrack = track;
+                    }
+                }
             }
         }
-        return null;
+        return bestTrack;
     }
 
     private boolean mTrackIsExplicit = false;
     private boolean mVisibilityIsExplicit = false;
 
-    /** @hide */
+    /** @hide - called from UI thread */
     public void selectDefaultTrack() {
         if (mTrackIsExplicit) {
-            return;
-        }
-
-        SubtitleTrack track = getDefaultTrack();
-        if (track != null) {
-            selectTrack(track);
-            mTrackIsExplicit = false;
+            // If track selection is explicit, but visibility
+            // is not, it falls back to the captioning setting
             if (!mVisibilityIsExplicit) {
-                if (mCaptioningManager.isEnabled()) {
+                if (mCaptioningManager.isEnabled() ||
+                    (mSelectedTrack != null &&
+                     mSelectedTrack.getFormat().getInteger(
+                            MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
                     show();
                 } else {
                     hide();
                 }
                 mVisibilityIsExplicit = false;
             }
+            return;
+        }
+
+        // We can have a default (forced) track even if captioning
+        // is not enabled.  This is handled by getDefaultTrack().
+        // Show this track unless subtitles were explicitly hidden.
+        SubtitleTrack track = getDefaultTrack();
+        if (track != null) {
+            selectTrack(track);
+            mTrackIsExplicit = false;
+            if (!mVisibilityIsExplicit) {
+                show();
+                mVisibilityIsExplicit = false;
+            }
         }
     }
 
-    /** @hide */
+    /** @hide - called from UI thread */
     public void reset() {
         hide();
         selectTrack(null);
         mTracks.clear();
         mTrackIsExplicit = false;
         mVisibilityIsExplicit = false;
+        mCaptioningManager.removeCaptioningChangeListener(
+                mCaptioningChangeListener);
     }
 
     /**
@@ -183,12 +278,20 @@
      * @return the created {@link SubtitleTrack} object
      */
     public SubtitleTrack addTrack(MediaFormat format) {
-        for (Renderer renderer: mRenderers) {
-            if (renderer.supports(format)) {
-                SubtitleTrack track = renderer.createTrack(format);
-                if (track != null) {
-                    mTracks.add(track);
-                    return track;
+        synchronized(mRenderers) {
+            for (Renderer renderer: mRenderers) {
+                if (renderer.supports(format)) {
+                    SubtitleTrack track = renderer.createTrack(format);
+                    if (track != null) {
+                        synchronized(mTracks) {
+                            if (mTracks.size() == 0) {
+                                mCaptioningManager.addCaptioningChangeListener(
+                                        mCaptioningChangeListener);
+                            }
+                            mTracks.add(track);
+                        }
+                        return track;
+                    }
                 }
             }
         }
@@ -197,6 +300,8 @@
 
     /**
      * Show the selected (or default) subtitle track.
+     *
+     * Must be called from the UI thread.
      */
     public void show() {
         mShowing = true;
@@ -208,6 +313,8 @@
 
     /**
      * Hide the selected (or default) subtitle track.
+     *
+     * Must be called from the UI thread.
      */
     public void hide() {
         mVisibilityIsExplicit = true;
@@ -257,10 +364,12 @@
      *                 support for a subtitle format.
      */
     public void registerRenderer(Renderer renderer) {
-        // TODO how to get available renderers in the system
-        if (!mRenderers.contains(renderer)) {
-            // TODO should added renderers override existing ones (to allow replacing?)
-            mRenderers.add(renderer);
+        synchronized(mRenderers) {
+            // TODO how to get available renderers in the system
+            if (!mRenderers.contains(renderer)) {
+                // TODO should added renderers override existing ones (to allow replacing?)
+                mRenderers.add(renderer);
+            }
         }
     }
 
@@ -279,7 +388,7 @@
 
     private Anchor mAnchor;
 
-    /** @hide */
+    /** @hide - called from UI thread */
     public void setAnchor(Anchor anchor) {
         if (mAnchor == anchor) {
             return;
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index cb689af..06063de 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -69,7 +69,7 @@
     }
 
     /** @hide */
-    public MediaFormat getFormat() {
+    public final MediaFormat getFormat() {
         return mFormat;
     }
 
@@ -201,7 +201,7 @@
     }
 
     /** @hide */
-    public void scheduleTimedEvents() {
+    protected void scheduleTimedEvents() {
         /* get times for the next event */
         if (mTimeProvider != null) {
             mNextScheduledTimeMs = mCues.nextTimeAfter(mLastTimeMs);
@@ -363,7 +363,7 @@
     }
 
     /** @hide */
-    public void setTimeProvider(MediaTimeProvider timeProvider) {
+    public synchronized void setTimeProvider(MediaTimeProvider timeProvider) {
         if (mTimeProvider == timeProvider) {
             return;
         }
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a03dbf3..0030dbd 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -721,13 +721,18 @@
         return ACQUIRE_NO_BUFFERS;
     }
 
+    if (buffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+        jniThrowException(env, "java/lang/UnsupportedOperationException",
+                "NV21 format is not supported by ImageReader");
+        return -1;
+    }
+
     // Check if the left-top corner of the crop rect is origin, we currently assume this point is
     // zero, will revist this once this assumption turns out problematic.
     Point lt = buffer->crop.leftTop();
     if (lt.x != 0 || lt.y != 0) {
-        ALOGE("crop left: %d, top = %d", lt.x, lt.y);
-        jniThrowException(env, "java/lang/UnsupportedOperationException",
-                          "crop left top corner need to at origin");
+        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+                "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
         return -1;
     }
 
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 7d77c48..c05d527 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -37,6 +37,7 @@
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
     <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
 
     <application android:label="@string/app_name"
         android:process="com.android.systemui"
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 6badaaf..8cdcb7a 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -102,6 +102,8 @@
                 == TelephonyManager.CALL_STATE_OFFHOOK) {
             mLockPatternUtils.resumeCall();
         } else {
+            final boolean bypassHandler = true;
+            KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
             Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
index 3e499b2..c2cd32f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardFaceUnlockView.java
@@ -295,6 +295,13 @@
                 }
             }
         }
+
+        @Override
+        public void onEmergencyCallAction() {
+            if (mBiometricUnlock != null) {
+                mBiometricUnlock.stop();
+            }
+        }
     };
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index dcec654..f4bbf9a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -91,6 +91,7 @@
     private static final int MSG_SET_CURRENT_CLIENT_ID = 315;
     protected static final int MSG_SET_PLAYBACK_STATE = 316;
     protected static final int MSG_USER_INFO_CHANGED = 317;
+    protected static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
 
 
     private static KeyguardUpdateMonitor sInstance;
@@ -181,6 +182,9 @@
                 case MSG_USER_INFO_CHANGED:
                     handleUserInfoChanged(msg.arg1);
                     break;
+                case MSG_REPORT_EMERGENCY_CALL_ACTION:
+                    handleReportEmergencyCallAction();
+                    break;
             }
         }
     };
@@ -758,6 +762,18 @@
         }
     }
 
+    /**
+     * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION}
+     */
+    private void handleReportEmergencyCallAction() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onEmergencyCallAction();
+            }
+        }
+    }
+
     public boolean isKeyguardVisible() {
         return mKeyguardIsVisible;
     }
@@ -902,6 +918,22 @@
         handleSimStateChange(new SimArgs(IccCardConstants.State.READY));
     }
 
+    /**
+     * Report that the emergency call button has been pressed and the emergency dialer is
+     * about to be displayed.
+     *
+     * @param bypassHandler runs immediately.
+     *
+     * NOTE: Must be called from UI thread if bypassHandler == true.
+     */
+    public void reportEmergencyCallAction(boolean bypassHandler) {
+        if (!bypassHandler) {
+            mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
+        } else {
+            handleReportEmergencyCallAction();
+        }
+    }
+
     public CharSequence getTelephonyPlmn() {
         return mTelephonyPlmn;
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 30b43f5..b0511e5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -131,4 +131,8 @@
      */
     public void onMusicPlaybackStateChanged(int playbackState, long eventTime) { }
 
+    /**
+     * Called when the emergency call button is pressed.
+     */
+    void onEmergencyCallAction() { }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 4333aea..8ab4645 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -414,12 +414,25 @@
             // write anything and wait for the user to fix the range which will
             // trigger an update.
             mRequestedPages = mEditor.getRequestedPages();
-            if (mRequestedPages == null) {
+            if (mRequestedPages == null || mRequestedPages.length == 0) {
                 mEditor.updateUi();
                 if (mEditor.isDone()) {
                     PrintJobConfigActivity.this.finish();
                 }
                 return;
+            } else {
+                // If print is not confirmed we just ask for the first of the
+                // selected pages to emulate a behavior that shows preview
+                // increasing the chances that apps will implement the APIs
+                // correctly.
+                if (!mEditor.isPrintConfirmed()) {
+                    if (ALL_PAGES_ARRAY.equals(mRequestedPages)) {
+                        mRequestedPages = new PageRange[] {new PageRange(0, 0)};
+                    } else {
+                        final int firstPage = mRequestedPages[0].getStart();
+                        mRequestedPages = new PageRange[] {new PageRange(firstPage, firstPage)};
+                    }
+                }
             }
 
             // If the info and the layout did not change and we already have
@@ -1461,8 +1474,12 @@
 
                     if (dashIndex > 0) {
                         fromIndex = Integer.parseInt(range.substring(0, dashIndex)) - 1;
-                        toIndex = Integer.parseInt(range.substring(
-                                dashIndex + 1, range.length())) - 1;
+                        // It is possible that the dash is at the end since the input
+                        // verification can has to allow the user to keep entering if
+                        // this would lead to a valid input. So we handle this.
+                        toIndex = (dashIndex < range.length() - 1)
+                                ? Integer.parseInt(range.substring(dashIndex + 1,
+                                        range.length())) - 1 : fromIndex;
                     } else {
                         fromIndex = toIndex = Integer.parseInt(range) - 1;
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2257617..2be8ee5 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -292,11 +292,7 @@
         c.drawRect(mFrame, mBatteryPaint);
         c.restore();
 
-        if (level <= EMPTY) {
-            final float x = mWidth * 0.5f;
-            final float y = (mHeight + mWarningTextHeight) * 0.48f;
-            c.drawText(mWarningString, x, y, mWarningTextPaint);
-        } else if (tracker.plugged) {
+        if (tracker.plugged) {
             // draw the bolt
             final int bl = (int)(mFrame.left + width / 4f);
             final int bt = (int)(mFrame.top + height / 6f);
@@ -319,6 +315,10 @@
                         mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
             }
             c.drawPath(mBoltPath, mBoltPaint);
+        } else if (level <= EMPTY) {
+            final float x = mWidth * 0.5f;
+            final float y = (mHeight + mWarningTextHeight) * 0.48f;
+            c.drawText(mWarningString, x, y, mWarningTextPaint);
         } else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
             mTextPaint.setTextSize(height *
                     (SINGLE_DIGIT_PERCENT ? 0.75f
diff --git a/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
new file mode 100644
index 0000000..b4d3edd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/ColorDrawableWithDimensions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recent;
+
+import android.graphics.drawable.ColorDrawable;
+
+public class ColorDrawableWithDimensions extends ColorDrawable {
+    private int mWidth;
+    private int mHeight;
+
+    public ColorDrawableWithDimensions(int color, int width, int height) {
+        super(color);
+        mWidth = width;
+        mHeight = height;
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mHeight;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
rename to packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
index f17766b..1cfc892 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/FadedEdgeDrawHelper.java
@@ -30,7 +30,7 @@
 
 import com.android.systemui.R;
 
-public class RecentsScrollViewPerformanceHelper {
+public class FadedEdgeDrawHelper {
     public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
     public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
     private View mScrollView;
@@ -43,18 +43,18 @@
     private Matrix mFadeMatrix;
     private LinearGradient mFade;
 
-    public static RecentsScrollViewPerformanceHelper create(Context context,
+    public static FadedEdgeDrawHelper create(Context context,
             AttributeSet attrs, View scrollView, boolean isVertical) {
         boolean isTablet = context.getResources().
                 getBoolean(R.bool.config_recents_interface_for_tablets);
         if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
-            return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
+            return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
         } else {
             return null;
         }
     }
 
-    public RecentsScrollViewPerformanceHelper(Context context,
+    public FadedEdgeDrawHelper(Context context,
             AttributeSet attrs, View scrollView, boolean isVertical) {
         mScrollView = scrollView;
         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
@@ -64,7 +64,7 @@
     }
 
     public void onAttachedToWindowCallback(
-            RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
+            LinearLayout layout, boolean hardwareAccelerated) {
         mSoftwareRendered = !hardwareAccelerated;
         if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
                 || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
@@ -178,11 +178,11 @@
         }
     }
 
-    public int getVerticalFadingEdgeLengthCallback() {
+    public int getVerticalFadingEdgeLength() {
         return mFadingEdgeLength;
     }
 
-    public int getHorizontalFadingEdgeLengthCallback() {
+    public int getHorizontalFadingEdgeLength() {
         return mFadingEdgeLength;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 8b2cd3f..c714d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -25,7 +25,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -62,8 +62,8 @@
     private Handler mHandler;
 
     private int mIconDpi;
-    private Bitmap mDefaultThumbnailBackground;
-    private Bitmap mDefaultIconBackground;
+    private ColorDrawableWithDimensions mDefaultThumbnailBackground;
+    private ColorDrawableWithDimensions mDefaultIconBackground;
     private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
 
     private boolean mFirstScreenful;
@@ -100,7 +100,7 @@
         // Render default icon (just a blank image)
         int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
         int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
-        mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+        mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
 
         // Render the default thumbnail background
         int thumbnailWidth =
@@ -110,9 +110,7 @@
         int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
 
         mDefaultThumbnailBackground =
-                Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
-        Canvas c = new Canvas(mDefaultThumbnailBackground);
-        c.drawColor(color);
+                new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
     }
 
     public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
@@ -125,11 +123,11 @@
         }
     }
 
-    public Bitmap getDefaultThumbnail() {
+    public Drawable getDefaultThumbnail() {
         return mDefaultThumbnailBackground;
     }
 
-    public Bitmap getDefaultIcon() {
+    public Drawable getDefaultIcon() {
         return mDefaultIconBackground;
     }
 
@@ -199,7 +197,7 @@
                 + td + ": " + thumbnail);
         synchronized (td) {
             if (thumbnail != null) {
-                td.setThumbnail(thumbnail);
+                td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
             } else {
                 td.setThumbnail(mDefaultThumbnailBackground);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index f51e34b..f5670e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -22,7 +22,10 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -68,7 +71,14 @@
                 }
 
             } else {
-                Bitmap first = firstTask.getThumbnail();
+                Bitmap first = null;
+                if (firstTask.getThumbnail() instanceof BitmapDrawable) {
+                    first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
+                } else {
+                    first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+                    Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
+                    d.draw(new Canvas(first));
+                }
                 final Resources res = mContext.getResources();
 
                 float thumbWidth = res
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 217b7fd..be42bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -49,16 +49,17 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
-    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
     private HashSet<View> mRecycledViews;
     private int mNumItemsInOneScreenful;
+    private Runnable mOnScrollListener;
 
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
-        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
         mRecycledViews = new HashSet<View>();
     }
 
@@ -108,8 +109,8 @@
 
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
-            if (mPerformanceHelper != null) {
-                mPerformanceHelper.addViewCallback(view);
+            if (mFadedEdgeDrawHelper != null) {
+                mFadedEdgeDrawHelper.addViewCallback(view);
             }
 
             OnTouchListener noOpListener = new OnTouchListener() {
@@ -234,26 +235,10 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
+    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+        if (mFadedEdgeDrawHelper != null) {
 
-        if (mPerformanceHelper != null) {
-            int paddingLeft = mPaddingLeft;
-            final boolean offsetRequired = isPaddingOffsetRequired();
-            if (offsetRequired) {
-                paddingLeft += getLeftPaddingOffset();
-            }
-
-            int left = mScrollX + paddingLeft;
-            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-            int top = mScrollY + getFadeTop(offsetRequired);
-            int bottom = top + getFadeHeight(offsetRequired);
-
-            if (offsetRequired) {
-                right += getRightPaddingOffset();
-                bottom += getBottomPaddingOffset();
-            }
-            mPerformanceHelper.drawCallback(canvas,
+            mFadedEdgeDrawHelper.drawCallback(canvas,
                     left, right, top, bottom, mScrollX, mScrollY,
                     0, 0,
                     getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
@@ -261,9 +246,21 @@
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+       super.onScrollChanged(l, t, oldl, oldt);
+       if (mOnScrollListener != null) {
+           mOnScrollListener.run();
+       }
+    }
+
+    public void setOnScrollListener(Runnable listener) {
+        mOnScrollListener = listener;
+    }
+
+    @Override
     public int getVerticalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
         } else {
             return super.getVerticalFadingEdgeLength();
         }
@@ -271,8 +268,8 @@
 
     @Override
     public int getHorizontalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
         } else {
             return super.getHorizontalFadingEdgeLength();
         }
@@ -290,9 +287,8 @@
 
     @Override
     public void onAttachedToWindow() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onAttachedToWindowCallback(
-                    mCallback, mLinearLayout, isHardwareAccelerated());
+        if (mFadedEdgeDrawHelper != null) {
+            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 5ebd11e0..788e843 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Shader.TileMode;
 import android.graphics.drawable.BitmapDrawable;
@@ -74,7 +75,7 @@
     private PopupMenu mPopup;
     private View mRecentsScrim;
     private View mRecentsNoApps;
-    private ViewGroup mRecentsContainer;
+    private RecentsScrollView mRecentsContainer;
 
     private boolean mShowing;
     private boolean mWaitingToShow;
@@ -98,6 +99,8 @@
         public void setCallback(RecentsCallback callback);
         public void setMinSwipeAlpha(float minAlpha);
         public View findViewForTask(int persistentTaskId);
+        public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
+        public void setOnScrollListener(Runnable listener);
     }
 
     private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -113,7 +116,7 @@
     /* package */ final static class ViewHolder {
         View thumbnailView;
         ImageView thumbnailViewImage;
-        Bitmap thumbnailViewImageBitmap;
+        Drawable thumbnailViewDrawable;
         ImageView iconView;
         TextView labelView;
         TextView descriptionView;
@@ -151,7 +154,7 @@
             // the thumbnail later (if they both have the same dimensions)
             updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
             holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
-            holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+            holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
             holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
             holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
             holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -227,7 +230,7 @@
         public void recycleView(View v) {
             ViewHolder holder = (ViewHolder) v.getTag();
             updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-            holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+            holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
             holder.iconView.setVisibility(INVISIBLE);
             holder.iconView.animate().cancel();
             holder.labelView.setText(null);
@@ -270,13 +273,7 @@
     }
 
     public int numItemsInOneScreenful() {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                    = (RecentsScrollView) mRecentsContainer;
-            return scrollView.numItemsInOneScreenful();
-        }  else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
+        return mRecentsContainer.numItemsInOneScreenful();
     }
 
     private boolean pointInside(int x, int y, View v) {
@@ -288,7 +285,7 @@
     }
 
     public boolean isInContentArea(int x, int y) {
-        return pointInside(x, y, mRecentsContainer);
+        return pointInside(x, y, (View) mRecentsContainer);
     }
 
     public void show(boolean show) {
@@ -436,16 +433,16 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
+        mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
+        mRecentsContainer.setOnScrollListener(new Runnable() {
+            public void run() {
+                // need to redraw the faded edges
+                invalidate();
+            }
+        });
         mListAdapter = new TaskDescriptionAdapter(mContext);
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                    = (RecentsScrollView) mRecentsContainer;
-            scrollView.setAdapter(mListAdapter);
-            scrollView.setCallback(this);
-        } else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
+        mRecentsContainer.setAdapter(mListAdapter);
+        mRecentsContainer.setCallback(this);
 
         mRecentsScrim = findViewById(R.id.recents_bg_protect);
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
@@ -462,11 +459,7 @@
     }
 
     public void setMinSwipeAlpha(float minAlpha) {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                = (RecentsScrollView) mRecentsContainer;
-            scrollView.setMinSwipeAlpha(minAlpha);
-        }
+        mRecentsContainer.setMinSwipeAlpha(minAlpha);
     }
 
     private void createCustomAnimations(LayoutTransition transitioner) {
@@ -488,23 +481,23 @@
         }
     }
 
-    private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
+    private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
         if (thumbnail != null) {
             // Should remove the default image in the frame
             // that this now covers, to improve scrolling speed.
             // That can't be done until the anim is complete though.
-            h.thumbnailViewImage.setImageBitmap(thumbnail);
+            h.thumbnailViewImage.setImageDrawable(thumbnail);
 
             // scale the image to fill the full width of the ImageView. do this only if
             // we haven't set a bitmap before, or if the bitmap size has changed
-            if (h.thumbnailViewImageBitmap == null ||
-                h.thumbnailViewImageBitmap.getWidth() != thumbnail.getWidth() ||
-                h.thumbnailViewImageBitmap.getHeight() != thumbnail.getHeight()) {
+            if (h.thumbnailViewDrawable == null ||
+                h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
+                h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
                 if (mFitThumbnailToXY) {
                     h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
                 } else {
                     Matrix scaleMatrix = new Matrix();
-                    float scale = mThumbnailWidth / (float) thumbnail.getWidth();
+                    float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
                     scaleMatrix.setScale(scale, scale);
                     h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
                     h.thumbnailViewImage.setImageMatrix(scaleMatrix);
@@ -517,14 +510,14 @@
                 }
                 h.thumbnailView.setVisibility(View.VISIBLE);
             }
-            h.thumbnailViewImageBitmap = thumbnail;
+            h.thumbnailViewDrawable = thumbnail;
         }
     }
 
     void onTaskThumbnailLoaded(TaskDescription td) {
         synchronized (td) {
             if (mRecentsContainer != null) {
-                ViewGroup container = mRecentsContainer;
+                ViewGroup container = (ViewGroup) mRecentsContainer;
                 if (container instanceof RecentsScrollView) {
                     container = (ViewGroup) container.findViewById(
                             R.id.recents_linear_layout);
@@ -633,7 +626,7 @@
         final int items = mRecentTaskDescriptions != null
                 ? mRecentTaskDescriptions.size() : 0;
 
-        mRecentsContainer.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
+        ((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
 
         // Set description for accessibility
         int numRecentApps = mRecentTaskDescriptions != null
@@ -650,33 +643,33 @@
     }
 
     public boolean simulateClick(int persistentTaskId) {
-        if (mRecentsContainer instanceof RecentsScrollView){
-            RecentsScrollView scrollView
-                = (RecentsScrollView) mRecentsContainer;
-            View v = scrollView.findViewForTask(persistentTaskId);
-            if (v != null) {
-                handleOnClick(v);
-                return true;
-            }
+        View v = mRecentsContainer.findViewForTask(persistentTaskId);
+        if (v != null) {
+            handleOnClick(v);
+            return true;
         }
         return false;
     }
 
     public void handleOnClick(View view) {
-        ViewHolder holder = (ViewHolder)view.getTag();
+        ViewHolder holder = (ViewHolder) view.getTag();
         TaskDescription ad = holder.taskDescription;
         final Context context = view.getContext();
         final ActivityManager am = (ActivityManager)
                 context.getSystemService(Context.ACTIVITY_SERVICE);
-        Bitmap bm = holder.thumbnailViewImageBitmap;
-        boolean usingDrawingCache;
-        if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
-                bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
-            usingDrawingCache = false;
-        } else {
+
+        Bitmap bm = null;
+        boolean usingDrawingCache = true;
+        if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
+            bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
+            if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
+                    bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
+                usingDrawingCache = false;
+            }
+        }
+        if (usingDrawingCache) {
             holder.thumbnailViewImage.setDrawingCacheEnabled(true);
             bm = holder.thumbnailViewImage.getDrawingCache();
-            usingDrawingCache = true;
         }
         Bundle opts = (bm == null) ?
                 null :
@@ -771,7 +764,7 @@
         popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
             public boolean onMenuItemClick(MenuItem item) {
                 if (item.getItemId() == R.id.recent_remove_item) {
-                    mRecentsContainer.removeViewInLayout(selectedView);
+                    ((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
                 } else if (item.getItemId() == R.id.recent_inspect_item) {
                     ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
                     if (viewHolder != null) {
@@ -795,4 +788,26 @@
         });
         popup.show();
     }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        int paddingLeft = mPaddingLeft;
+        final boolean offsetRequired = isPaddingOffsetRequired();
+        if (offsetRequired) {
+            paddingLeft += getLeftPaddingOffset();
+        }
+
+        int left = mScrollX + paddingLeft;
+        int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
+        int top = mScrollY + getFadeTop(offsetRequired);
+        int bottom = top + getFadeHeight(offsetRequired);
+
+        if (offsetRequired) {
+            right += getRightPaddingOffset();
+            bottom += getBottomPaddingOffset();
+        }
+        mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index ee076d9..6dddc39 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -49,9 +49,10 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
-    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
     private HashSet<View> mRecycledViews;
     private int mNumItemsInOneScreenful;
+    private Runnable mOnScrollListener;
 
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
@@ -59,7 +60,7 @@
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
 
-        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+        mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
         mRecycledViews = new HashSet<View>();
     }
 
@@ -112,8 +113,8 @@
             }
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
-            if (mPerformanceHelper != null) {
-                mPerformanceHelper.addViewCallback(view);
+            if (mFadedEdgeDrawHelper != null) {
+                mFadedEdgeDrawHelper.addViewCallback(view);
             }
 
             OnTouchListener noOpListener = new OnTouchListener() {
@@ -243,36 +244,32 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        if (mPerformanceHelper != null) {
-            int paddingLeft = mPaddingLeft;
+    public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
+        if (mFadedEdgeDrawHelper != null) {
             final boolean offsetRequired = isPaddingOffsetRequired();
-            if (offsetRequired) {
-                paddingLeft += getLeftPaddingOffset();
-            }
-
-            int left = mScrollX + paddingLeft;
-            int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
-            int top = mScrollY + getFadeTop(offsetRequired);
-            int bottom = top + getFadeHeight(offsetRequired);
-
-            if (offsetRequired) {
-                right += getRightPaddingOffset();
-                bottom += getBottomPaddingOffset();
-            }
-            mPerformanceHelper.drawCallback(canvas,
-                    left, right, top, bottom, mScrollX, mScrollY,
+            mFadedEdgeDrawHelper.drawCallback(canvas,
+                    left, right, top + getFadeTop(offsetRequired), bottom, mScrollX, mScrollY,
                     getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
                     0, 0, mPaddingTop);
         }
     }
 
     @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+       super.onScrollChanged(l, t, oldl, oldt);
+       if (mOnScrollListener != null) {
+           mOnScrollListener.run();
+       }
+    }
+
+    public void setOnScrollListener(Runnable listener) {
+        mOnScrollListener = listener;
+    }
+
+    @Override
     public int getVerticalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
         } else {
             return super.getVerticalFadingEdgeLength();
         }
@@ -280,8 +277,8 @@
 
     @Override
     public int getHorizontalFadingEdgeLength() {
-        if (mPerformanceHelper != null) {
-            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        if (mFadedEdgeDrawHelper != null) {
+            return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
         } else {
             return super.getHorizontalFadingEdgeLength();
         }
@@ -299,9 +296,8 @@
 
     @Override
     public void onAttachedToWindow() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onAttachedToWindowCallback(
-                    mCallback, mLinearLayout, isHardwareAccelerated());
+        if (mFadedEdgeDrawHelper != null) {
+            mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index 7e979b7..2bc2821 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -29,7 +29,7 @@
     final String packageName; // used to override animations (see onClick())
     final CharSequence description;
 
-    private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
+    private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
     private Drawable mIcon; // application package icon
     private CharSequence mLabel; // application package label
     private boolean mLoaded;
@@ -85,11 +85,11 @@
         mIcon = icon;
     }
 
-    public void setThumbnail(Bitmap thumbnail) {
+    public void setThumbnail(Drawable thumbnail) {
         mThumbnail = thumbnail;
     }
 
-    public Bitmap getThumbnail() {
+    public Drawable getThumbnail() {
         return mThumbnail;
     }
 }
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 4bf1db8..596435a 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.net.ProxySelector;
@@ -198,9 +199,15 @@
 
                 while (mIsRunning) {
                     try {
-                        ProxyConnection parser = new ProxyConnection(serverSocket.accept());
+                        Socket socket = serverSocket.accept();
+                        // Only receive local connections.
+                        if (socket.getInetAddress().isLoopbackAddress()) {
+                            ProxyConnection parser = new ProxyConnection(socket);
 
-                        threadExecutor.execute(parser);
+                            threadExecutor.execute(parser);
+                        } else {
+                            socket.close();
+                        }
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index c6c4a94..67b2307 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -113,7 +113,7 @@
             uid = _uid;
             packageName = _packageName;
             op = _op;
-            mode = AppOpsManager.MODE_ALLOWED;
+            mode = AppOpsManager.opToDefaultMode(op);
         }
     }
 
@@ -191,7 +191,7 @@
         mHandler = new Handler();
         readState();
     }
-    
+
     public void publish(Context context) {
         mContext = context;
         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
@@ -379,7 +379,7 @@
                         }
                         repCbs.addAll(cbs);
                     }
-                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
                         // If going into the default mode, prune this op
                         // if there is nothing else interesting in it.
                         pruneOp(op, uid, packageName);
@@ -435,8 +435,8 @@
                     Ops pkgOps = ent.getValue();
                     for (int j=pkgOps.size()-1; j>=0; j--) {
                         Op curOp = pkgOps.valueAt(j);
-                        if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
-                            curOp.mode = AppOpsManager.MODE_ALLOWED;
+                        if (curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+                            curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
                             changed = true;
                             callbacks = addCallbacks(callbacks, packageName, curOp.op,
                                     mOpModeWatchers.get(curOp.op));
@@ -545,7 +545,7 @@
         synchronized (this) {
             Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
             if (op == null) {
-                return AppOpsManager.MODE_ALLOWED;
+                return AppOpsManager.opToDefaultMode(code);
             }
             return op.mode;
         }
@@ -947,7 +947,7 @@
                             AppOpsManager.OpEntry op = ops.get(j);
                             out.startTag(null, "op");
                             out.attribute(null, "n", Integer.toString(op.getOp()));
-                            if (op.getMode() != AppOpsManager.MODE_ALLOWED) {
+                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
                                 out.attribute(null, "m", Integer.toString(op.getMode()));
                             }
                             long time = op.getTime();
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 37fbb13..fea7623 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -143,6 +143,7 @@
      * Information about services for a single user.
      */
     class ServiceMap extends Handler {
+        final int mUserId;
         final ArrayMap<ComponentName, ServiceRecord> mServicesByName
                 = new ArrayMap<ComponentName, ServiceRecord>();
         final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
@@ -165,6 +166,10 @@
 
         static final int MSG_BG_START_TIMEOUT = 1;
 
+        ServiceMap(int userId) {
+            mUserId = userId;
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -224,6 +229,9 @@
                 Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
                 sendMessageAtTime(msg, when);
             }
+            if (mStartingBackground.size() < mMaxStartingBackground) {
+                mAm.backgroundServicesFinishedLocked(mUserId);
+            }
         }
     }
 
@@ -239,10 +247,15 @@
         return getServiceMap(callingUser).mServicesByName.get(name);
     }
 
+    boolean hasBackgroundServices(int callingUser) {
+        ServiceMap smap = mServiceMap.get(callingUser);
+        return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
+    }
+
     private ServiceMap getServiceMap(int callingUser) {
         ServiceMap smap = mServiceMap.get(callingUser);
         if (smap == null) {
-            smap = new ServiceMap();
+            smap = new ServiceMap(callingUser);
             mServiceMap.put(callingUser, smap);
         }
         return smap;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2bac96e..676b330 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1903,8 +1903,8 @@
     private ActivityManagerService() {
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
 
-        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
-        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
+        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
 
@@ -4910,6 +4910,7 @@
                         final int userId = mStartedUsers.keyAt(i);
                         Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                         broadcastIntentLocked(null, null, intent, null,
                                 new IIntentReceiver.Stub() {
                                     @Override
@@ -4924,7 +4925,7 @@
                                 },
                                 0, null, null,
                                 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
-                                AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
+                                AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
                                 userId);
                     }
                 }
@@ -12578,14 +12579,13 @@
             boolean doTrim = false;
 
             synchronized(this) {
-                ReceiverList rl
-                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                 if (rl != null) {
                     if (rl.curBroadcast != null) {
                         BroadcastRecord r = rl.curBroadcast;
                         final boolean doNext = finishReceiverLocked(
                                 receiver.asBinder(), r.resultCode, r.resultData,
-                                r.resultExtras, r.resultAbort, true);
+                                r.resultExtras, r.resultAbort);
                         if (doNext) {
                             doTrim = true;
                             r.queue.processNextBroadcast(false);
@@ -13212,16 +13212,20 @@
     }
 
     private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort,
-            boolean explicit) {
+            String resultData, Bundle resultExtras, boolean resultAbort) {
         final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
         if (r == null) {
             Slog.w(TAG, "finishReceiver called but not found on queue");
             return false;
         }
 
-        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
-                explicit);
+        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false);
+    }
+
+    void backgroundServicesFinishedLocked(int userId) {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.backgroundServicesFinishedLocked(userId);
+        }
     }
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -13236,7 +13240,7 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             boolean doNext = false;
-            BroadcastRecord r = null;
+            BroadcastRecord r;
 
             synchronized(this) {
                 r = broadcastRecordForReceiverLocked(who);
@@ -14749,7 +14753,7 @@
     }
 
     private final void setProcessTrackerState(ProcessRecord proc, int memFactor, long now) {
-        if (proc.thread != null) {
+        if (proc.thread != null && proc.baseProcessTracker != null) {
             proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
         }
     }
@@ -15704,10 +15708,11 @@
                 final int userId = uss.mHandle.getIdentifier();
                 Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null,
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
-                        false, false, MY_PID, Process.SYSTEM_UID, userId);
+                        true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
             int num = mUserLru.size();
             int i = 0;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6e50808..4359895 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -143,9 +143,6 @@
     private boolean inHistory;  // are we in the history stack?
     final ActivityStackSupervisor mStackSupervisor;
 
-    /** Launch the home activity rather than the activity at the top of stack */
-    boolean mLaunchHomeTaskNext;
-
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -243,6 +240,8 @@
         pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
                 pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
                 pw.print(" forceNewConfig="); pw.println(forceNewConfig);
+        pw.print(prefix); pw.print("mActivityType=");
+                pw.println(activityTypeToString(mActivityType));
         pw.print(prefix); pw.print("thumbHolder: ");
                 pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
                 if (thumbHolder != null) {
@@ -1040,6 +1039,15 @@
         return null;
     }
 
+    private String activityTypeToString(int type) {
+        switch (type) {
+            case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
+            case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
+            case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
+            default: return Integer.toString(type);
+        }
+    }
+
     @Override
     public String toString() {
         if (stringName != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 064b3a8..c31c213 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1000,7 +1000,8 @@
         boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
                 !(forceHomeShown && isHomeStack());
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final ArrayList<ActivityRecord> activities = task.mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.finishing) {
@@ -1083,7 +1084,7 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
-                    } else if (r.mLaunchHomeTaskNext) {
+                    } else if (task.mOnTopOfHome) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         showHomeBehindStack = true;
                         behindFullscreen = true;
@@ -1224,7 +1225,7 @@
 
         final TaskRecord nextTask = next.task;
         final TaskRecord prevTask = prev != null ? prev.task : null;
-        if (prevTask != null && prev.mLaunchHomeTaskNext && prev.finishing && prev.frontOfTask) {
+        if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
                 ArrayList<ActivityRecord> activities = prevTask.mActivities;
@@ -1234,7 +1235,6 @@
                     // r is usually the same as next, but what if two activities were launched
                     // before prev finished?
                     if (!r.finishing) {
-                        r.mLaunchHomeTaskNext = true;
                         r.frontOfTask = true;
                         break;
                     }
@@ -1243,7 +1243,7 @@
                 // This task is going away but it was supposed to return to the home task.
                 // Now the task above it has to return to the home task instead.
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
-                mTaskHistory.get(taskNdx).mActivities.get(0).mLaunchHomeTaskNext = true;
+                mTaskHistory.get(taskNdx).mOnTopOfHome = true;
             } else {
                 if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
                 return mStackSupervisor.resumeHomeActivity(prev);
@@ -1843,16 +1843,17 @@
                 // bottom of the activity stack.  This also keeps it
                 // correctly ordered with any activities we previously
                 // moved.
-                TaskRecord bottomTask = mTaskHistory.get(0);
-                ActivityRecord p = bottomTask.mActivities.get(0);
-                if (target.taskAffinity != null
-                        && target.taskAffinity.equals(p.task.affinity)) {
+                final ActivityRecord bottom =
+                        !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
+                        mTaskHistory.get(0).mActivities.get(0) : null;
+                if (bottom != null && target.taskAffinity != null
+                        && target.taskAffinity.equals(bottom.task.affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
-                    target.setTask(p.task, p.thumbHolder, false);
+                    target.setTask(bottom.task, bottom.thumbHolder, false);
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
-                            + " out to bottom task " + p.task);
+                            + " out to bottom task " + bottom.task);
                 } else {
                     target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
                             null, false), null, false);
@@ -1868,7 +1869,7 @@
                 boolean noOptions = canMoveOptions;
                 final int start = replyChainEnd < 0 ? i : replyChainEnd;
                 for (int srcPos = start; srcPos >= i; --srcPos) {
-                    p = activities.get(srcPos);
+                    final ActivityRecord p = activities.get(srcPos);
                     if (p.finishing) {
                         continue;
                     }
@@ -2932,7 +2933,7 @@
             if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
                 // Caller wants the home activity moved with it.  To accomplish this,
                 // we'll just indicate that this task returns to the home task.
-                task.mActivities.get(0).mLaunchHomeTaskNext = true;
+                task.mOnTopOfHome = true;
             }
             moveTaskToFrontLocked(task, null, options);
             return true;
@@ -2993,17 +2994,17 @@
      * If a watcher is installed, the action is preflighted and the watcher has an opportunity
      * to premeptively cancel the move.
      *
-     * @param task The taskId to collect and move to the bottom.
+     * @param taskId The taskId to collect and move to the bottom.
      * @return Returns true if the move completed, false if not.
      */
-    final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
-        Slog.i(TAG, "moveTaskToBack: " + task);
+    final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
+        Slog.i(TAG, "moveTaskToBack: " + taskId);
 
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
         if (mStackSupervisor.isFrontStack(this) && mService.mController != null) {
-            ActivityRecord next = topRunningActivityLocked(null, task);
+            ActivityRecord next = topRunningActivityLocked(null, taskId);
             if (next == null) {
                 next = topRunningActivityLocked(null, 0);
             }
@@ -3023,9 +3024,9 @@
         }
 
         if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to back transition: task=" + task);
+                "Prepare to back transition: task=" + taskId);
 
-        final TaskRecord tr = taskForIdLocked(task);
+        final TaskRecord tr = taskForIdLocked(taskId);
         if (tr == null) {
             return false;
         }
@@ -3037,28 +3038,15 @@
         // We make sure here that some activity in the stack will launch home.
         ActivityRecord lastActivity = null;
         int numTasks = mTaskHistory.size();
-        int taskNdx;
-        for (taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
-            int activityNdx;
-            for (activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.mLaunchHomeTaskNext) {
-                    break;
-                }
-                if (taskNdx == 1 && activityNdx == 0) {
-                    // Final activity before tr task.
-                    lastActivity = r;
-                }
-            }
-            if (activityNdx >= 0) {
-                // Early exit, we found an activity that will launchHomeTaskNext.
+        for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.mOnTopOfHome) {
                 break;
             }
-        }
-        if (lastActivity != null) {
-            // No early exit, we did not find an activity that will launchHomeTaskNext, set one.
-            lastActivity.mLaunchHomeTaskNext = true;
+            if (taskNdx == 1) {
+                // Set the last task before tr to go to home.
+                task.mOnTopOfHome = true;
+            }
         }
 
         if (reason != null &&
@@ -3071,15 +3059,15 @@
         } else {
             mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
         }
-        mWindowManager.moveTaskToBottom(task);
+        mWindowManager.moveTaskToBottom(taskId);
 
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
 
-        if (numTasks <= 1 || (mResumedActivity != null && mResumedActivity.task == tr &&
-                mResumedActivity.mLaunchHomeTaskNext)) {
-            mResumedActivity.mLaunchHomeTaskNext = false;
+        final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+        if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
+            task.mOnTopOfHome = false;
             return mStackSupervisor.resumeHomeActivity(null);
         }
 
@@ -3426,7 +3414,7 @@
         }
         final ActivityRecord top = topRunningActivityLocked(null);
         final boolean launchHomeTaskNext =
-                top != null && top.app == app && top.mLaunchHomeTaskNext;
+                top != null && top.app == app && top.task.mOnTopOfHome;
 
         // Remove this application's activities from active lists.
         boolean hasVisibleActivities = removeHistoryRecordsForAppLocked(app);
@@ -3533,6 +3521,11 @@
     }
 
     boolean removeTask(TaskRecord task) {
+        final int taskNdx = mTaskHistory.indexOf(task);
+        final int topTaskNdx = mTaskHistory.size() - 1;
+        if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
+            mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
+        }
         mTaskHistory.remove(task);
         return mTaskHistory.isEmpty();
     }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index f5d45b3..8ad29f3 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -282,7 +282,7 @@
     boolean resumeHomeActivity(ActivityRecord prev) {
         moveHomeStack(true);
         if (prev != null) {
-            prev.mLaunchHomeTaskNext = false;
+            prev.task.mOnTopOfHome = false;
         }
         mHomeStack.moveHomeTaskToTop();
         ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
@@ -304,7 +304,7 @@
                 r = stack.topRunningActivityLocked(null);
             }
             if (r != null && !r.isHomeActivity() && r.isRootActivity()) {
-                r.mLaunchHomeTaskNext = true;
+                r.task.mOnTopOfHome = true;
             }
         }
     }
@@ -1417,8 +1417,8 @@
                     final ActivityStack lastStack = getLastStack();
                     ActivityRecord curTop = lastStack == null?
                             null : lastStack.topRunningNonDelayedActivityLocked(notTop);
-                    if (curTop != null && (curTop.task != intentActivity.task) ||
-                            curTop.task != lastStack.topTask()) {
+                    if (curTop != null && (curTop.task != intentActivity.task ||
+                            curTop.task != lastStack.topTask())) {
                         r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                         if (sourceRecord == null || (sourceStack.topActivity() != null &&
                                 sourceStack.topActivity().task == sourceRecord.task)) {
@@ -1429,7 +1429,7 @@
                                     (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                     == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                 // Caller wants to appear on home activity.
-                                r.mLaunchHomeTaskNext = true;
+                                intentActivity.task.mOnTopOfHome = true;
                             }
                             targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
                             options = null;
@@ -1543,7 +1543,7 @@
                         // sure we have correctly resumed the top activity.
                         if (doResume) {
                             // Reset flag so it gets correctly reevaluated.
-                            intentActivity.mLaunchHomeTaskNext = false;
+                            intentActivity.task.mOnTopOfHome = false;
                             setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack);
                             targetStack.resumeTopActivityLocked(null, options);
                         } else {
@@ -1640,7 +1640,7 @@
                         == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                     // Caller wants to appear on home activity, so before starting
                     // their own activity we will bring home to the front.
-                    r.mLaunchHomeTaskNext = true;
+                    r.task.mOnTopOfHome = true;
                 }
             }
         } else if (sourceRecord != null) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 254a219..b35ca79 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -54,8 +54,9 @@
     static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
     static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
 
-    static final int MAX_BROADCAST_HISTORY = 25;
-    static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
+    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 25;
+    static final int MAX_BROADCAST_SUMMARY_HISTORY
+            = ActivityManager.isLowRamDeviceStatic() ? 25 : 100;
 
     final ActivityManagerService mService;
 
@@ -70,14 +71,20 @@
     final long mTimeoutPeriod;
 
     /**
+     * If true, we can delay broadcasts while waiting services to finish in the previous
+     * receiver's process.
+     */
+    final boolean mDelayBehindServices;
+
+    /**
      * Lists of all active broadcasts that are to be executed immediately
      * (without waiting for another broadcast to finish).  Currently this only
      * contains broadcasts to registered receivers, to avoid spinning up
      * a bunch of processes to execute IntentReceiver components.  Background-
      * and foreground-priority broadcasts are queued separately.
      */
-    final ArrayList<BroadcastRecord> mParallelBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
+
     /**
      * List of all active broadcasts that are to be executed one at a time.
      * The object at the top of the list is the currently activity broadcasts;
@@ -85,20 +92,17 @@
      * broadcasts, separate background- and foreground-priority queues are
      * maintained.
      */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
 
     /**
      * Historical data of past broadcasts, for debugging.
      */
-    final BroadcastRecord[] mBroadcastHistory
-            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
 
     /**
      * Summary of historical data of past broadcasts, for debugging.
      */
-    final Intent[] mBroadcastSummaryHistory
-            = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
 
     /**
      * Set when we current have a BROADCAST_INTENT_MSG in flight.
@@ -128,10 +132,6 @@
     static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
 
     final Handler mHandler = new Handler() {
-        //public Handler() {
-        //    if (localLOGV) Slog.v(TAG, "Handler started!");
-        //}
-
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
@@ -163,10 +163,12 @@
         }
     }
 
-    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod,
+            boolean allowDelayBehindServices) {
         mService = service;
         mQueueName = name;
         mTimeoutPeriod = timeoutPeriod;
+        mDelayBehindServices = allowDelayBehindServices;
     }
 
     public boolean isPendingBroadcastProcessLocked(int pid) {
@@ -260,7 +262,7 @@
                         + br.curComponent.flattenToShortString(), e);
                 logBroadcastReceiverDiscardLocked(br);
                 finishReceiverLocked(br, br.resultCode, br.resultData,
-                        br.resultExtras, br.resultAbort, true);
+                        br.resultExtras, br.resultAbort, false);
                 scheduleBroadcastsLocked();
                 // We need to reset the state if we failed to start the receiver.
                 br.state = BroadcastRecord.IDLE;
@@ -289,7 +291,7 @@
             // let the broadcast continue.
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
+                    r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
 
@@ -299,7 +301,7 @@
                     "[" + mQueueName + "] skip & discard pending app " + r);
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
+                    r.resultExtras, r.resultAbort, false);
             reschedule = true;
         }
         if (reschedule) {
@@ -330,14 +332,11 @@
     }
 
     public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort,
-            boolean explicit) {
-        int state = r.state;
+            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
+        final int state = r.state;
         r.state = BroadcastRecord.IDLE;
         if (state == BroadcastRecord.IDLE) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
-            }
+            Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
         }
         r.receiver = null;
         r.intent.setComponent(null);
@@ -348,15 +347,35 @@
             r.curFilter.receiverList.curBroadcast = null;
         }
         r.curFilter = null;
-        r.curApp = null;
-        r.curComponent = null;
         r.curReceiver = null;
+        r.curApp = null;
         mPendingBroadcast = null;
 
         r.resultCode = resultCode;
         r.resultData = resultData;
         r.resultExtras = resultExtras;
-        r.resultAbort = resultAbort;
+        if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
+            r.resultAbort = resultAbort;
+        } else {
+            r.resultAbort = false;
+        }
+
+        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
+                && r.queue.mOrderedBroadcasts.size() > 0
+                && r.queue.mOrderedBroadcasts.get(0) == r) {
+            // In this case, we are ready to process the next receiver for the current broadcast,
+            // but are on a queue that would like to wait for services to finish before moving
+            // on.  If there are background services currently starting, then we will go into a
+            // special state where we hold off on continuing this broadcast until they are done.
+            if (mService.mServices.hasBackgroundServices(r.userId)) {
+                Slog.i(ActivityManagerService.TAG, "Delay finish: "
+                        + r.curComponent.flattenToShortString());
+                r.state = BroadcastRecord.WAITING_SERVICES;
+                return false;
+            }
+        }
+
+        r.curComponent = null;
 
         // We will process the next receiver right now if this is finishing
         // an app receiver (which is always asynchronous) or after we have
@@ -365,6 +384,18 @@
                 || state == BroadcastRecord.CALL_DONE_RECEIVE;
     }
 
+    public void backgroundServicesFinishedLocked(int userId) {
+        if (mOrderedBroadcasts.size() > 0) {
+            BroadcastRecord br = mOrderedBroadcasts.get(0);
+            if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
+                Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+                br.curComponent = null;
+                br.state = BroadcastRecord.IDLE;
+                processNextBroadcast(false);
+            }
+        }
+    }
+
     private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
             Intent intent, int resultCode, String data, Bundle extras,
             boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
@@ -821,7 +852,7 @@
                     // sent the broadcast.
                     logBroadcastReceiverDiscardLocked(r);
                     finishReceiverLocked(r, r.resultCode, r.resultData,
-                            r.resultExtras, r.resultAbort, true);
+                            r.resultExtras, r.resultAbort, false);
                     scheduleBroadcastsLocked();
                     // We need to reset the state if we failed to start the receiver.
                     r.state = BroadcastRecord.IDLE;
@@ -850,7 +881,7 @@
                         + r.intent + ": process is bad");
                 logBroadcastReceiverDiscardLocked(r);
                 finishReceiverLocked(r, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
+                        r.resultExtras, r.resultAbort, false);
                 scheduleBroadcastsLocked();
                 r.state = BroadcastRecord.IDLE;
                 return;
@@ -917,7 +948,21 @@
             }
         }
 
-        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+        BroadcastRecord br = mOrderedBroadcasts.get(0);
+        if (br.state == BroadcastRecord.WAITING_SERVICES) {
+            // In this case the broadcast had already finished, but we had decided to wait
+            // for started services to finish as well before going on.  So if we have actually
+            // waited long enough time timeout the broadcast, let's give up on the whole thing
+            // and just move on to the next.
+            Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+                    ? br.curComponent.flattenToShortString() : "(null)"));
+            br.curComponent = null;
+            br.state = BroadcastRecord.IDLE;
+            processNextBroadcast(false);
+            return;
+        }
+
+        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
                 + ", started " + (now - r.receiverTime) + "ms ago");
         r.receiverTime = now;
         r.anrCount++;
@@ -957,7 +1002,7 @@
 
         // Move on to the next receiver.
         finishReceiverLocked(r, r.resultCode, r.resultData,
-                r.resultExtras, r.resultAbort, true);
+                r.resultExtras, r.resultAbort, false);
         scheduleBroadcastsLocked();
 
         if (anrMessage != null) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index db61e88..b2cfd7a 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -70,6 +70,7 @@
     static final int APP_RECEIVE = 1;
     static final int CALL_IN_RECEIVE = 2;
     static final int CALL_DONE_RECEIVE = 3;
+    static final int WAITING_SERVICES = 4;
 
     // The following are set when we are calling a receiver (one that
     // was found in our list of registered receivers).
@@ -153,6 +154,7 @@
                 case APP_RECEIVE:       stateStr=" (APP_RECEIVE)"; break;
                 case CALL_IN_RECEIVE:   stateStr=" (CALL_IN_RECEIVE)"; break;
                 case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+                case WAITING_SERVICES:  stateStr=" (WAITING_SERVICES)"; break;
             }
             pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
         }
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 4fdacb3..7a456f7 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -407,9 +407,9 @@
     }
 
     public void makeInactive(ProcessStatsService tracker) {
-        if (thread != null) {
-            thread = null;
-            final ProcessStats.ProcessState origBase = baseProcessTracker;
+        thread = null;
+        final ProcessStats.ProcessState origBase = baseProcessTracker;
+        if (origBase != null) {
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
                         tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
@@ -567,7 +567,16 @@
      */
     public boolean addPackage(String pkg, ProcessStatsService tracker) {
         if (!pkgList.containsKey(pkg)) {
-            pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName));
+            if (baseProcessTracker != null) {
+                ProcessStats.ProcessState state = tracker.getProcessStateLocked(
+                        pkg, info.uid, processName);
+                pkgList.put(pkg, state);
+                if (state != baseProcessTracker) {
+                    state.makeActive();
+                }
+            } else {
+                pkgList.put(pkg, null);
+            }
             return true;
         }
         return false;
@@ -592,25 +601,30 @@
      *  Delete all packages from list except the package indicated in info
      */
     public void resetPackageList(ProcessStatsService tracker) {
-        long now = SystemClock.uptimeMillis();
-        baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
-                tracker.getMemFactorLocked(), now, pkgList);
         final int N = pkgList.size();
-        if (N != 1) {
-            for (int i=0; i<N; i++) {
-                ProcessStats.ProcessState ps = pkgList.valueAt(i);
-                if (ps != null && ps != baseProcessTracker) {
-                    ps.makeInactive();
-                }
+        if (baseProcessTracker != null) {
+            long now = SystemClock.uptimeMillis();
+            baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+                    tracker.getMemFactorLocked(), now, pkgList);
+            if (N != 1) {
+                for (int i=0; i<N; i++) {
+                    ProcessStats.ProcessState ps = pkgList.valueAt(i);
+                    if (ps != null && ps != baseProcessTracker) {
+                        ps.makeInactive();
+                    }
 
+                }
+                pkgList.clear();
+                ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
+                        info.packageName, info.uid, processName);
+                pkgList.put(info.packageName, ps);
+                if (ps != baseProcessTracker) {
+                    ps.makeActive();
+                }
             }
+        } else if (N != 1) {
             pkgList.clear();
-            ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
-                    info.packageName, info.uid, processName);
-            pkgList.put(info.packageName, ps);
-            if (thread != null && ps != baseProcessTracker) {
-                ps.makeActive();
-            }
+            pkgList.put(info.packageName, null);
         }
     }
     
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 582e11e..0a1685c 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -30,6 +30,7 @@
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TimeUtils;
 import com.android.internal.app.IProcessStats;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BackgroundThread;
@@ -39,6 +40,7 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -313,7 +315,8 @@
         return true;
     }
 
-    private ArrayList<String> getCommittedFiles(int minNum, boolean inclAll) {
+    private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
+            boolean inclCheckedIn) {
         File[] files = mBaseDir.listFiles();
         if (files == null || files.length <= minNum) {
             return null;
@@ -325,11 +328,11 @@
             File file = files[i];
             String fileStr = file.getPath();
             if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
-            if (!inclAll && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
+            if (!inclCheckedIn && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
                 if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
                 continue;
             }
-            if (fileStr.equals(currentFile)) {
+            if (!inclCurrent && fileStr.equals(currentFile)) {
                 if (DEBUG) Slog.d(TAG, "Skipping: current stats");
                 continue;
             }
@@ -340,7 +343,7 @@
     }
 
     public void trimHistoricStatesWriteLocked() {
-        ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, true);
+        ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
         if (filesArray == null) {
             return;
         }
@@ -409,6 +412,8 @@
     }
 
     public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
         Parcel current = Parcel.obtain();
         mWriteLock.lock();
         try {
@@ -417,7 +422,7 @@
                 mProcessStats.writeToParcel(current, 0);
             }
             if (historic != null) {
-                ArrayList<String> files = getCommittedFiles(0, true);
+                ArrayList<String> files = getCommittedFiles(0, false, true);
                 if (files != null) {
                     for (int i=files.size()-1; i>=0; i--) {
                         try {
@@ -436,6 +441,76 @@
         return current.marshall();
     }
 
+    public ParcelFileDescriptor getStatsOverTime(long minTime) {
+        mAm.mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+        mWriteLock.lock();
+        try {
+            Parcel current = Parcel.obtain();
+            long curTime;
+            synchronized (mAm) {
+                mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
+                mProcessStats.writeToParcel(current, 0);
+                curTime = mProcessStats.mTimePeriodEndRealtime
+                        - mProcessStats.mTimePeriodStartRealtime;
+            }
+            if (curTime < minTime) {
+                // Need to add in older stats to reach desired time.
+                ArrayList<String> files = getCommittedFiles(0, false, true);
+                if (files.size() > 0) {
+                    current.setDataPosition(0);
+                    ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
+                    current.recycle();
+                    int i = 0;
+                    while (i < files.size() && (stats.mTimePeriodEndRealtime
+                            - stats.mTimePeriodStartRealtime) < minTime) {
+                        AtomicFile file = new AtomicFile(new File(files.get(i)));
+                        i++;
+                        ProcessStats moreStats = new ProcessStats(false);
+                        readLocked(moreStats, file);
+                        if (moreStats.mReadError == null) {
+                            stats.add(moreStats);
+                            StringBuilder sb = new StringBuilder();
+                            sb.append("Added stats: ");
+                            sb.append(moreStats.mTimePeriodStartClockStr);
+                            sb.append(", over ");
+                            TimeUtils.formatDuration(moreStats.mTimePeriodEndRealtime
+                                    - moreStats.mTimePeriodStartRealtime, sb);
+                            Slog.i(TAG, sb.toString());
+                        } else {
+                            Slog.w(TAG, "Failure reading " + files.get(i) + "; "
+                                    + moreStats.mReadError);
+                            continue;
+                        }
+                    }
+                    current = Parcel.obtain();
+                    stats.writeToParcel(current, 0);
+                }
+            }
+            final byte[] outData = current.marshall();
+            current.recycle();
+            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
+            Thread thr = new Thread("ProcessStats pipe output") {
+                public void run() {
+                    FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
+                    try {
+                        fout.write(outData);
+                        fout.close();
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Failure writing pipe", e);
+                    }
+                }
+            };
+            thr.start();
+            return fds[0];
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed building output pipe", e);
+        } finally {
+            mWriteLock.unlock();
+        }
+        return null;
+    }
+
     public int getCurrentMemoryState() {
         synchronized (mAm) {
             return mLastMemOnlyState;
@@ -445,7 +520,8 @@
     static private void dumpHelp(PrintWriter pw) {
         pw.println("Process stats (procstats) dump options:");
         pw.println("    [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
-        pw.println("    [--details] [--current] [--commit] [--reset] [--write] [-h] [<package.name>]");
+        pw.println("    [--details] [--full-details] [--current] [--one-day]");
+        pw.println("    [--commit] [--reset] [--clear] [--write] [-h] [<package.name>]");
         pw.println("  --checkin: perform a checkin: print and delete old committed states.");
         pw.println("  --c: print only state in checkin format.");
         pw.println("  --csv: output data suitable for putting in a spreadsheet.");
@@ -454,9 +530,12 @@
         pw.println("  --csv-proc: pers, top, fore, vis, precept, backup,");
         pw.println("    service, home, prev, cached");
         pw.println("  --details: dump all execution details, not just summary.");
+        pw.println("  --full-details: dump only detail information, for all saved state.");
         pw.println("  --current: only dump current state.");
+        pw.println("  --one-day: dump stats aggregated across about one day.");
         pw.println("  --commit: commit current stats to disk and reset to start new stats.");
         pw.println("  --reset: reset current stats, without committing.");
+        pw.println("  --clear: clear all stats; does both --reset and deletes old stats.");
         pw.println("  --write: write current in-memory stats to disk.");
         pw.println("  --read: replace current stats with last-written stats.");
         pw.println("  -a: print everything.");
@@ -481,7 +560,9 @@
         boolean isCsv = false;
         boolean currentOnly = false;
         boolean dumpDetails = false;
+        boolean dumpFullDetails = false;
         boolean dumpAll = false;
+        boolean oneDay = false;
         String reqPackage = null;
         boolean csvSepScreenStats = false;
         int[] csvScreenStats = new int[] { ProcessStats.ADJ_SCREEN_OFF, ProcessStats.ADJ_SCREEN_ON};
@@ -549,6 +630,10 @@
                     csvSepProcStats = sep[0];
                 } else if ("--details".equals(arg)) {
                     dumpDetails = true;
+                } else if ("--full-details".equals(arg)) {
+                    dumpFullDetails = true;
+                } else if ("--one-day".equals(arg)) {
+                    oneDay = true;
                 } else if ("--current".equals(arg)) {
                     currentOnly = true;
                 } else if ("--commit".equals(arg)) {
@@ -564,6 +649,18 @@
                         pw.println("Process stats reset.");
                     }
                     return;
+                } else if ("--clear".equals(arg)) {
+                    synchronized (mAm) {
+                        mProcessStats.resetSafely();
+                        ArrayList<String> files = getCommittedFiles(0, true, true);
+                        if (files != null) {
+                            for (int fi=0; fi<files.size(); fi++) {
+                                (new File(files.get(fi))).delete();
+                            }
+                        }
+                        pw.println("All process stats cleared.");
+                    }
+                    return;
                 } else if ("--write".equals(arg)) {
                     synchronized (mAm) {
                         writeStateSyncLocked();
@@ -653,13 +750,36 @@
                 */
             }
             return;
+        } else if (oneDay) {
+            ParcelFileDescriptor pfd = getStatsOverTime(24*60*60*1000);
+            if (pfd == null) {
+                pw.println("Unable to build stats!");
+                return;
+            }
+            ProcessStats stats = new ProcessStats(false);
+            InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            stats.read(stream);
+            if (stats.mReadError != null) {
+                pw.print("Failure reading: "); pw.println(stats.mReadError);
+                return;
+            }
+            if (isCompact) {
+                stats.dumpCheckinLocked(pw, reqPackage);
+            } else {
+                if (dumpDetails || dumpFullDetails) {
+                    stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll);
+                } else {
+                    stats.dumpSummaryLocked(pw, reqPackage, now);
+                }
+            }
+            return;
         }
 
         boolean sepNeeded = false;
         if (!currentOnly || isCheckin) {
             mWriteLock.lock();
             try {
-                ArrayList<String> files = getCommittedFiles(0, !isCheckin);
+                ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
                 if (files != null) {
                     for (int i=0; i<files.size(); i++) {
                         if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
@@ -693,7 +813,11 @@
                                 // Don't really need to lock because we uniquely own this object.
                                 // Always dump summary here, dumping all details is just too
                                 // much crud.
-                                processStats.dumpSummaryLocked(pw, reqPackage, now);
+                                if (dumpFullDetails) {
+                                    mProcessStats.dumpLocked(pw, reqPackage, now, false, false);
+                                } else {
+                                    processStats.dumpSummaryLocked(pw, reqPackage, now);
+                                }
                             }
                             if (isCheckin) {
                                 // Rename file suffix to mark that it has checked in.
@@ -719,8 +843,8 @@
                         pw.println();
                         pw.println("CURRENT STATS:");
                     }
-                    if (dumpDetails) {
-                        mProcessStats.dumpLocked(pw, reqPackage, now, dumpAll);
+                    if (dumpDetails || dumpFullDetails) {
+                        mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll);
                         if (dumpAll) {
                             pw.print("  mFile="); pw.println(mFile.getBaseFile());
                         }
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 479665c..f0bba4f 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -60,6 +60,9 @@
     /** Takes on same set of values as ActivityRecord.mActivityType */
     private int mTaskType;
 
+    /** Launch the home activity when leaving this task. */
+    boolean mOnTopOfHome = false;
+
     TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
         taskId = _taskId;
         affinity = info.taskAffinity;
@@ -411,11 +414,12 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        if (numActivities != 0 || rootWasReset || userId != 0) {
+        if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
                     pw.print(" rootWasReset="); pw.print(rootWasReset);
                     pw.print(" userId="); pw.print(userId);
-                    pw.print(" numFullscreen="); pw.println(numFullscreen);
+                    pw.print(" numFullscreen="); pw.print(numFullscreen);
+                    pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
         }
         if (affinity != null) {
             pw.print(prefix); pw.print("affinity="); pw.println(affinity);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index dbd42af..69ff449 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -923,7 +923,8 @@
                     //that was created later or a window at the top of the list of
                     //windows associated with this token.
                     if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-                            "Adding window " + win + " at " + (newIdx + 1) + " of " + N);
+                            "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
+                            N);
                     windows.add(newIdx + 1, win);
                     if (newIdx < 0) {
                         // No window from token found on win's display.
@@ -1044,7 +1045,7 @@
             }
         }
         if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-                "Adding window " + win + " at " + i + " of " + N);
+                "Based on layer: Adding window " + win + " at " + i + " of " + N);
         windows.add(i, win);
         mWindowsChanged = true;
         return tokenWindowsPos;
@@ -1063,7 +1064,7 @@
         }
         i++;
         if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
-                "Adding window " + win + " at " + i + " of " + windows.size());
+                "Free window: Adding window " + win + " at " + i + " of " + windows.size());
         windows.add(i, win);
         mWindowsChanged = true;
     }
@@ -1130,6 +1131,8 @@
     }
 
     private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) {
+        if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win +
+                " Callers=" + Debug.getCallers(4));
         if (win.mAttachedWindow == null) {
             final WindowToken token = win.mToken;
             int tokenWindowsPos = 0;
@@ -1185,16 +1188,15 @@
         // same display. Or even when the current IME/target are not on the same screen as the next
         // IME/target. For now only look for input windows on the main screen.
         WindowList windows = getDefaultWindowListLocked();
-        final int N = windows.size();
         WindowState w = null;
-        int i = N;
-        while (i > 0) {
-            i--;
-            w = windows.get(i);
+        int i;
+        for (i = windows.size() - 1; i >= 0; --i) {
+            WindowState win = windows.get(i);
 
             if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i
-                    + " " + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags));
-            if (canBeImeTarget(w)) {
+                    + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
+            if (canBeImeTarget(win)) {
+                w = win;
                 //Slog.i(TAG, "Putting input method here!");
 
                 // Yet more tricksyness!  If this window is a "starting"
@@ -7081,19 +7083,17 @@
                         }
                     }
 
-                    if (lastFocus != newFocus) {
-                        //System.out.println("Changing focus from " + lastFocus
-                        //                   + " to " + newFocus);
-                        if (newFocus != null) {
-                            if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
-                            newFocus.reportFocusChangedSerialized(true, mInTouchMode);
-                            notifyFocusChanged();
-                        }
+                    //System.out.println("Changing focus from " + lastFocus
+                    //                   + " to " + newFocus);
+                    if (newFocus != null) {
+                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
+                        newFocus.reportFocusChangedSerialized(true, mInTouchMode);
+                        notifyFocusChanged();
+                    }
 
-                        if (lastFocus != null) {
-                            if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
-                            lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
-                        }
+                    if (lastFocus != null) {
+                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
+                        lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
                     }
                 } break;
 
@@ -10277,14 +10277,13 @@
 
     void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
             ArrayList<WindowState> windows) {
-        int j = 0;
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
             for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
                 final WindowState w = windowList.get(winNdx);
                 if (windows == null || windows.contains(w)) {
-                    pw.print("  Window #"); pw.print(j++); pw.print(' ');
+                    pw.print("  Window #"); pw.print(winNdx); pw.print(' ');
                             pw.print(w); pw.println(":");
                     w.dump(pw, "    ", dumpAll || windows != null);
                 }