Merge "Fix notification ticker info text alignment."
diff --git a/api/current.txt b/api/current.txt
index 4f50bf3..52b28f5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -709,6 +709,7 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
+    field public static final int overridesImplicitlyEnabledSubtype = 16843696; // 0x10103b0
     field public static final int packageNames = 16843649; // 0x1010381
     field public static final int padding = 16842965; // 0x10100d5
     field public static final int paddingBottom = 16842969; // 0x10100d9
@@ -10668,7 +10669,7 @@
     method public void setAuxEffectSendLevel(float);
     method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
-    method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
+    method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException;
     method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setDisplay(android.view.SurfaceHolder);
@@ -15610,7 +15611,7 @@
   public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
     field public static final java.lang.String CALENDAR_LOCATION = "calendar_location";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DEFAULT_SORT_ORDER = "displayName";
+    field public static final java.lang.String DEFAULT_SORT_ORDER = "calendar_displayName";
     field public static final java.lang.String NAME = "name";
   }
 
@@ -18463,7 +18464,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.textservice.SpellCheckerService";
   }
 
-  public abstract class SpellCheckerService.Session {
+  public static abstract class SpellCheckerService.Session {
     ctor public SpellCheckerService.Session();
     method public android.os.Bundle getBundle();
     method public java.lang.String getLocale();
@@ -20702,7 +20703,6 @@
 
   public class EasyEditSpan implements android.text.ParcelableSpan {
     ctor public EasyEditSpan();
-    ctor public EasyEditSpan(android.os.Parcel);
     method public int describeContents();
     method public int getSpanTypeId();
     method public void writeToParcel(android.os.Parcel, int);
@@ -23046,7 +23046,6 @@
     method public boolean willNotDraw();
     field public static android.util.Property ALPHA;
     field protected static int DEFAULT_TEXT_DIRECTION;
-    field protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD;
     field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
     field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
     field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -24488,7 +24487,7 @@
     method public boolean isWatchingCursor(android.view.View);
     method public void restartInput(android.view.View);
     method public void sendAppPrivateCommand(android.view.View, java.lang.String, android.os.Bundle);
-    method public boolean setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
+    method public void setAdditionalInputMethodSubtypes(java.lang.String, android.view.inputmethod.InputMethodSubtype[]);
     method public boolean setCurrentInputMethodSubtype(android.view.inputmethod.InputMethodSubtype);
     method public void setInputMethod(android.os.IBinder, java.lang.String);
     method public void setInputMethodAndSubtype(android.os.IBinder, java.lang.String, android.view.inputmethod.InputMethodSubtype);
@@ -24533,8 +24532,7 @@
   }
 
   public final class InputMethodSubtype implements android.os.Parcelable {
-    ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String);
-    ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean);
+    ctor public InputMethodSubtype(int, int, java.lang.String, java.lang.String, java.lang.String, boolean, boolean);
     method public boolean containsExtraValueKey(java.lang.String);
     method public int describeContents();
     method public java.lang.CharSequence getDisplayName(android.content.Context, java.lang.String, android.content.pm.ApplicationInfo);
@@ -24545,6 +24543,7 @@
     method public java.lang.String getMode();
     method public int getNameResId();
     method public boolean isAuxiliary();
+    method public boolean overridesImplicitlyEnabledSubtype();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
   }
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index aa3bc03..b13236a 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -357,9 +357,9 @@
     }
 
     sp<IMediaPlayer> player =
-        service->create(getpid(), client, source, 0);
+        service->create(getpid(), client, 0);
 
-    if (player != NULL) {
+    if (player != NULL && player->setDataSource(source) == NO_ERROR) {
         player->setVideoSurface(surface);
         player->start();
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 0e3eaaa..41e3fdf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4471,9 +4471,12 @@
                     ManagedCursor mc = mManagedCursors.get(i);
                     if (mc.mReleased || mc.mUpdated) {
                         if (!mc.mCursor.requery()) {
-                            throw new IllegalStateException(
-                                    "trying to requery an already closed cursor  "
-                                    + mc.mCursor);
+                            if (getApplicationInfo().targetSdkVersion
+                                    >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                                throw new IllegalStateException(
+                                        "trying to requery an already closed cursor  "
+                                        + mc.mCursor);
+                            }
                         }
                         mc.mReleased = false;
                         mc.mUpdated = false;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e3075d7..8275cbd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1291,7 +1291,8 @@
         public final boolean queueIdle() {
             ActivityClientRecord a = mNewActivities;
             boolean stopProfiling = false;
-            if (mBoundApplication.profileFd != null && mBoundApplication.autoStopProfiler) {
+            if (mBoundApplication != null && mBoundApplication.profileFd != null
+                    && mBoundApplication.autoStopProfiler) {
                 stopProfiling = true;
             }
             if (a != null) {
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 496da41..ef6e131 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -191,6 +191,12 @@
     private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds
     private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours
 
+    /**
+     * The amount of time to wait after attempting a bind before canceling a sync and disabling
+     * the sync adapter
+     */
+    public static final long BIND_TIMEOUT_MS = 30 * 1000;
+
     public void onAccountsUpdated(Account[] accounts) {
         // remember if this was the first time this was called after an update
         final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;
@@ -1068,6 +1074,9 @@
             pw.print(" - ");
             pw.print(activeSyncContext.mSyncOperation.dump(false));
             pw.println();
+            if (activeSyncContext.mSyncAdapter == null) {
+                pw.println("   **** Waiting for onServiceConnected ****");
+            }
         }
 
         synchronized (mSyncQueue) {
@@ -1424,6 +1433,7 @@
         public void handleMessage(Message msg) {
             long earliestFuturePollTime = Long.MAX_VALUE;
             long nextPendingSyncTime = Long.MAX_VALUE;
+            long nextBindTimeoutTime = Long.MAX_VALUE;
 
             // Setting the value here instead of a method because we want the dumpsys logs
             // to have the most recent value used.
@@ -1431,6 +1441,7 @@
                 waitUntilReadyToRun();
                 mDataConnectionIsConnected = readDataConnectionState();
                 mSyncManagerWakeLock.acquire();
+                nextBindTimeoutTime = auditRunningSyncsForStuckBindsLocked();
                 // Always do this first so that we be sure that any periodic syncs that
                 // are ready to run have been converted into pending syncs. This allows the
                 // logic that considers the next steps to take based on the set of pending syncs
@@ -1532,6 +1543,7 @@
                         break;
                 }
             } finally {
+                nextPendingSyncTime = Math.min(nextBindTimeoutTime, nextPendingSyncTime);
                 manageSyncNotificationLocked();
                 manageSyncAlarmLocked(earliestFuturePollTime, nextPendingSyncTime);
                 mSyncTimeTracker.update();
@@ -1540,6 +1552,36 @@
         }
 
         /**
+         * Looks to see if any of the active syncs have been waiting for a bind for too long,
+         * and if so the sync is canceled and the sync adapter is disabled for that account.
+         * @return the earliest time that an active sync can have waited too long to bind,
+         * relative to {@link android.os.SystemClock#elapsedRealtime()}.
+         */
+        private long auditRunningSyncsForStuckBindsLocked() {
+            final long now = SystemClock.elapsedRealtime();
+            long oldest = Long.MAX_VALUE;
+            for (ActiveSyncContext active : mActiveSyncContexts) {
+                if (active.mSyncAdapter == null) {
+                    final long timeoutTime = active.mStartTime + BIND_TIMEOUT_MS;
+                    if (timeoutTime < now) {
+                        Log.w(TAG, "canceling long-running bind and disabling sync for "
+                                + active.mSyncOperation.account + ", authority "
+                                + active.mSyncOperation.authority);
+                        runSyncFinishedOrCanceledLocked(null, active);
+                        ContentResolver.setIsSyncable(active.mSyncOperation.account,
+                                active.mSyncOperation.authority, 0);
+                    } else {
+                        if (oldest > timeoutTime) {
+                            oldest = timeoutTime;
+                        }
+                    }
+                }
+            }
+
+            return oldest;
+        }
+
+        /**
          * Turn any periodic sync operations that are ready to run into pending sync operations.
          * @return the desired start time of the earliest future  periodic sync operation,
          * in milliseconds since boot
@@ -1819,13 +1861,17 @@
                 synchronized (mSyncQueue){
                     mSyncQueue.remove(candidate);
                 }
-                dispatchSyncOperation(candidate);
+                ActiveSyncContext newSyncContext = dispatchSyncOperation(candidate);
+                if (newSyncContext != null) {
+                    nextReadyToRunTime = Math.min(nextReadyToRunTime,
+                            newSyncContext.mStartTime + BIND_TIMEOUT_MS);
+                }
             }
 
             return nextReadyToRunTime;
      }
 
-        private boolean dispatchSyncOperation(SyncOperation op) {
+        private ActiveSyncContext dispatchSyncOperation(SyncOperation op) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
                 Log.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
@@ -1842,7 +1888,7 @@
                 Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
                         + ", removing settings for it");
                 mSyncStorageEngine.removeAuthority(op.account, op.authority);
-                return false;
+                return null;
             }
 
             ActiveSyncContext activeSyncContext =
@@ -1855,10 +1901,10 @@
             if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) {
                 Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
                 closeActiveSyncContext(activeSyncContext);
-                return false;
+                return null;
             }
 
-            return true;
+            return activeSyncContext;
         }
 
         private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index b6487bd..5fe42db 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -36,6 +36,8 @@
     DataSetObservable mDataSetObservable = new DataSetObservable();
     ContentObservable mContentObservable = new ContentObservable();
 
+    Bundle mExtras = Bundle.EMPTY;
+
     /* -------------------------------------------------------- */
     /* These need to be implemented by subclasses */
     abstract public int getCount();
@@ -71,11 +73,11 @@
     public int getColumnCount() {
         return getColumnNames().length;
     }
-    
+
     public void deactivate() {
         deactivateInternal();
     }
-    
+
     /**
      * @hide
      */
@@ -99,7 +101,7 @@
     public boolean isClosed() {
         return mClosed;
     }
-    
+
     public void close() {
         mClosed = true;
         mContentObservable.unregisterAll();
@@ -120,7 +122,7 @@
         return true;
     }
 
-    
+
     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
         // Default implementation, uses getString
         String result = getString(columnIndex);
@@ -136,7 +138,7 @@
             buffer.sizeCopied = 0;
         }
     }
-    
+
     /* -------------------------------------------------------- */
     /* Implementation */
     public AbstractCursor() {
@@ -181,7 +183,7 @@
 
         return result;
     }
-    
+
     /**
      * Copy data from cursor to CursorWindow
      * @param position start position of data
@@ -199,7 +201,7 @@
             window.setStartPosition(position);
             int columnNum = getColumnCount();
             window.setNumColumns(columnNum);
-            while (moveToNext() && window.allocRow()) {            
+            while (moveToNext() && window.allocRow()) {
                 for (int i = 0; i < columnNum; i++) {
                     String field = getString(i);
                     if (field != null) {
@@ -215,7 +217,7 @@
                     }
                 }
             }
-            
+
             mPos = oldpos;
         } catch (IllegalStateException e){
             // simply ignore it
@@ -314,7 +316,7 @@
             mContentObservable.unregisterObserver(observer);
         }
     }
-    
+
     /**
      * This is hidden until the data set change model has been re-evaluated.
      * @hide
@@ -322,14 +324,14 @@
     protected void notifyDataSetChange() {
         mDataSetObservable.notifyChanged();
     }
-    
+
     /**
      * This is hidden until the data set change model has been re-evaluated.
      * @hide
      */
     protected DataSetObservable getDataSetObservable() {
         return mDataSetObservable;
-        
+
     }
 
     public void registerDataSetObserver(DataSetObserver observer) {
@@ -383,8 +385,19 @@
         return false;
     }
 
+    /**
+     * Sets a {@link Bundle} that will be returned by {@link #getExtras()}.  <code>null</code> will
+     * be converted into {@link Bundle#EMPTY}.
+     *
+     * @param extras {@link Bundle} to set.
+     * @hide
+     */
+    public void setExtras(Bundle extras) {
+        mExtras = (extras == null) ? Bundle.EMPTY : extras;
+    }
+
     public Bundle getExtras() {
-        return Bundle.EMPTY;
+        return mExtras;
     }
 
     public Bundle respond(Bundle extras) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index bc45945..63f2244 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1468,6 +1468,7 @@
         private static final String KEY_MAX_NUM_DETECTED_FACES_HW = "max-num-detected-faces-hw";
         private static final String KEY_MAX_NUM_DETECTED_FACES_SW = "max-num-detected-faces-sw";
         private static final String KEY_RECORDING_HINT = "recording-hint";
+        private static final String KEY_VIDEO_SNAPSHOT_SUPPORTED = "video-snapshot-supported";
 
         // Parameter key suffix for supported values.
         private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -3210,6 +3211,35 @@
             set(KEY_RECORDING_HINT, hint ? TRUE : FALSE);
         }
 
+        /**
+         * Returns true if video snapshot is supported. That is, applications
+         * can call {@link #takePicture(Camera.ShutterCallback,
+         * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}
+         * during recording. Applications do not need to call {@link
+         * #startPreview()} after taking a picture. The preview will be still
+         * active. Other than that, taking a picture during recording is
+         * identical to taking a picture normally. All settings and methods
+         * related to takePicture work identically. Ex: {@link
+         * #getPictureSize()}, {@link #getSupportedPictureSizes()}, {@link
+         * #setJpegQuality(int)}, {@link #setRotation(int)}, and etc. The
+         * picture will have an EXIF header. {@link #FLASH_MODE_AUTO} and {@link
+         * #FLASH_MODE_ON} also still work, but the video will record the flash.
+         *
+         * Applications can set shutter callback as null to avoid the shutter
+         * sound. It is also recommended to set raw picture and post view
+         * callbacks to null to avoid the interrupt of preview display.
+         *
+         * Field-of-view of the recorded video may be different from that of the
+         * captured pictures.
+         *
+         * @return true if video snapshot is supported.
+         * @hide
+         */
+        public boolean isVideoSnapshotSupported() {
+            String str = get(KEY_VIDEO_SNAPSHOT_SUPPORTED);
+            return TRUE.equals(str);
+        }
+
         // Splits a comma delimited string to an ArrayList of String.
         // Return null if the passing string is null or the size is 0.
         private ArrayList<String> split(String str) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3441217..530122c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -814,4 +814,22 @@
         } catch (RemoteException e) {
         }
     }
+
+    /**
+     * Returns true if the hardware supports the given network type
+     * else it returns false.  This doesn't indicate we have coverage
+     * or are authorized onto a network, just whether or not the
+     * hardware supports it.  For example a gsm phone without a sim
+     * should still return true for mobile data, but a wifi only tablet
+     * would return false.
+     * @param networkType The nework type we'd like to check
+     * @return true if supported, else false
+     * @hide
+     */
+    public boolean isNetworkSupported(int networkType) {
+        try {
+            return mService.isNetworkSupported(networkType);
+        } catch (RemoteException e) {}
+        return false;
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index c9553c0..eef658e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -43,6 +43,8 @@
     NetworkInfo getNetworkInfo(int networkType);
     NetworkInfo[] getAllNetworkInfo();
 
+    boolean isNetworkSupported(int networkType);
+
     LinkProperties getActiveLinkProperties();
     LinkProperties getLinkProperties(int networkType);
 
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index e5f3273..3918cfd 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -320,15 +320,36 @@
      * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
      */
     public long getTotalBytes() {
-        long totalBytes = 0;
+        final Entry entry = getTotal(null);
+        return entry.rxBytes + entry.txBytes;
+    }
+
+    /**
+     * Return total of all fields represented by this snapshot object.
+     */
+    public Entry getTotal(Entry recycle) {
+        final Entry entry = recycle != null ? recycle : new Entry();
+
+        entry.iface = IFACE_ALL;
+        entry.uid = UID_ALL;
+        entry.set = SET_ALL;
+        entry.tag = TAG_NONE;
+        entry.rxBytes = 0;
+        entry.rxPackets = 0;
+        entry.txBytes = 0;
+        entry.txPackets = 0;
+
         for (int i = 0; i < size; i++) {
             // skip specific tags, since already counted in TAG_NONE
             if (tag[i] != TAG_NONE) continue;
 
-            totalBytes += rxBytes[i];
-            totalBytes += txBytes[i];
+            entry.rxBytes += rxBytes[i];
+            entry.rxPackets += rxPackets[i];
+            entry.txBytes += txBytes[i];
+            entry.txPackets += txPackets[i];
+            entry.operations += operations[i];
         }
-        return totalBytes;
+        return entry;
     }
 
     /**
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 6fe5124..9ba1fdb 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -599,7 +599,7 @@
         /**
          * The default sort order for this table
          */
-        public static final String DEFAULT_SORT_ORDER = "displayName";
+        public static final String DEFAULT_SORT_ORDER = CALENDAR_DISPLAY_NAME;
 
         /**
          * The name of the calendar. Column name.
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 3e2e38e..b96099e 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -66,7 +66,7 @@
     /**
      * This abstract class should be overridden by a concrete implementation of a spell checker.
      */
-    public abstract class Session {
+    public static abstract class Session {
         private InternalISpellCheckerSession mInternalSession;
 
         /**
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index e914316..355d467 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -24,8 +24,8 @@
 import android.text.style.BackgroundColorSpan;
 import android.text.style.BulletSpan;
 import android.text.style.CharacterStyle;
-import android.text.style.ForegroundColorSpan;
 import android.text.style.EasyEditSpan;
+import android.text.style.ForegroundColorSpan;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.QuoteSpan;
@@ -748,11 +748,11 @@
                     break;
 
                 case SUGGESTION_RANGE_SPAN:
-                    readSpan(p, sp, new SuggestionRangeSpan());
+                    readSpan(p, sp, new SuggestionRangeSpan(p));
                     break;
                     
                 case EASY_EDIT_SPAN:
-                    readSpan(p, sp, new EasyEditSpan(p));
+                    readSpan(p, sp, new EasyEditSpan());
                     break;
 
                 default:
diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java
index e6e4d2c..2feb719 100644
--- a/core/java/android/text/style/EasyEditSpan.java
+++ b/core/java/android/text/style/EasyEditSpan.java
@@ -33,10 +33,6 @@
         // Empty
     }
 
-    public EasyEditSpan(Parcel src) {
-        this();
-    }
-
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/text/style/SuggestionRangeSpan.java b/core/java/android/text/style/SuggestionRangeSpan.java
index fc91697..a637b1c 100644
--- a/core/java/android/text/style/SuggestionRangeSpan.java
+++ b/core/java/android/text/style/SuggestionRangeSpan.java
@@ -16,7 +16,6 @@
 
 package android.text.style;
 
-import android.graphics.Color;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
@@ -29,12 +28,20 @@
  * @hide
  */
 public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan {
+    private final int mBackgroundColor;
+
     @Override
     public void updateDrawState(TextPaint tp) {
-        tp.setColor(Color.GREEN);            
+        tp.bgColor = mBackgroundColor;
     }
 
-    public SuggestionRangeSpan() { /* Nothing to do*/ }
+    public SuggestionRangeSpan(int color) {
+        mBackgroundColor = color;
+    }
+
+    public SuggestionRangeSpan(Parcel src) {
+        mBackgroundColor = src.readInt();
+    }
 
     @Override
     public int describeContents() {
@@ -42,7 +49,9 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) { /* Nothing to do*/ }
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mBackgroundColor);
+    }
 
     @Override
     public int getSpanTypeId() {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 2bf16d8..1fcde3d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -344,9 +344,9 @@
         static final int EGL_SURFACE_TYPE = 0x3033;
         static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;        
 
-        private static final int SURFACE_STATE_ERROR = 0;
-        private static final int SURFACE_STATE_SUCCESS = 1;
-        private static final int SURFACE_STATE_UPDATED = 2;
+        static final int SURFACE_STATE_ERROR = 0;
+        static final int SURFACE_STATE_SUCCESS = 1;
+        static final int SURFACE_STATE_UPDATED = 2;
         
         static EGL10 sEgl;
         static EGLDisplay sEglDisplay;
@@ -913,8 +913,7 @@
 
         @Override
         void destroyLayers(View view) {
-            if (view != null && isEnabled()) {
-                checkCurrent();
+            if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) {
                 destroyHardwareLayer(view);
                 GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
             }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 9d959fb..c735d6b 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -286,6 +286,11 @@
     }
 
     @Override
+    boolean destroyLayer() {
+        return false;
+    }
+
+    @Override
     HardwareLayer getHardwareLayer() {
         if (mLayer == null) {
             if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 14677e1..fa1d249 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2595,11 +2595,6 @@
     protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
 
     /**
-     * Default threshold for "char count" heuristic.
-     */
-    protected static float DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD = 0.6f;
-
-    /**
      * The text direction that has been defined by {@link #setTextDirection(int)}.
      *
      * {@hide}
@@ -6052,23 +6047,29 @@
      * @see #onHoverChanged
      */
     public boolean onHoverEvent(MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_HOVER_ENTER:
-                if (!hasHoveredChild() && !mSendingHoverAccessibilityEvents) {
-                    mSendingHoverAccessibilityEvents = true;
-                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
-                }
-                break;
-            case MotionEvent.ACTION_HOVER_EXIT:
-                if (mSendingHoverAccessibilityEvents) {
-                    mSendingHoverAccessibilityEvents = false;
-                    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-                }
-                break;
+        // The root view may receive hover (or touch) events that are outside the bounds of
+        // the window.  This code ensures that we only send accessibility events for
+        // hovers that are actually within the bounds of the root view.
+        final int action = event.getAction();
+        if (!mSendingHoverAccessibilityEvents) {
+            if ((action == MotionEvent.ACTION_HOVER_ENTER
+                    || action == MotionEvent.ACTION_HOVER_MOVE)
+                    && !hasHoveredChild()
+                    && pointInView(event.getX(), event.getY())) {
+                mSendingHoverAccessibilityEvents = true;
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+            }
+        } else {
+            if (action == MotionEvent.ACTION_HOVER_EXIT
+                    || (action == MotionEvent.ACTION_HOVER_MOVE
+                            && !pointInView(event.getX(), event.getY()))) {
+                mSendingHoverAccessibilityEvents = false;
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+            }
         }
 
         if (isHoverable()) {
-            switch (event.getAction()) {
+            switch (action) {
                 case MotionEvent.ACTION_HOVER_ENTER:
                     setHovered(true);
                     break;
@@ -9361,7 +9362,6 @@
 
         if (mAttachInfo != null) {
             mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this);
-            mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_RECT_MSG, this);
         }
 
         mCurrentAnimation = null;
@@ -13909,6 +13909,7 @@
                         }
 
                         public void onReleased(InvalidateInfo element) {
+                            element.target = null;
                         }
                     }, POOL_LIMIT)
             );
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5c045bb..7db1b32 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2141,6 +2141,10 @@
 
     void dispatchDetachedFromWindow() {
         if (mView != null && mView.mAttachInfo != null) {
+            if (mAttachInfo.mHardwareRenderer != null &&
+                    mAttachInfo.mHardwareRenderer.isEnabled()) {
+                mAttachInfo.mHardwareRenderer.validate();
+            }
             mView.dispatchDetachedFromWindow();
         }
 
@@ -3568,6 +3572,11 @@
         checkThread();
         if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
         synchronized (this) {
+            if (mAdded) {
+                mAdded = false;
+                dispatchDetachedFromWindow();
+            }
+
             if (mAdded && !mFirst) {
                 destroyHardwareRenderer();
 
@@ -3588,10 +3597,6 @@
 
                 mSurface.release();
             }
-            if (mAdded) {
-                mAdded = false;
-                dispatchDetachedFromWindow();
-            }
         }
     }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index a963e10..dc1bbd7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -872,6 +872,12 @@
     public void systemReady();
 
     /**
+     * Called when the system is done booting to the point where the
+     * user can start interacting with it.
+     */
+    public void systemBooted();
+
+    /**
      * Show boot time message to the user.
      */
     public void showBootMessage(final CharSequence msg, final boolean always);
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 5d4fbbe..76b47ca 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -332,7 +332,7 @@
         // we perform an orientation change under ideal conditions.  It will take
         // proportionally longer than this to effect an orientation change when
         // the proposed orientation confidence is low.
-        private static final float ORIENTATION_SETTLE_TIME_MS = 100;
+        private static final float ORIENTATION_SETTLE_TIME_MS = 250;
 
         // The confidence that we have abount effecting each orientation change.
         // When one of these values exceeds 1.0, we have determined our new orientation!
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 4ec4ff9..0119d03 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -164,7 +164,9 @@
                             a.getString(com.android.internal.R.styleable
                                     .InputMethod_Subtype_imeSubtypeExtraValue),
                             a.getBoolean(com.android.internal.R.styleable
-                                    .InputMethod_Subtype_isAuxiliary, false));
+                                    .InputMethod_Subtype_isAuxiliary, false),
+                            a.getBoolean(com.android.internal.R.styleable
+                                    .InputMethod_Subtype_overridesImplicitlyEnabledSubtype, false));
                     mSubtypes.add(subtype);
                 }
             }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 302be57..3ead9df 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1593,15 +1593,13 @@
      * to the current implementation.)
      * @param imiId Id of InputMethodInfo which additional input method subtypes will be added to.
      * @param subtypes subtypes will be added as additional subtypes of the current input method.
-     * @return true if the additional input method subtypes are successfully added.
      */
-    public boolean setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
+    public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
         synchronized (mH) {
             try {
-                return mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
+                mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
             } catch (RemoteException e) {
                 Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
             }
         }
     }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 4a98336..5670432 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -42,6 +42,7 @@
     private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
 
     private final boolean mIsAuxiliary;
+    private final boolean mOverridesImplicitlyEnabledSubtype;
     private final int mSubtypeHashCode;
     private final int mSubtypeIconResId;
     private final int mSubtypeNameResId;
@@ -57,10 +58,12 @@
      * @param locale The locale supported by the subtype
      * @param mode The mode supported by the subtype
      * @param extraValue The extra value of the subtype
+     * @param isAuxiliary true when this subtype is one shot subtype.
+     * @hide
      */
-    public InputMethodSubtype(
-            int nameId, int iconId, String locale, String mode, String extraValue) {
-        this(nameId, iconId, locale, mode, extraValue, false);
+    public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
+            boolean isAuxiliary) {
+        this(nameId, iconId, locale, mode, extraValue, false, false);
     }
 
     /**
@@ -71,17 +74,21 @@
      * @param mode The mode supported by the subtype
      * @param extraValue The extra value of the subtype
      * @param isAuxiliary true when this subtype is one shot subtype.
+     * @param overridesImplicitlyEnabledSubtype true when this subtype should be selected by default
+     * if no other subtypes are selected explicitly. Note that a subtype with this parameter being
+     * true will not be shown in the subtypes list.
      */
     public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
-            boolean isAuxiliary) {
+            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
         mSubtypeNameResId = nameId;
         mSubtypeIconResId = iconId;
         mSubtypeLocale = locale != null ? locale : "";
         mSubtypeMode = mode != null ? mode : "";
         mSubtypeExtraValue = extraValue != null ? extraValue : "";
         mIsAuxiliary = isAuxiliary;
+        mOverridesImplicitlyEnabledSubtype = overridesImplicitlyEnabledSubtype;
         mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
-                mIsAuxiliary);
+                mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
     }
 
     InputMethodSubtype(Parcel source) {
@@ -95,8 +102,9 @@
         s = source.readString();
         mSubtypeExtraValue = s != null ? s : "";
         mIsAuxiliary = (source.readInt() == 1);
+        mOverridesImplicitlyEnabledSubtype = (source.readInt() == 1);
         mSubtypeHashCode = hashCodeInternal(mSubtypeLocale, mSubtypeMode, mSubtypeExtraValue,
-                mIsAuxiliary);
+                mIsAuxiliary, mOverridesImplicitlyEnabledSubtype);
     }
 
     /**
@@ -144,6 +152,14 @@
     }
 
     /**
+     * @return true when this subtype is selected by default if no other subtypes are selected
+     * explicitly. Note that a subtype that returns true will not be shown in the subtypes list.
+     */
+    public boolean overridesImplicitlyEnabledSubtype() {
+        return mOverridesImplicitlyEnabledSubtype;
+    }
+
+    /**
      * @param context Context will be used for getting Locale and PackageManager.
      * @param packageName The package name of the IME
      * @param appInfo The application info of the IME
@@ -242,6 +258,7 @@
         dest.writeString(mSubtypeMode);
         dest.writeString(mSubtypeExtraValue);
         dest.writeInt(mIsAuxiliary ? 1 : 0);
+        dest.writeInt(mOverridesImplicitlyEnabledSubtype ? 1 : 0);
     }
 
     public static final Parcelable.Creator<InputMethodSubtype> CREATOR
@@ -274,8 +291,9 @@
     }
 
     private static int hashCodeInternal(String locale, String mode, String extraValue,
-            boolean isAuxiliary) {
-        return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary});
+            boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
+        return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
+                overridesImplicitlyEnabledSubtype});
     }
 
     /**
diff --git a/core/java/android/webkit/JniUtil.java b/core/java/android/webkit/JniUtil.java
index 4264e9d..ef1641d 100644
--- a/core/java/android/webkit/JniUtil.java
+++ b/core/java/android/webkit/JniUtil.java
@@ -28,6 +28,7 @@
 
     static {
         System.loadLibrary("webcore");
+        System.loadLibrary("chromium_net");
     }
     private static final String LOGTAG = "webkit";
     private JniUtil() {} // Utility class, do not instantiate.
diff --git a/core/java/android/webkit/ViewStateSerializer.java b/core/java/android/webkit/ViewStateSerializer.java
index 0fc76fa..5f91ed3 100644
--- a/core/java/android/webkit/ViewStateSerializer.java
+++ b/core/java/android/webkit/ViewStateSerializer.java
@@ -36,11 +36,15 @@
 
     static boolean serializeViewState(OutputStream stream, WebView web)
             throws IOException {
+        int baseLayer = web.getBaseLayer();
+        if (baseLayer == 0) {
+            return false;
+        }
         DataOutputStream dos = new DataOutputStream(stream);
         dos.writeInt(VERSION);
         dos.writeInt(web.getContentWidth());
         dos.writeInt(web.getContentHeight());
-        return nativeSerializeViewState(web.getBaseLayer(), dos,
+        return nativeSerializeViewState(baseLayer, dos,
                 new byte[WORKING_STREAM_STORAGE]);
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4748522..2e7f923 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -34,7 +34,6 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.CornerPathEffect;
 import android.graphics.DrawFilter;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
@@ -58,8 +57,6 @@
 import android.os.StrictMode;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
-import android.text.Selection;
-import android.text.Spannable;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
@@ -606,9 +603,15 @@
     // know to handle Shift and arrows natively first
     private boolean mAccessibilityScriptInjected;
 
+    static final boolean USE_JAVA_TEXT_SELECTION = true;
+    private Region mTextSelectionRegion = new Region();
+    private Paint mTextSelectionPaint;
+    private Drawable mSelectHandleLeft;
+    private Drawable mSelectHandleRight;
+
     static final boolean USE_WEBKIT_RINGS = true;
     // the color used to highlight the touch rectangles
-    private static final int mHightlightColor = 0x6633b5e5;
+    private static final int HIGHLIGHT_COLOR = 0x6633b5e5;
     // the round corner for the highlight path
     private static final float TOUCH_HIGHLIGHT_ARC = 5.0f;
     // the region indicating where the user touched on the screen
@@ -4004,12 +4007,9 @@
         // state.
         // If mNativeClass is 0, we should not reach here, so we do not
         // need to check it again.
-        if (mDrawCursorRing && drawRings) {
-            // Only update if we are actually going to use the result
-            nativeRecordButtons(hasFocus() && hasWindowFocus(),
-                    mTouchMode == TOUCH_SHORTPRESS_START_MODE
-                    || mTrackballDown || mGotCenterDown, false);
-        }
+        nativeRecordButtons(hasFocus() && hasWindowFocus(),
+                (mTouchMode == TOUCH_SHORTPRESS_START_MODE && !USE_WEBKIT_RINGS)
+                || mTrackballDown || mGotCenterDown, false);
         drawCoreAndCursorRing(canvas, mBackgroundColor,
                 mDrawCursorRing && drawRings);
     }
@@ -4050,8 +4050,10 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
+        // if mNativeClass is 0, the WebView is either destroyed or not
+        // initialized. In either case, just draw the background color and return
         if (mNativeClass == 0) {
+            canvas.drawColor(mBackgroundColor);
             return;
         }
 
@@ -4105,7 +4107,7 @@
             } else {
                 if (mTouchHightlightPaint == null) {
                     mTouchHightlightPaint = new Paint();
-                    mTouchHightlightPaint.setColor(mHightlightColor);
+                    mTouchHightlightPaint.setColor(HIGHLIGHT_COLOR);
                 }
                 RegionIterator iter = new RegionIterator(mTouchHighlightRegion);
                 Rect r = new Rect();
@@ -4306,6 +4308,9 @@
     }
 
     int getBaseLayer() {
+        if (mNativeClass == 0) {
+            return 0;
+        }
         return nativeGetBaseLayer();
     }
 
@@ -4400,7 +4405,7 @@
         int extras = DRAW_EXTRAS_NONE;
         if (mFindIsUp) {
             extras = DRAW_EXTRAS_FIND;
-        } else if (mSelectingText) {
+        } else if (mSelectingText && !USE_JAVA_TEXT_SELECTION) {
             extras = DRAW_EXTRAS_SELECTION;
             nativeSetSelectionPointer(mDrawSelectionPointer,
                     mZoomManager.getInvScale(),
@@ -4427,6 +4432,10 @@
                 nativeUseHardwareAccelSkia(mHardwareAccelSkia);
             }
 
+            if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
+                drawTextSelectionHandles(canvas);
+            }
+
         } else {
             DrawFilter df = null;
             if (mZoomManager.isZoomAnimating() || UIAnimationsRunning) {
@@ -4461,6 +4470,56 @@
         }
     }
 
+    private void drawTextSelectionHandles(Canvas canvas) {
+        if (mTextSelectionPaint == null) {
+            mTextSelectionPaint = new Paint();
+            mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
+        }
+        mTextSelectionRegion.setEmpty();
+        nativeGetTextSelectionRegion(mTextSelectionRegion);
+        Rect r = new Rect();
+        RegionIterator iter = new RegionIterator(mTextSelectionRegion);
+        int start_x = -1;
+        int start_y = -1;
+        int end_x = -1;
+        int end_y = -1;
+        while (iter.next(r)) {
+            r = new Rect(
+                    contentToViewDimension(r.left),
+                    contentToViewDimension(r.top),
+                    contentToViewDimension(r.right),
+                    contentToViewDimension(r.bottom));
+            // Regions are in order. First one is where selection starts,
+            // last one is where it ends
+            if (start_x < 0 || start_y < 0) {
+                start_x = r.left;
+                start_y = r.bottom;
+            }
+            end_x = r.right;
+            end_y = r.bottom;
+            canvas.drawRect(r, mTextSelectionPaint);
+        }
+        if (mSelectHandleLeft == null) {
+            mSelectHandleLeft = mContext.getResources().getDrawable(
+                    com.android.internal.R.drawable.text_select_handle_left);
+        }
+        // Magic formula copied from TextView
+        start_x -= (mSelectHandleLeft.getIntrinsicWidth() * 3) / 4;
+        mSelectHandleLeft.setBounds(start_x, start_y,
+                start_x + mSelectHandleLeft.getIntrinsicWidth(),
+                start_y + mSelectHandleLeft.getIntrinsicHeight());
+        if (mSelectHandleRight == null) {
+            mSelectHandleRight = mContext.getResources().getDrawable(
+                    com.android.internal.R.drawable.text_select_handle_right);
+        }
+        end_x -= mSelectHandleRight.getIntrinsicWidth() / 4;
+        mSelectHandleRight.setBounds(end_x, end_y,
+                end_x + mSelectHandleRight.getIntrinsicWidth(),
+                end_y + mSelectHandleRight.getIntrinsicHeight());
+        mSelectHandleLeft.draw(canvas);
+        mSelectHandleRight.draw(canvas);
+    }
+
     // draw history
     private boolean mDrawHistory = false;
     private Picture mHistoryPicture = null;
@@ -9329,4 +9388,5 @@
     private native int      nativeGetBackgroundColor();
     native boolean  nativeSetProperty(String key, String value);
     native String   nativeGetProperty(String key);
+    private native void     nativeGetTextSelectionRegion(Region region);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3ca3eaa..c895b84 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -57,13 +57,14 @@
     private static final String LOGTAG = "webcore";
 
     static {
-        // Load libwebcore during static initialization. This happens in the
-        // zygote process so it will be shared read-only across all app
-        // processes.
+        // Load libwebcore and libchromium_net during static initialization.
+        // This happens in the zygote process so they will be shared read-only
+        // across all app processes.
         try {
             System.loadLibrary("webcore");
+            System.loadLibrary("chromium_net");
         } catch (UnsatisfiedLinkError e) {
-            Log.e(LOGTAG, "Unable to load webcore library");
+            Log.e(LOGTAG, "Unable to load native support libraries.");
         }
     }
 
@@ -537,6 +538,8 @@
 
     private native void nativeSendListBoxChoice(int choice);
 
+    private native void nativeCloseIdleConnections();
+
     /*  Tell webkit what its width and height are, for the purposes
         of layout/line-breaking. These coordinates are in document space,
         which is the same as View coords unless we have zoomed the document
@@ -1040,6 +1043,7 @@
         // Flag for blocking messages. This is used during DESTROY to avoid
         // posting more messages to the EventHub or to WebView's event handler.
         private boolean mBlockMessages;
+        private boolean mDestroying;
 
         private int mTid;
         private int mSavedPriority;
@@ -1071,12 +1075,20 @@
                                 + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
                                 + " obj=" + msg.obj);
                     }
-                    if (mWebView == null
+                    if (mWebView == null || mNativeClass == 0) {
+                        if (DebugFlags.WEB_VIEW_CORE) {
+                            Log.w(LOGTAG, "Rejecting message " + msg.what
+                                    + " because we are destroyed");
+                        }
+                        return;
+                    }
+                    if (mDestroying == true
                             && msg.what != EventHub.RESUME_TIMERS
-                            && msg.what != EventHub.PAUSE_TIMERS) {
+                            && msg.what != EventHub.PAUSE_TIMERS
+                            && msg.what != EventHub.DESTROY) {
                         if (DebugFlags.WEB_VIEW_CORE) {
                             Log.v(LOGTAG, "Rejecting message " + msg.what
-                                    + " because we are destroyed");
+                                    + " because we are being destroyed");
                         }
                         return;
                     }
@@ -1252,6 +1264,8 @@
                             if (!JniUtil.useChromiumHttpStack()) {
                                 WebViewWorker.getHandler().sendEmptyMessage(
                                         WebViewWorker.MSG_PAUSE_CACHE_TRANSACTION);
+                            } else {
+                                nativeCloseIdleConnections();
                             }
                             break;
 
@@ -1780,7 +1794,8 @@
             // or RESUME_TIMERS messages, which we must still handle as they
             // are per process. DESTROY will instead trigger a white list in
             // mEventHub, skipping any remaining messages in the queue
-            mEventHub.sendMessageAtFrontOfQueue(
+            mEventHub.mDestroying = true;
+            mEventHub.sendMessage(
                     Message.obtain(null, EventHub.DESTROY));
             mEventHub.blockMessages();
         }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index f267458c..4ba604d 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -926,6 +926,8 @@
         }
         event.setItemCount(getCount());
         event.setCurrentItemIndex(getSelectedItemPosition());
+        event.setFromIndex(mFirstPosition);
+        event.setToIndex(mFirstPosition + getChildCount());
     }
 
     @Override
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 4812283..3b67f44 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -30,6 +30,7 @@
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.NumberPicker.OnValueChangeListener;
 
 import com.android.internal.R;
@@ -264,6 +265,11 @@
 
         // re-order the number spinners to match the current date format
         reorderSpinners();
+
+        // set content descriptions
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            setContentDescriptions();
+        }
     }
 
     /**
@@ -357,11 +363,16 @@
     }
 
     @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
         super.onPopulateAccessibilityEvent(event);
 
-        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
-                | DateUtils.FORMAT_SHOW_YEAR;
+        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
         String selectedDateUtterance = DateUtils.formatDateTime(mContext,
                 mCurrentDate.getTimeInMillis(), flags);
         event.getText().add(selectedDateUtterance);
@@ -709,5 +720,22 @@
             }
         };
     }
-}
 
+    private void setContentDescriptions() {
+        // Day
+        String text = mContext.getString(R.string.date_picker_increment_day_button);
+        mDaySpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.date_picker_decrement_day_button);
+        mDaySpinner.findViewById(R.id.decrement).setContentDescription(text);
+        // Month
+        text = mContext.getString(R.string.date_picker_increment_month_button);
+        mMonthSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.date_picker_decrement_month_button);
+        mMonthSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        // Year
+        text = mContext.getString(R.string.date_picker_increment_year_button);
+        mYearSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.date_picker_decrement_year_button);
+        mYearSpinner.findViewById(R.id.decrement).setContentDescription(text);
+    }
+}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 2a299bd..35e48f2 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -33,6 +33,7 @@
 import android.graphics.Rect;
 import android.graphics.Paint.Align;
 import android.graphics.drawable.Drawable;
+import android.os.SystemClock;
 import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Spanned;
@@ -48,6 +49,8 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.LayoutInflater.Filter;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.DecelerateInterpolator;
 import android.view.inputmethod.InputMethodManager;
 
@@ -471,7 +474,7 @@
         // the fading edge effect implemented by View and we need our
         // draw() method to be called. Therefore, we declare we will draw.
         setWillNotDraw(false);
-        setDrawSelectorWheel(false);
+        setDrawScrollWheel(false);
 
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
@@ -561,7 +564,7 @@
             public void onAnimationEnd(Animator animation) {
                 if (!mCanceled) {
                     // if canceled => we still want the wheel drawn
-                    setDrawSelectorWheel(false);
+                    setDrawScrollWheel(false);
                 }
                 mCanceled = false;
                 mSelectorPaint.setAlpha(255);
@@ -587,7 +590,7 @@
             // Start with shown selector wheel and hidden controls. When made
             // visible hide the selector and fade-in the controls to suggest
             // fling interaction.
-            setDrawSelectorWheel(true);
+            setDrawScrollWheel(true);
             hideInputControls();
         }
     }
@@ -630,7 +633,7 @@
                         || (!mDecrementButton.isShown()
                                 && isEventInViewHitRect(event, mDecrementButton))) {
                     mAdjustScrollerOnUpEvent = false;
-                    setDrawSelectorWheel(true);
+                    setDrawScrollWheel(true);
                     hideInputControls();
                     return true;
                 }
@@ -641,7 +644,7 @@
                 if (deltaDownY > mTouchSlop) {
                     mBeginEditOnUpEvent = false;
                     onScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
-                    setDrawSelectorWheel(true);
+                    setDrawScrollWheel(true);
                     hideInputControls();
                     return true;
                 }
@@ -678,7 +681,7 @@
                 break;
             case MotionEvent.ACTION_UP:
                 if (mBeginEditOnUpEvent) {
-                    setDrawSelectorWheel(false);
+                    setDrawScrollWheel(false);
                     showInputControls(mShowInputControlsAnimimationDuration);
                     mInputText.requestFocus();
                     InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
@@ -1135,6 +1138,12 @@
         }
     }
 
+    @Override
+    public void sendAccessibilityEvent(int eventType) {
+        // Do not send accessibility events - we want the user to
+        // perceive this widget as several controls rather as a whole.
+    }
+
     /**
      * Resets the selector indices and clear the cached
      * string representation of these indices.
@@ -1192,10 +1201,19 @@
     /**
      * Sets if to <code>drawSelectionWheel</code>.
      */
-    private void setDrawSelectorWheel(boolean drawSelectorWheel) {
+    private void setDrawScrollWheel(boolean drawSelectorWheel) {
         mDrawSelectorWheel = drawSelectorWheel;
         // do not fade if the selector wheel not shown
         setVerticalFadingEdgeEnabled(drawSelectorWheel);
+
+        if (mFlingable && mDrawSelectorWheel
+                && AccessibilityManager.getInstance(mContext).isEnabled()) {
+            AccessibilityManager.getInstance(mContext).interrupt();
+            String text = mContext.getString(R.string.number_picker_increment_scroll_action);
+            mInputText.setContentDescription(text);
+            mInputText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+            mInputText.setContentDescription(null);
+        }
     }
 
     private void initializeScrollWheel() {
@@ -1429,6 +1447,12 @@
             mInputText.setText(mDisplayedValues[mValue - mMinValue]);
         }
         mInputText.setSelection(mInputText.getText().length());
+
+        if (mFlingable && AccessibilityManager.getInstance(mContext).isEnabled()) {
+            String text = mContext.getString(R.string.number_picker_increment_scroll_mode,
+                    mInputText.getText());
+            mInputText.setContentDescription(text);
+        }
     }
 
     /**
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index b89b8ec..14cbf6f 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -1,4 +1,18 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2011 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.widget;
 
@@ -32,7 +46,7 @@
 
     private final TextView mTextView;
 
-    final SpellCheckerSession spellCheckerSession;
+    final SpellCheckerSession mSpellCheckerSession;
     final int mCookie;
 
     // Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position
@@ -49,7 +63,7 @@
 
         final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
                 getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
-        spellCheckerSession = textServicesManager.newSpellCheckerSession(
+        mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
                 null /* not currently used by the textServicesManager */, Locale.getDefault(),
                 this, true /* means use the languages defined in Settings */);
         mCookie = hashCode();
@@ -112,7 +126,7 @@
 
     private void scheduleSpellCheck() {
         if (mLength == 0) return;
-        if (spellCheckerSession == null) return;
+        if (mSpellCheckerSession == null) return;
 
         if (mChecker != null) {
             mTextView.removeCallbacks(mChecker);
@@ -157,7 +171,7 @@
                 System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount);
                 textInfos = textInfosCopy;
             }
-            spellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
+            mSpellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
                     false /* TODO Set sequentialWords to true for initial spell check */);
         }
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4ce2d90..1aa009b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -63,8 +63,8 @@
 import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
 import android.text.TextUtils;
-import android.text.TextWatcher;
 import android.text.TextUtils.TruncateAt;
+import android.text.TextWatcher;
 import android.text.method.AllCapsTransformationMethod;
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.DateKeyListener;
@@ -82,7 +82,6 @@
 import android.text.method.TransformationMethod;
 import android.text.method.TransformationMethod2;
 import android.text.method.WordIterator;
-import android.text.style.CharacterStyle;
 import android.text.style.ClickableSpan;
 import android.text.style.EasyEditSpan;
 import android.text.style.ParagraphStyle;
@@ -131,6 +130,7 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView.OnItemClickListener;
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.util.FastMath;
@@ -7868,7 +7868,9 @@
 
         @Override
         protected void initContentView() {
-            mContentView.setOrientation(LinearLayout.HORIZONTAL);
+            LinearLayout linearLayout = new LinearLayout(TextView.this.getContext());
+            linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+            mContentView = linearLayout;
             mContentView.setBackgroundResource(
                     com.android.internal.R.drawable.text_edit_side_paste_window);
 
@@ -8177,17 +8179,6 @@
         startStopMarquee(hasWindowFocus);
     }
 
-    private void removeSpans(int start, int end, Class<?> type) {
-        if (mText instanceof Editable) {
-            Editable editable = ((Editable) mText);
-            Object[] spans = editable.getSpans(start, end, type);
-            final int length = spans.length;
-            for (int i = 0; i < length; i++) {
-                editable.removeSpan(spans[i]);
-            }
-        }
-    }
-
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -9326,7 +9317,7 @@
 
     private abstract class PinnedPopupWindow implements TextViewPositionListener {
         protected PopupWindow mPopupWindow;
-        protected LinearLayout mContentView;
+        protected ViewGroup mContentView;
         int mPositionX, mPositionY;
 
         protected abstract void createPopupWindow();
@@ -9342,23 +9333,16 @@
             mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
             mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
 
-            mContentView = new LinearLayout(TextView.this.getContext());
-            LayoutParams wrapContent = new LayoutParams(
-                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+            initContentView();
+
+            LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
             mContentView.setLayoutParams(wrapContent);
 
-            initContentView();
             mPopupWindow.setContentView(mContentView);
         }
 
         public void show() {
-            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
-            mContentView.measure(
-                    View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
-                            View.MeasureSpec.AT_MOST),
-                    View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
-                            View.MeasureSpec.AT_MOST));
-
             TextView.this.getPositionListener().addSubscriber(this, false);
 
             computeLocalPosition();
@@ -9366,11 +9350,24 @@
             final PositionListener positionListener = TextView.this.getPositionListener();
             updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
         }
+        
+        protected void measureContent() {
+            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+            mContentView.measure(
+                    View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
+                            View.MeasureSpec.AT_MOST),
+                    View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
+                            View.MeasureSpec.AT_MOST));
+        }
 
+        /* The popup window will be horizontally centered on the getTextOffset() and vertically
+         * positioned according to viewportToContentHorizontalOffset.
+         * 
+         * This method assumes that mContentView has properly been measured from its content. */
         private void computeLocalPosition() {
-            final int offset = getTextOffset();
-
+            measureContent();
             final int width = mContentView.getMeasuredWidth();
+            final int offset = getTextOffset();
             mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
             mPositionX += viewportToContentHorizontalOffset();
 
@@ -9418,42 +9415,17 @@
         }
     }
 
-    private static class SuggestionRangeSpan extends CharacterStyle {
-
-        private final int mTextColor;
-        private final int mBackgroundColor;
-
-        public SuggestionRangeSpan(Context context) {
-            TypedArray typedArray = context.obtainStyledAttributes(null,
-                    com.android.internal.R.styleable.SuggestionRangeSpan,
-                    com.android.internal.R.attr.textAppearanceSuggestionRange, 0);
-
-            mTextColor = typedArray.getColor(
-                    com.android.internal.R.styleable.SuggestionRangeSpan_textColor, 0);
-            mBackgroundColor = typedArray.getColor(
-                    com.android.internal.R.styleable.SuggestionRangeSpan_colorBackground, 0);
-        }
-
-        @Override
-        public void updateDrawState(TextPaint tp) {
-            if (mTextColor != 0) {
-                tp.setColor(mTextColor);
-            }
-
-            if (mBackgroundColor != 0) {
-                tp.bgColor = mBackgroundColor;
-            }
-        }
-    }
-
-    private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener {
+    private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
         private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
         private static final int NO_SUGGESTIONS = -1;
         private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
         private WordIterator mSuggestionWordIterator;
         private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
                 [(int) (AVERAGE_HIGHLIGHTS_PER_SUGGESTION * MAX_NUMBER_SUGGESTIONS)];
+        private SuggestionInfo[] mSuggestionInfos;
+        private int mNumberOfSuggestions;
         private boolean mCursorWasVisibleBeforeSuggestions;
+        private SuggestionAdapter mSuggestionsAdapter;
 
         private class CustomPopupWindow extends PopupWindow {
             public CustomPopupWindow(Context context, int defStyle) {
@@ -9494,29 +9466,16 @@
 
         @Override
         protected void initContentView() {
-            mContentView.setOrientation(LinearLayout.VERTICAL);
-
-            LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
-                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
-            if (inflater == null) {
-                throw new IllegalArgumentException(
-                        "Unable to create inflater for TextEdit suggestions");
-            }
+            ListView listView = new ListView(TextView.this.getContext());
+            mSuggestionsAdapter = new SuggestionAdapter();
+            listView.setAdapter(mSuggestionsAdapter);
+            listView.setOnItemClickListener(this);
+            mContentView = listView;
 
             // Inflate the suggestion items once and for all.
+            mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
             for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
-                View childView = inflater.inflate(mTextEditSuggestionItemLayout,
-                        mContentView, false);
-
-                if (! (childView instanceof TextView)) {
-                    throw new IllegalArgumentException(
-                            "Inflated TextEdit suggestion item is not a TextView: " + childView);
-                }
-
-                childView.setTag(new SuggestionInfo());
-                mContentView.addView(childView);
-                childView.setOnClickListener(this);
+                mSuggestionInfos[i] = new SuggestionInfo();
             }
         }
 
@@ -9525,6 +9484,40 @@
             int spanStart, spanEnd; // range in TextView where text should be inserted
             SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
             int suggestionIndex; // the index of the suggestion inside suggestionSpan
+            SpannableStringBuilder text = new SpannableStringBuilder();
+        }
+
+        private class SuggestionAdapter extends BaseAdapter {
+            private LayoutInflater mInflater = (LayoutInflater) TextView.this.mContext.
+                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            @Override
+            public int getCount() {
+                return mNumberOfSuggestions;
+            }
+
+            @Override
+            public Object getItem(int position) {
+                return mSuggestionInfos[position];
+            }
+
+            @Override
+            public long getItemId(int position) {
+                return position;
+            }
+
+            @Override
+            public View getView(int position, View convertView, ViewGroup parent) {
+                TextView textView = (TextView) convertView;
+
+                if (textView == null) {
+                    textView = (TextView) mInflater.inflate(mTextEditSuggestionItemLayout, parent,
+                            false);
+                }
+
+                textView.setText(mSuggestionInfos[position].text);
+                return textView;
+            }
         }
 
         /**
@@ -9569,6 +9562,36 @@
         }
 
         @Override
+        protected void measureContent() {
+            final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+            final int horizontalMeasure = View.MeasureSpec.makeMeasureSpec(
+                    displayMetrics.widthPixels, View.MeasureSpec.AT_MOST);
+            final int verticalMeasure = View.MeasureSpec.makeMeasureSpec(
+                    displayMetrics.heightPixels, View.MeasureSpec.AT_MOST);
+            
+            int width = 0;
+            View view = null;
+            for (int i = 0; i < mNumberOfSuggestions; i++) {
+                view = mSuggestionsAdapter.getView(i, view, mContentView);
+                view.measure(horizontalMeasure, verticalMeasure);
+                width = Math.max(width, view.getMeasuredWidth());
+            }
+
+            // Enforce the width based on actual text widths
+            mContentView.measure(
+                    View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                    verticalMeasure);
+
+            Drawable popupBackground = mPopupWindow.getBackground();
+            if (popupBackground != null) {
+                if (mTempRect == null) mTempRect = new Rect();
+                popupBackground.getPadding(mTempRect);
+                width += mTempRect.left + mTempRect.right;
+            }
+            mPopupWindow.setWidth(width);
+        }
+
+        @Override
         protected int getTextOffset() {
             return getSelectionStart();
         }
@@ -9596,7 +9619,7 @@
 
             final int nbSpans = suggestionSpans.length;
 
-            int totalNbSuggestions = 0;
+            mNumberOfSuggestions = 0;
             int spanUnionStart = mText.length();
             int spanUnionEnd = 0;
 
@@ -9610,17 +9633,15 @@
                 String[] suggestions = suggestionSpan.getSuggestions();
                 int nbSuggestions = suggestions.length;
                 for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
-                    TextView textView = (TextView) mContentView.getChildAt(
-                            totalNbSuggestions);
-                    textView.setText(suggestions[suggestionIndex]);
-                    SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
+                    SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
                     suggestionInfo.spanStart = spanStart;
                     suggestionInfo.spanEnd = spanEnd;
                     suggestionInfo.suggestionSpan = suggestionSpan;
                     suggestionInfo.suggestionIndex = suggestionIndex;
+                    suggestionInfo.text = new SpannableStringBuilder(suggestions[suggestionIndex]);
 
-                    totalNbSuggestions++;
-                    if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) {
+                    mNumberOfSuggestions++;
+                    if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
                         // Also end outer for loop
                         spanIndex = nbSpans;
                         break;
@@ -9628,31 +9649,18 @@
                 }
             }
 
-            if (totalNbSuggestions == 0) return false;
+            if (mNumberOfSuggestions == 0) return false;
 
-            if (mSuggestionRangeSpan == null) {
-                mSuggestionRangeSpan = new SuggestionRangeSpan(getContext());
-            }
-            
-            ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
-                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
+                    new SuggestionRangeSpan(mHighlightColor);
 
-            if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = 
-                    new SuggestionRangeSpan(getContext());
             ((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
-            for (int i = 0; i < totalNbSuggestions; i++) {
-                final TextView textView = (TextView) mContentView.getChildAt(i);
-                highlightTextDifferences(textView, spanUnionStart, spanUnionEnd);
+            for (int i = 0; i < mNumberOfSuggestions; i++) {
+                highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
             }
-
-            for (int i = 0; i < totalNbSuggestions; i++) {
-                mContentView.getChildAt(i).setVisibility(VISIBLE);
-            }
-            for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) {
-                mContentView.getChildAt(i).setVisibility(GONE);
-            }
+            mSuggestionsAdapter.notifyDataSetChanged();
 
             return true;
         }
@@ -9719,13 +9727,13 @@
             return highlightSpan;
         }
 
-        private void highlightTextDifferences(TextView textView, int unionStart, int unionEnd) {
-            SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
+        private void highlightTextDifferences(SuggestionInfo suggestionInfo,
+                int unionStart, int unionEnd) {
             final int spanStart = suggestionInfo.spanStart;
             final int spanEnd = suggestionInfo.spanEnd;
 
             // Remove all text formating by converting to Strings
-            final String text = textView.getText().toString();
+            final String text = suggestionInfo.text.toString();
             final String sourceText = mText.subSequence(spanStart, spanEnd).toString();
 
             long[] sourceWordLimits = getWordLimits(sourceText);
@@ -9800,7 +9808,7 @@
             if (previousCommonWordIndex < words.length - 1) {
                 int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 :
                     extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
-                int lastDifferentPosition = textView.length();
+                int lastDifferentPosition = text.length();
                 ssb.setSpan(highlightSpan(nbHighlightSpans++),
                         shift + firstDifferentPosition, shift + lastDifferentPosition,
                         Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -9811,25 +9819,24 @@
 
                 int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 :
                     extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
-                String textSpaces = text.substring(lastCommonTextWordEnd, textView.length());
+                String textSpaces = text.substring(lastCommonTextWordEnd, text.length());
 
                 if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) {
                     ssb.setSpan(highlightSpan(nbHighlightSpans++),
-                            shift + lastCommonTextWordEnd, shift + textView.length(),
+                            shift + lastCommonTextWordEnd, shift + text.length(),
                             Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                 }
             }
 
             // Final part, text after the current suggestion range.
             ssb.append(mText.subSequence(spanEnd, unionEnd).toString());
-            textView.setText(ssb);
         }
 
         @Override
-        public void onClick(View view) {
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             if (view instanceof TextView) {
                 TextView textView = (TextView) view;
-                SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
+                SuggestionInfo suggestionInfo = mSuggestionInfos[position];
                 final int spanStart = suggestionInfo.spanStart;
                 final int spanEnd = suggestionInfo.spanEnd;
                 if (spanStart != NO_SUGGESTIONS) {
@@ -10190,9 +10197,11 @@
 
         @Override
         protected void initContentView() {
-            mContentView.setOrientation(LinearLayout.HORIZONTAL);
+            LinearLayout linearLayout = new LinearLayout(TextView.this.getContext());
+            linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+            mContentView = linearLayout;
             mContentView.setBackgroundResource(
-                    com.android.internal.R.drawable.text_edit_side_paste_window);
+                    com.android.internal.R.drawable.text_edit_paste_window);
 
             LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -11282,7 +11291,7 @@
     private final TextPaint         mTextPaint;
     private boolean                 mUserSetTextScaleX;
     private final Paint             mHighlightPaint;
-    private int                     mHighlightColor = 0xCC475925;
+    private int                     mHighlightColor = 0x4C33B5E5;
     /**
      * This is temporarily visible to fix bug 3085564 in webView. Do not rely on
      * this field being protected. Will be restored as private when lineHeight
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 0547438..2350229 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -29,6 +29,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.NumberPicker.OnValueChangeListener;
 
 import java.text.DateFormatSymbols;
@@ -227,6 +228,11 @@
         if (!isEnabled()) {
             setEnabled(false);
         }
+
+        // set the content descriptions
+        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+            setContentDescriptions();
+        }
     }
 
     @Override
@@ -433,6 +439,12 @@
     }
 
     @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
         super.onPopulateAccessibilityEvent(event);
 
@@ -487,4 +499,22 @@
             mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
         }
     }
+
+    private void setContentDescriptions() {
+        // Minute
+        String text = mContext.getString(R.string.time_picker_increment_minute_button);
+        mMinuteSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.time_picker_decrement_minute_button);
+        mMinuteSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        // Hour
+        text = mContext.getString(R.string.time_picker_increment_hour_button);
+        mHourSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.time_picker_decrement_hour_button);
+        mHourSpinner.findViewById(R.id.decrement).setContentDescription(text);
+        // AM/PM
+        text = mContext.getString(R.string.time_picker_increment_set_pm_button);
+        mAmPmSpinner.findViewById(R.id.increment).setContentDescription(text);
+        text = mContext.getString(R.string.time_picker_decrement_set_am_button);
+        mAmPmSpinner.findViewById(R.id.decrement).setContentDescription(text);
+    }
 }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index ce0299c..683aca5 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -68,5 +68,5 @@
     boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
     boolean switchToLastInputMethod(in IBinder token);
     boolean setInputMethodEnabled(String id, boolean enabled);
-    boolean setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
+    oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
 }
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 76bc535..cd1f8ba 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -902,13 +902,13 @@
             String directionDescription = getDirectionDescription(i);
             if (!TextUtils.isEmpty(targetDescription)
                     && !TextUtils.isEmpty(directionDescription)) {
-                utterance.append(targetDescription);
-                utterance.append(" ");
-                utterance.append(directionDescription);
-                utterance.append(".");
+                String text = String.format(directionDescription, targetDescription);
+                utterance.append(text);
+            }
+            if (utterance.length() > 0) {
+                announceText(utterance.toString());
             }
         }
-        announceText(utterance.toString());
     }
 
     private void announceText(String text) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 01f2a8f..f50cecd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -920,7 +920,7 @@
     <!-- Allows applications to write the apn settings -->
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
                 android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-                android:protectionLevel="dangerous"
+                android:protectionLevel="signatureOrSystem"
                 android:description="@string/permdesc_writeApnSettings"
                 android:label="@string/permlab_writeApnSettings" />
 
diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml
index 7e0e05f..987fd89 100644
--- a/core/res/res/anim/wallpaper_close_exit.xml
+++ b/core/res/res/anim/wallpaper_close_exit.xml
@@ -29,4 +29,7 @@
             android:fillEnabled="true" android:fillAfter="true"
             android:interpolator="@interpolator/decelerate_quint"
             android:duration="300" />
+    <!-- This is needed to keep the animation running while wallpaper_close_enter completes -->
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:duration="600" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 075831b..1804fa8 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -29,5 +29,7 @@
                 android:interpolator="@interpolator/accelerate_quint"
                 android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
                 android:duration="200" />
-
+        <!-- This is needed to keep the animation running while wallpaper_open_enter completes -->
+        <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+                android:duration="500" />
 </set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
index 6654e4d..b74f37b 100644
--- a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png
index c97514f..b74f37b 100644
--- a/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png
+++ b/core/res/res/drawable-hdpi/text_edit_suggestions_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
index 41886eb..16f623d 100644
--- a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png
index 88be6e1..16f623d 100644
--- a/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_suggestions_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png b/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png
new file mode 100644
index 0000000..5c043b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png b/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png
new file mode 100644
index 0000000..5c043b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml
index 4c8c0d1..0368530 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml
@@ -131,7 +131,7 @@
 
             android:targetDrawables="@array/lockscreen_targets_with_camera"
             android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
-            android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera"
+            android:directionDescriptions="@array/lockscreen_direction_descriptions"
             android:handleDrawable="@drawable/ic_lockscreen_handle"
             android:waveDrawable="@drawable/ic_lockscreen_outerring"
             android:outerRadius="@dimen/multiwaveview_target_placement_radius"
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index ba55f0c0..2849376 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -136,7 +136,7 @@
 
         android:targetDrawables="@array/lockscreen_targets_with_camera"
         android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
-        android:directionDescriptions="@array/lockscreen_direction_descriptions_with_camera"
+        android:directionDescriptions="@array/lockscreen_direction_descriptions"
         android:handleDrawable="@drawable/ic_lockscreen_handle"
         android:waveDrawable="@drawable/ic_lockscreen_outerring"
         android:outerRadius="@dimen/multiwaveview_target_placement_radius"
diff --git a/core/res/res/layout/text_edit_action_popup_text.xml b/core/res/res/layout/text_edit_action_popup_text.xml
index aa6a5e1..42e6f2e 100644
--- a/core/res/res/layout/text_edit_action_popup_text.xml
+++ b/core/res/res/layout/text_edit_action_popup_text.xml
@@ -25,4 +25,5 @@
     android:textAppearance="?android:attr/textAppearanceSmallInverse"
     android:textColor="@android:color/black"
     android:textAllCaps="true"
+    android:textStyle="bold"
 />
diff --git a/core/res/res/values-land/arrays.xml b/core/res/res/values-land/arrays.xml
index 57aafc8..68e5cfd 100644
--- a/core/res/res/values-land/arrays.xml
+++ b/core/res/res/values-land/arrays.xml
@@ -34,7 +34,7 @@
         <item>@string/description_target_soundon</item>
     </array>
 
-    <array name="lockscreen_direction_descriptions_when_silent">
+    <array name="lockscreen_direction_descriptions">
         <item>@null</item>
         <item>@string/description_direction_up</item>
         <item>@null</item>
@@ -55,13 +55,6 @@
         <item>@string/description_target_silent</item>
     </array>
 
-    <array name="lockscreen_direction_descriptions_when_soundon">
-        <item>@null</item>
-        <item>@string/description_direction_up</item>
-        <item>@null</item>
-        <item>@string/description_direction_down</item>
-    </array>
-
     <array name="lockscreen_targets_with_camera">
         <item>@null</item>
         <item>@drawable/ic_lockscreen_unlock</item>
@@ -76,11 +69,4 @@
         <item>@string/description_target_camera</item>
     </array>
 
-    <array name="lockscreen_direction_descriptions_with_camera">
-        <item>@null</item>
-        <item>@string/description_direction_up</item>
-        <item>@null</item>
-        <item>@string/description_direction_down</item>
-    </array>
-
 </resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index c9043ba..8d5bd0b 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -356,7 +356,7 @@
         <item>@null</item>
     </array>
 
-    <array name="lockscreen_direction_descriptions_when_silent">
+    <array name="lockscreen_direction_descriptions">
         <item>@string/description_direction_right</item>
         <item>@null</item>
         <item>@string/description_direction_left</item>
@@ -377,13 +377,6 @@
         <item>@null</item>
     </array>
 
-    <array name="lockscreen_direction_descriptions_when_soundon">
-        <item>@string/description_direction_right</item>
-        <item>@null</item>
-        <item>@string/description_direction_left</item>
-        <item>@null</item>
-    </array>
-
     <array name="lockscreen_targets_with_camera">
         <item>@drawable/ic_lockscreen_unlock</item>
         <item>@null</item>
@@ -398,11 +391,4 @@
         <item>@null</item>
     </array>
 
-    <array name="lockscreen_direction_descriptions_with_camera">
-        <item>@string/description_direction_right</item>
-        <item>@null</item>
-        <item>@string/description_direction_left</item>
-        <item>@null</item>
-    </array>
-
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fed5651..0bf5b0a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -158,10 +158,6 @@
         <!-- The underline color and thickness for misspelled suggestion -->
         <attr name="textAppearanceMisspelledSuggestion" format="reference" />
 
-        <!-- The text color and the background for suggestion range span. This span identifies the
-        portion of text the suggestions refer to). -->
-        <attr name="textAppearanceSuggestionRange" format="reference" />
-
         <!--  The underline color -->
         <attr name="textUnderlineColor" format="reference|color" />
         <!--  The underline thickness -->
@@ -2241,6 +2237,10 @@
              InputMethodManager#switchToLastInputMethod will ignore auxiliary subtypes when it
              chooses a target subtype. -->
         <attr name="isAuxiliary" format="boolean" />
+        <!-- Set true when this subtype should be selected by default if no other subtypes are
+             selected explicitly. Note that a subtype with this parameter being true will
+             not be shown in the subtypes list. -->
+        <attr name="overridesImplicitlyEnabledSubtype" format="boolean" />
         <!-- The extra value of the subtype. This string can be any string and will be passed to
              the IME when the framework calls the IME with the subtype.  -->
         <attr name="imeSubtypeExtraValue" format="string" />
@@ -3154,10 +3154,6 @@
         <attr name="textUnderlineColor" />
         <attr name="textUnderlineThickness" />
     </declare-styleable>
-    <declare-styleable name="SuggestionRangeSpan">
-        <attr name="textColor" />
-        <attr name="colorBackground" />
-    </declare-styleable>
     <!-- An <code>input-extras</code> is a container for extra data to supply to
          an input method.  Contains
          one more more {@link #Extra <extra>} tags.  -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index aee7ea4..fd525f3 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -54,8 +54,6 @@
     <color name="dim_foreground_light_inverse">#bebebe</color>
     <color name="dim_foreground_light_inverse_disabled">#80bebebe</color>
     <color name="hint_foreground_light">#808080</color>
-    <color name="highlight_background">#cc475925</color>
-    <color name="highlight_background_inverse">#ccd2e461</color>
     <color name="highlighted_text_dark">#9983CC39</color>
     <color name="highlighted_text_light">#9983CC39</color>
     <color name="link_text_dark">#5c5cff</color>
@@ -135,10 +133,8 @@
     <color name="dim_foreground_inverse_holo_light">#bebebe</color>
     <color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
     <color name="hint_foreground_holo_light">#808080</color>
-    <color name="highlight_background_holo">#cc475925</color>
-    <color name="highlight_background_inverse_holo">#ccd2e461</color>
-    <color name="highlighted_text_holo_dark">#9983CC39</color>
-    <color name="highlighted_text_holo_light">#9983CC39</color>
+    <color name="highlighted_text_holo_dark">#4c33b5e5</color>
+    <color name="highlighted_text_holo_light">#4c33b5e5</color>
     <color name="link_text_holo_dark">#5c5cff</color>
     <color name="link_text_holo_light">#0000ee</color>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6988f6b..bc2b907 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2010,4 +2010,5 @@
   <public type="attr" name="targetDescriptions" />
   <public type="attr" name="directionDescriptions" />
 
+  <public type="attr" name="overridesImplicitlyEnabledSubtype" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a9e2971..685ebb7 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3091,6 +3091,38 @@
     <string name="number_picker_increment_button">Increment</string>
     <!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
     <string name="number_picker_decrement_button">Decrement</string>
+    <!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] -->
+    <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> tap and hold.</string>
+    <!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] -->
+    <string name="number_picker_increment_scroll_action">Slide up to increment and down to decrement.</string>
+
+    <!-- TimePicker - accessibility support -->
+    <!-- Description of the button to increment the TimePicker's minute value. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_increment_minute_button">Increment minute</string>
+    <!-- Description of the button to decrement the TimePicker's minute value. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_decrement_minute_button">Decrement minute</string>
+    <!-- Description of the button to increment the TimePicker's hour value. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_increment_hour_button">Increment hour</string>
+    <!-- Description of the button to decrement the TimePicker's hour value. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_decrement_hour_button">Decrement hour</string>
+    <!-- Description of the button to increment the TimePicker's set PM value. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_increment_set_pm_button">Set PM</string>
+    <!-- Description of the button to decrement the TimePicker's set AM value. [CHAR LIMIT=NONE] -->
+    <string name="time_picker_decrement_set_am_button">Set AM</string>
+
+    <!-- DatePicker - accessibility support -->
+    <!-- Description of the button to increment the DatePicker's month value. [CHAR LIMIT=NONE] -->
+    <string name="date_picker_increment_month_button">Increment month</string>
+    <!-- Description of the button to decrement the DatePicker's month value. [CHAR LIMIT=NONE] -->
+    <string name="date_picker_decrement_month_button">Decrement month</string>
+    <!-- Description of the button to increment the DatePicker's day value. [CHAR LIMIT=NONE] -->
+    <string name="date_picker_increment_day_button">Increment day</string>
+    <!-- Description of the button to decrement the DatePicker's day value. [CHAR LIMIT=NONE] -->
+    <string name="date_picker_decrement_day_button">Decrement day</string>
+    <!-- Description of the button to increment the DatePicker's year value. [CHAR LIMIT=NONE] -->
+    <string name="date_picker_increment_year_button">Increment year</string>
+    <!-- Description of the button to decrement the DatePicker's year value. [CHAR LIMIT=NONE] -->
+    <string name="date_picker_decrement_year_button">Decrement year</string>
 
     <!-- CheckBox - accessibility support -->
     <!-- Description of the checked state of a CheckBox. [CHAR LIMIT=NONE] -->
@@ -3138,13 +3170,13 @@
     <string name="content_description_sliding_handle">"Sliding handle. Tap and hold."</string>
 
     <!-- Description of the up direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_up">"Up</string>
+    <string name="description_direction_up">Up for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
     <!-- Description of the down direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_down">Down</string>
+    <string name="description_direction_down">Down for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
     <!-- Description of the left direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_left">"Left</string>
+    <string name="description_direction_left">"Left for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
     <!-- Description of the right direction in which one can to slide the handle in the Slide unlock screen. [CHAR LIMIT=NONE] -->
-    <string name="description_direction_right">Right</string>
+    <string name="description_direction_right">Right for <xliff:g id="target_description" example="Unlock">%s</xliff:g>.</string>
 
     <!-- Description of the unlock target in the Slide unlock screen. [CHAR LIMIT=NONE] -->
     <string name="description_target_unlock">Unlock</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 1a2ad05..1a6a523 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -255,11 +255,6 @@
         <item name="android:textUnderlineColor">@color/holo_red_light</item>
     </style>
 
-    <style name="TextAppearance.SuggestionRange">
-        <item name="android:textColor">@color/white</item>
-        <item name="android:colorBackground">@color/holo_blue_dark</item>
-    </style>
-
     <!-- Widget Styles -->
 
     <style name="Widget">
@@ -1554,6 +1549,7 @@
 
     <style name="Widget.Holo.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
         <item name="android:background">@android:drawable/list_section_divider_holo_dark</item>
+        <item name="android:textAllCaps">true</item>
     </style>
 
     <style name="Widget.Holo.TextSelectHandle" parent="Widget.TextSelectHandle">
@@ -1997,6 +1993,7 @@
 
     <style name="Widget.Holo.Light.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
         <item name="android:background">@android:drawable/list_section_divider_holo_light</item>
+        <item name="android:textAllCaps">true</item>
     </style>
 
     <style name="Widget.Holo.Light.TextSelectHandle" parent="Widget.TextSelectHandle">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 899c9d5..f434ce8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -91,7 +91,6 @@
 
         <item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item>
         <item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</item>
-        <item name="textAppearanceSuggestionRange">@android:style/TextAppearance.SuggestionRange</item>
 
         <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
         
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index cacbdaa..56bd2ce 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -14,15 +14,14 @@
 
 # Warning: this is actually a product definition, to be inherited from
 
+# On space-constrained devices, we include a subset of fonts:
+# First, core/required fonts
 PRODUCT_COPY_FILES := \
     frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \
     frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \
     frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \
     frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \
-    frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \
-    frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \
     frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \
-    frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf \
     frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \
     frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \
     frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \
@@ -33,9 +32,22 @@
     frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
     frameworks/base/data/fonts/Lohit_Hindi.ttf:system/fonts/Lohit_Hindi.ttf \
     frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
-    frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf \
     frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
     frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
     frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \
     frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \
     frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml
+
+# Next, include additional fonts, depending on how much space we have
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+# Smaller fonts alternatives
+PRODUCT_COPY_FILES += \
+    frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf
+else
+# Full font set alternatives
+PRODUCT_COPY_FILES += \
+    frameworks/base/data/fonts/DroidSansFallbackFull.ttf:system/fonts/DroidSansFallback.ttf \
+    frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \
+    frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \
+    frameworks/base/data/fonts/DroidSansEthiopic-Regular.ttf:system/fonts/DroidSansEthiopic-Regular.ttf
+endif
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index fd6bf17..610e821 100755
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -41,29 +41,4 @@
 	$(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Andromeda.ogg:system/media/audio/ringtones/Andromeda.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Bootes.ogg:system/media/audio/ringtones/Bootes.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/CanisMajor.ogg:system/media/audio/ringtones/CanisMajor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Cassiopeia.ogg:system/media/audio/ringtones/Cassiopeia.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Eridani.ogg:system/media/audio/ringtones/Eridani.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Hydra.ogg:system/media/audio/ringtones/hydra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Iridium.ogg:system/media/audio/ringtones/Iridium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Lyra.ogg:system/media/audio/ringtones/Lyra.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Perseus.ogg:system/media/audio/ringtones/Perseus.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg \
 	$(LOCAL_PATH)/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Testudo.ogg:system/media/audio/ringtones/Testudo.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/UrsaMinor.ogg:system/media/audio/ringtones/UrsaMinor.ogg \
-	$(LOCAL_PATH)/ringtones/ogg/Vespa.ogg:system/media/audio/ringtones/Vespa.ogg
diff --git a/data/sounds/alarms/ogg/Copernicium.ogg b/data/sounds/alarms/ogg/Copernicium.ogg
index c619e8b..65d2867 100644
--- a/data/sounds/alarms/ogg/Copernicium.ogg
+++ b/data/sounds/alarms/ogg/Copernicium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Curium.ogg b/data/sounds/alarms/ogg/Curium.ogg
index ebce391..125a236 100644
--- a/data/sounds/alarms/ogg/Curium.ogg
+++ b/data/sounds/alarms/ogg/Curium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Fermium.ogg b/data/sounds/alarms/ogg/Fermium.ogg
index 6132565..6940442 100644
--- a/data/sounds/alarms/ogg/Fermium.ogg
+++ b/data/sounds/alarms/ogg/Fermium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Hassium.ogg b/data/sounds/alarms/ogg/Hassium.ogg
index 408b7c2..86b2b71 100644
--- a/data/sounds/alarms/ogg/Hassium.ogg
+++ b/data/sounds/alarms/ogg/Hassium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Neptunium.ogg b/data/sounds/alarms/ogg/Neptunium.ogg
index 058e2db..1a99141 100644
--- a/data/sounds/alarms/ogg/Neptunium.ogg
+++ b/data/sounds/alarms/ogg/Neptunium.ogg
Binary files differ
diff --git a/data/sounds/alarms/ogg/Nobelium.ogg b/data/sounds/alarms/ogg/Nobelium.ogg
index 33878c9..4309bc6 100644
--- a/data/sounds/alarms/ogg/Nobelium.ogg
+++ b/data/sounds/alarms/ogg/Nobelium.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Altair.ogg b/data/sounds/notifications/ogg/Altair.ogg
old mode 100755
new mode 100644
index d84b59e..407aeb9
--- a/data/sounds/notifications/ogg/Altair.ogg
+++ b/data/sounds/notifications/ogg/Altair.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Antares.ogg b/data/sounds/notifications/ogg/Antares.ogg
old mode 100755
new mode 100644
index 9d60917..409c684
--- a/data/sounds/notifications/ogg/Antares.ogg
+++ b/data/sounds/notifications/ogg/Antares.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Betelgeuse.ogg b/data/sounds/notifications/ogg/Betelgeuse.ogg
index 83c7722..488d1e8 100644
--- a/data/sounds/notifications/ogg/Betelgeuse.ogg
+++ b/data/sounds/notifications/ogg/Betelgeuse.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Deneb.ogg b/data/sounds/notifications/ogg/Deneb.ogg
old mode 100755
new mode 100644
index e58b3b6..b84eae3
--- a/data/sounds/notifications/ogg/Deneb.ogg
+++ b/data/sounds/notifications/ogg/Deneb.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Hojus.ogg b/data/sounds/notifications/ogg/Hojus.ogg
index fc8f73f..65b780c 100644
--- a/data/sounds/notifications/ogg/Hojus.ogg
+++ b/data/sounds/notifications/ogg/Hojus.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Lalande.ogg b/data/sounds/notifications/ogg/Lalande.ogg
old mode 100755
new mode 100644
index b6e253a..eda9c9d
--- a/data/sounds/notifications/ogg/Lalande.ogg
+++ b/data/sounds/notifications/ogg/Lalande.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Mira.ogg b/data/sounds/notifications/ogg/Mira.ogg
index f21e3c4..f5a6e94 100644
--- a/data/sounds/notifications/ogg/Mira.ogg
+++ b/data/sounds/notifications/ogg/Mira.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Proxima.ogg b/data/sounds/notifications/ogg/Proxima.ogg
index 235b5ca..53bf899 100644
--- a/data/sounds/notifications/ogg/Proxima.ogg
+++ b/data/sounds/notifications/ogg/Proxima.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Upsilon.ogg b/data/sounds/notifications/ogg/Upsilon.ogg
index 036dcad..e970422 100644
--- a/data/sounds/notifications/ogg/Upsilon.ogg
+++ b/data/sounds/notifications/ogg/Upsilon.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Cassiopeia.ogg b/data/sounds/ringtones/ogg/Cassiopeia.ogg
index 61c4d27..b871940 100644
--- a/data/sounds/ringtones/ogg/Cassiopeia.ogg
+++ b/data/sounds/ringtones/ogg/Cassiopeia.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Lyra.ogg b/data/sounds/ringtones/ogg/Lyra.ogg
index b7f740d..d170bc0 100644
--- a/data/sounds/ringtones/ogg/Lyra.ogg
+++ b/data/sounds/ringtones/ogg/Lyra.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Sceptrum.ogg b/data/sounds/ringtones/ogg/Sceptrum.ogg
index 89d64d70..e94abe0 100644
--- a/data/sounds/ringtones/ogg/Sceptrum.ogg
+++ b/data/sounds/ringtones/ogg/Sceptrum.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Solarium.ogg b/data/sounds/ringtones/ogg/Solarium.ogg
index 361367a..8dac71e 100644
--- a/data/sounds/ringtones/ogg/Solarium.ogg
+++ b/data/sounds/ringtones/ogg/Solarium.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/UrsaMinor.ogg b/data/sounds/ringtones/ogg/UrsaMinor.ogg
index a80801d..a90d1de 100644
--- a/data/sounds/ringtones/ogg/UrsaMinor.ogg
+++ b/data/sounds/ringtones/ogg/UrsaMinor.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ogg/Vespa.ogg b/data/sounds/ringtones/ogg/Vespa.ogg
index 1f75ec8..f637831 100644
--- a/data/sounds/ringtones/ogg/Vespa.ogg
+++ b/data/sounds/ringtones/ogg/Vespa.ogg
Binary files differ
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 896f81e..ee65223 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1594,7 +1594,7 @@
     }
 
     /**
-     * Return the glypth Ids for the characters in the string.
+     * Return the glyph Ids for the characters in the string.
      *
      * @param text   The text to measure
      * @param start  The index of the first char to to measure
@@ -1613,7 +1613,7 @@
      *
      * Used only for BiDi / RTL Tests
      */
-    public int getTextGlypths(String text, int start, int end, int contextStart, int contextEnd,
+    public int getTextGlyphs(String text, int start, int end, int contextStart, int contextEnd,
             int flags, char[] glyphs) {
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 6c91dfc..4a4bcfb 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -495,6 +495,25 @@
     // Example value: "true" or "false". Read/write.
     static const char KEY_RECORDING_HINT[];
 
+    // Returns true if video snapshot is supported. That is, applications
+    // can call Camera.takePicture during recording. Applications do not need to
+    // call Camera.startPreview after taking a picture. The preview will be
+    // still active. Other than that, taking a picture during recording is
+    // identical to taking a picture normally. All settings and methods related
+    // to takePicture work identically. Ex: KEY_PICTURE_SIZE,
+    // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc.
+    // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON
+    // also still work, but the video will record the flash.
+    //
+    // Applications can set shutter callback as null to avoid the shutter
+    // sound. It is also recommended to set raw picture and post view callbacks
+    // to null to avoid the interrupt of preview display.
+    //
+    // Field-of-view of the recorded video may be different from that of the
+    // captured pictures.
+    // Example value: "true" or "false". Read only.
+    static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
+
     // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
     static const char TRUE[];
     static const char FALSE[];
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index d552b2e..0e2cdf7 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -20,11 +20,13 @@
 #include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
+#include <utils/KeyedVector.h>
 
 namespace android {
 
 class Parcel;
 class Surface;
+class IStreamSource;
 class ISurfaceTexture;
 
 class IMediaPlayer: public IInterface
@@ -34,6 +36,10 @@
 
     virtual void            disconnect() = 0;
 
+    virtual status_t        setDataSource(const char *url,
+                                    const KeyedVector<String8, String8>* headers) = 0;
+    virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
+    virtual status_t        setDataSource(const sp<IStreamSource>& source) = 0;
     virtual status_t        setVideoSurface(const sp<Surface>& surface) = 0;
     virtual status_t        setVideoSurfaceTexture(
                                     const sp<ISurfaceTexture>& surfaceTexture) = 0;
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 7956788..93bbe13 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -39,17 +39,9 @@
 public:
     DECLARE_META_INTERFACE(MediaPlayerService);
 
-    virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;
+    virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
-    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
-            const char* url, const KeyedVector<String8, String8> *headers = NULL,
-            int audioSessionId = 0) = 0;
-    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
-            int fd, int64_t offset, int64_t length, int audioSessionId) = 0;
-
-    virtual sp<IMediaPlayer> create(
-            pid_t pid, const sp<IMediaPlayerClient> &client,
-            const sp<IStreamSource> &source, int audioSessionId) = 0;
+    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 0;
 
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 1a67671..e98d55c 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -21,6 +21,7 @@
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
 #include <media/IMediaDeathNotifier.h>
+#include <media/IStreamSource.h>
 
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
@@ -168,6 +169,7 @@
                     const KeyedVector<String8, String8> *headers);
 
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
+            status_t        setDataSource(const sp<IStreamSource> &source);
             status_t        setVideoSurface(const sp<Surface>& surface);
             status_t        setVideoSurfaceTexture(
                                     const sp<ISurfaceTexture>& surfaceTexture);
@@ -206,7 +208,7 @@
             status_t        seekTo_l(int msec);
             status_t        prepareAsync_l();
             status_t        getDuration_l(int *msec);
-            status_t        setDataSource(const sp<IMediaPlayer>& player);
+            status_t        attachNewPlayer(const sp<IMediaPlayer>& player);
             void            disconnectNativeWindow();
             status_t        reset_l();
 
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index f7f0ed7..d0940bb 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -34,7 +34,7 @@
 class SurfaceMediaSource : public BnSurfaceTexture, public MediaSource,
                                             public MediaBufferObserver {
 public:
-    enum { MIN_UNDEQUEUED_BUFFERS = 3 };
+    enum { MIN_UNDEQUEUED_BUFFERS = 4 };
     enum {
         MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
         MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 0eb5d50..0dcab6b 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -87,6 +87,7 @@
 const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
 const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
 const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
+const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
 
 const char CameraParameters::TRUE[] = "true";
 const char CameraParameters::FALSE[] = "false";
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 44ea79c..0755fb7 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -37,6 +37,7 @@
 struct DrvScript {
     int (*mRoot)();
     void (*mInit)();
+    void (*mFreeChildren)();
 
     BCCScriptRef mBccScript;
 
@@ -125,6 +126,7 @@
 
     drv->mRoot = reinterpret_cast<int (*)()>(bccGetFuncAddr(drv->mBccScript, "root"));
     drv->mInit = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, "init"));
+    drv->mFreeChildren = reinterpret_cast<void (*)()>(bccGetFuncAddr(drv->mBccScript, ".rs.dtor"));
 
     exportFuncCount = drv->ME->getExportFuncCount();
     if (exportFuncCount > 0) {
@@ -430,6 +432,13 @@
     }
 }
 
+void rsdScriptInvokeFreeChildren(const Context *dc, Script *script) {
+    DrvScript *drv = (DrvScript *)script->mHal.drv;
+
+    if (drv->mFreeChildren) {
+        drv->mFreeChildren();
+    }
+}
 
 void rsdScriptInvokeFunction(const Context *dc, Script *script,
                             uint32_t slot,
diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h
index 67929bc..5f83ed2 100644
--- a/libs/rs/driver/rsdBcc.h
+++ b/libs/rs/driver/rsdBcc.h
@@ -43,6 +43,8 @@
                         android::renderscript::Script *script);
 void rsdScriptInvokeInit(const android::renderscript::Context *dc,
                          android::renderscript::Script *script);
+void rsdScriptInvokeFreeChildren(const android::renderscript::Context *dc,
+                                 android::renderscript::Script *script);
 
 void rsdScriptSetGlobalVar(const android::renderscript::Context *,
                            const android::renderscript::Script *,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 171d045..a38fff77 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -60,6 +60,7 @@
         rsdScriptInvokeRoot,
         rsdScriptInvokeForEach,
         rsdScriptInvokeInit,
+        rsdScriptInvokeFreeChildren,
         rsdScriptSetGlobalVar,
         rsdScriptSetGlobalBind,
         rsdScriptSetGlobalObj,
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index f62c72e..93513fe 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -72,6 +72,12 @@
     mRSC->mHal.funcs.script.setGlobalObj(mRSC, this, slot, val);
 }
 
+bool Script::freeChildren() {
+    incSysRef();
+    mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this);
+    return decSysRef();
+}
+
 namespace android {
 namespace renderscript {
 
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index c0324dd..d645421 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -73,6 +73,8 @@
     void setVar(uint32_t slot, const void *val, size_t len);
     void setVarObj(uint32_t slot, ObjectBase *val);
 
+    virtual bool freeChildren();
+
     virtual void runForEach(Context *rsc,
                             const Allocation * ain,
                             Allocation * aout,
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index dccf71f..2e7f213 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -44,6 +44,7 @@
         BT = NULL;
     }
 #endif
+    mRSC->mHal.funcs.script.invokeFreeChildren(mRSC, this);
     mRSC->mHal.funcs.script.destroy(mRSC, this);
 }
 
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 21dff218..b8d7351 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -90,6 +90,7 @@
                               uint32_t usrLen,
                               const RsScriptCall *sc);
         void (*invokeInit)(const Context *rsc, Script *s);
+        void (*invokeFreeChildren)(const Context *rsc, Script *s);
 
         void (*setGlobalVar)(const Context *rsc, const Script *s,
                              uint32_t slot,
diff --git a/libs/rs/scriptc/rs_cl.rsh b/libs/rs/scriptc/rs_cl.rsh
index 98b0b1d..bbc8fc5 100644
--- a/libs/rs/scriptc/rs_cl.rsh
+++ b/libs/rs/scriptc/rs_cl.rsh
@@ -660,7 +660,6 @@
 extern float __attribute__((overloadable)) trunc(float);
 FN_FUNC_FN(trunc)
 
-// Int ops (partial), 6.11.3
 
 #define XN_FUNC_YN(typeout, fnc, typein)                                \
 extern typeout __attribute__((overloadable)) fnc(typein);               \
@@ -704,14 +703,29 @@
 UIN_FUNC_IN(abs)
 IN_FUNC_IN(clz)
 
+/**
+ * Return the minimum of two values.
+ *
+ * Supports 1,2,3,4 components of uchar, char, ushort, short, uint, int, float.
+ */
 IN_FUNC_IN_IN_BODY(min, (v1 < v2 ? v1 : v2))
 FN_FUNC_FN_F(min)
 
+/**
+ * Return the maximum of two values.
+ *
+ * Supports 1,2,3,4 components of uchar, char, ushort, short, uint, int, float.
+ */
 IN_FUNC_IN_IN_BODY(max, (v1 > v2 ? v1 : v2))
 FN_FUNC_FN_F(max)
 
-// 6.11.4
-
+/**
+ *  Clamp a value to a specified high and low bound.
+ *
+ * @param amount value to be clamped.  Supports 1,2,3,4 components
+ * @param low Lower bound, must be scalar or matching vector.
+ * @param high High bound, must match type of low
+ */
 _RS_RUNTIME float __attribute__((overloadable)) clamp(float amount, float low, float high);
 _RS_RUNTIME float2 __attribute__((overloadable)) clamp(float2 amount, float2 low, float2 high);
 _RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float3 low, float3 high);
@@ -720,9 +734,19 @@
 _RS_RUNTIME float3 __attribute__((overloadable)) clamp(float3 amount, float low, float high);
 _RS_RUNTIME float4 __attribute__((overloadable)) clamp(float4 amount, float low, float high);
 
+/**
+ * Convert from radians to degrees.
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) degrees(float radians);
 FN_FUNC_FN(degrees)
 
+/**
+ * return start + ((stop - start) * amount);
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) mix(float start, float stop, float amount);
 _RS_RUNTIME float2 __attribute__((overloadable)) mix(float2 start, float2 stop, float2 amount);
 _RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float3 amount);
@@ -731,9 +755,22 @@
 _RS_RUNTIME float3 __attribute__((overloadable)) mix(float3 start, float3 stop, float amount);
 _RS_RUNTIME float4 __attribute__((overloadable)) mix(float4 start, float4 stop, float amount);
 
+/**
+ * Convert from degrees to radians.
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) radians(float degrees);
 FN_FUNC_FN(radians)
 
+/**
+ * if (v < edge)
+ *     return 0.f;
+ * else
+ *     return 1.f;
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) step(float edge, float v);
 _RS_RUNTIME float2 __attribute__((overloadable)) step(float2 edge, float2 v);
 _RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float3 v);
@@ -742,6 +779,7 @@
 _RS_RUNTIME float3 __attribute__((overloadable)) step(float3 edge, float v);
 _RS_RUNTIME float4 __attribute__((overloadable)) step(float4 edge, float v);
 
+// not implemented
 extern float __attribute__((overloadable)) smoothstep(float, float, float);
 extern float2 __attribute__((overloadable)) smoothstep(float2, float2, float2);
 extern float3 __attribute__((overloadable)) smoothstep(float3, float3, float3);
@@ -750,29 +788,59 @@
 extern float3 __attribute__((overloadable)) smoothstep(float, float, float3);
 extern float4 __attribute__((overloadable)) smoothstep(float, float, float4);
 
+/**
+ * if (v < 0) return -1.f;
+ * else if (v > 0) return 1.f;
+ * else return 0.f;
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) sign(float v);
 FN_FUNC_FN(sign)
 
-// 6.11.5
+/**
+ * Compute the cross product of two vectors.
+ *
+ * Supports 3,4 components
+ */
 _RS_RUNTIME float3 __attribute__((overloadable)) cross(float3 lhs, float3 rhs);
-
 _RS_RUNTIME float4 __attribute__((overloadable)) cross(float4 lhs, float4 rhs);
 
+/**
+ * Compute the dot product of two vectors.
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) dot(float lhs, float rhs);
 _RS_RUNTIME float __attribute__((overloadable)) dot(float2 lhs, float2 rhs);
 _RS_RUNTIME float __attribute__((overloadable)) dot(float3 lhs, float3 rhs);
 _RS_RUNTIME float __attribute__((overloadable)) dot(float4 lhs, float4 rhs);
 
+/**
+ * Compute the length of a vector.
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) length(float v);
 _RS_RUNTIME float __attribute__((overloadable)) length(float2 v);
 _RS_RUNTIME float __attribute__((overloadable)) length(float3 v);
 _RS_RUNTIME float __attribute__((overloadable)) length(float4 v);
 
+/**
+ * Compute the distance between two points.
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) distance(float lhs, float rhs);
 _RS_RUNTIME float __attribute__((overloadable)) distance(float2 lhs, float2 rhs);
 _RS_RUNTIME float __attribute__((overloadable)) distance(float3 lhs, float3 rhs);
 _RS_RUNTIME float __attribute__((overloadable)) distance(float4 lhs, float4 rhs);
 
+/**
+ * Normalize a vector.
+ *
+ * Supports 1,2,3,4 components
+ */
 _RS_RUNTIME float __attribute__((overloadable)) normalize(float v);
 _RS_RUNTIME float2 __attribute__((overloadable)) normalize(float2 v);
 _RS_RUNTIME float3 __attribute__((overloadable)) normalize(float3 v);
diff --git a/libs/rs/scriptc/rs_quaternion.rsh b/libs/rs/scriptc/rs_quaternion.rsh
index 36e6736..23945ae 100644
--- a/libs/rs/scriptc/rs_quaternion.rsh
+++ b/libs/rs/scriptc/rs_quaternion.rsh
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-/** @file rs_matrix.rsh
+/** @file rs_quaternion.rsh
  *  \brief Quaternion routines
  *
  *
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index ddd9d1f..cd15718 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -2638,7 +2638,7 @@
                 notifyTopOfAudioFocusStack();
                 // there's a new top of the stack, let the remote control know
                 synchronized(mRCStack) {
-                    checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
                 }
             }
         } else {
@@ -2681,7 +2681,7 @@
             notifyTopOfAudioFocusStack();
             // there's a new top of the stack, let the remote control know
             synchronized(mRCStack) {
-                checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
             }
         }
     }
@@ -2785,7 +2785,7 @@
 
             // there's a new top of the stack, let the remote control know
             synchronized(mRCStack) {
-                checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
             }
         }//synchronized(mAudioFocusLock)
 
@@ -3183,7 +3183,7 @@
      * Helper function:
      * Called synchronized on mRCStack
      */
-    private void clearRemoteControlDisplay_syncRcs() {
+    private void clearRemoteControlDisplay_syncAfRcs() {
         synchronized(mCurrentRcLock) {
             mCurrentRcClient = null;
         }
@@ -3192,18 +3192,21 @@
     }
 
     /**
-     * Helper function:
-     * Called synchronized on mRCStack
-     * mRCStack.isEmpty() is false
+     * Helper function for code readability: only to be called from
+     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
+     *    this method.
+     * Preconditions:
+     *    - called synchronized mAudioFocusLock then on mRCStack
+     *    - mRCStack.isEmpty() is false
      */
-    private void updateRemoteControlDisplay_syncRcs(int infoChangedFlags) {
+    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
         RemoteControlStackEntry rcse = mRCStack.peek();
         int infoFlagsAboutToBeUsed = infoChangedFlags;
         // this is where we enforce opt-in for information display on the remote controls
         //   with the new AudioManager.registerRemoteControlClient() API
         if (rcse.mRcClient == null) {
             //Log.w(TAG, "Can't update remote control display with null remote control client");
-            clearRemoteControlDisplay_syncRcs();
+            clearRemoteControlDisplay_syncAfRcs();
             return;
         }
         synchronized(mCurrentRcLock) {
@@ -3220,17 +3223,17 @@
 
     /**
      * Helper function:
-     * Called synchronized on mFocusLock, then mRCStack
+     * Called synchronized on mAudioFocusLock, then mRCStack
      * Check whether the remote control display should be updated, triggers the update if required
      * @param infoChangedFlags the flags corresponding to the remote control client information
      *     that has changed, if applicable (checking for the update conditions might trigger a
      *     clear, rather than an update event).
      */
-    private void checkUpdateRemoteControlDisplay_syncRcs(int infoChangedFlags) {
+    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
         // determine whether the remote control display should be refreshed
         // if either stack is empty, there is a mismatch, so clear the RC display
         if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
-            clearRemoteControlDisplay_syncRcs();
+            clearRemoteControlDisplay_syncAfRcs();
             return;
         }
         // if the top of the two stacks belong to different packages, there is a mismatch, clear
@@ -3238,18 +3241,18 @@
                 && (mFocusStack.peek().mPackageName != null)
                 && !(mRCStack.peek().mCallingPackageName.compareTo(
                         mFocusStack.peek().mPackageName) == 0)) {
-            clearRemoteControlDisplay_syncRcs();
+            clearRemoteControlDisplay_syncAfRcs();
             return;
         }
         // if the audio focus didn't originate from the same Uid as the one in which the remote
         //   control information will be retrieved, clear
         if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
-            clearRemoteControlDisplay_syncRcs();
+            clearRemoteControlDisplay_syncAfRcs();
             return;
         }
         // refresh conditions were verified: update the remote controls
-        // ok to call, mRCStack is not empty
-        updateRemoteControlDisplay_syncRcs(infoChangedFlags);
+        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
+        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
     }
 
     /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
@@ -3260,7 +3263,7 @@
             synchronized(mRCStack) {
                 pushMediaButtonReceiver(eventReceiver);
                 // new RC client, assume every type of information shall be queried
-                checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
             }
         }
     }
@@ -3275,7 +3278,7 @@
                 removeMediaButtonReceiver(eventReceiver);
                 if (topOfStackWillChange) {
                     // current RC client will change, assume every type of info needs to be queried
-                    checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
                 }
             }
         }
@@ -3284,6 +3287,7 @@
     /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
     public void registerRemoteControlClient(ComponentName eventReceiver,
             IRemoteControlClient rcClient, String clientName, String callingPackageName) {
+        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
                 // store the new display information
@@ -3331,7 +3335,7 @@
                 // if the eventReceiver is at the top of the stack
                 // then check for potential refresh of the remote controls
                 if (isCurrentRcController(eventReceiver)) {
-                    checkUpdateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
                 }
             }
         }
@@ -3436,35 +3440,35 @@
      */
     public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
         if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
-        synchronized(mRCStack) {
-            if ((mRcDisplay == rcd) || (rcd == null)) {
-                return;
-            }
-            // if we had a display before, stop monitoring its death
-            rcDisplay_stopDeathMonitor_syncRcStack();
-            mRcDisplay = rcd;
-            // new display, start monitoring its death
-            rcDisplay_startDeathMonitor_syncRcStack();
+        synchronized(mAudioFocusLock) {
+            synchronized(mRCStack) {
+                if ((mRcDisplay == rcd) || (rcd == null)) {
+                    return;
+                }
+                // if we had a display before, stop monitoring its death
+                rcDisplay_stopDeathMonitor_syncRcStack();
+                mRcDisplay = rcd;
+                // new display, start monitoring its death
+                rcDisplay_startDeathMonitor_syncRcStack();
 
-            // let all the remote control clients there is a new display
-            // no need to unplug the previous because we only support one display
-            // and the clients don't track the death of the display
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                if(rcse.mRcClient != null) {
-                    try {
-                        rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Error connecting remote control display to client: " + e);
-                        e.printStackTrace();
+                // let all the remote control clients there is a new display
+                // no need to unplug the previous because we only support one display
+                // and the clients don't track the death of the display
+                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+                while(stackIterator.hasNext()) {
+                    RemoteControlStackEntry rcse = stackIterator.next();
+                    if(rcse.mRcClient != null) {
+                        try {
+                            rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Error connecting remote control display to client: " + e);
+                            e.printStackTrace();
+                        }
                     }
                 }
-            }
 
-            if (!mRCStack.isEmpty()) {
                 // we have a new display, of which all the clients are now aware: have it be updated
-                updateRemoteControlDisplay_syncRcs(RC_INFO_ALL);
+                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
             }
         }
     }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1ee9a1f..e25f654 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -459,6 +459,9 @@
  * android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
  * element.
  *
+ * <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
+ * when used with network-based content.
+ *
  * <a name="Callbacks"></a>
  * <h3>Callbacks</h3>
  * <p>Applications may want to register for informational and error
@@ -828,6 +831,7 @@
                 fd.close();
             }
         }
+
         Log.d(TAG, "Couldn't open file on client side, trying server side");
         setDataSource(uri.toString(), headers);
         return;
@@ -839,7 +843,8 @@
      * @param path the path of the file, or the http/rtsp URL of the stream you want to play
      * @throws IllegalStateException if it is called in an invalid state
      */
-    public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException;
+    public native void setDataSource(String path)
+            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
 
     /**
      * Sets the data source (file-path or http/rtsp URL) to use.
@@ -850,7 +855,7 @@
      * @hide pending API council
      */
     public void setDataSource(String path, Map<String, String> headers)
-            throws IOException, IllegalArgumentException, IllegalStateException
+            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
     {
         String[] keys = null;
         String[] values = null;
@@ -871,7 +876,7 @@
 
     private native void _setDataSource(
         String path, String[] keys, String[] values)
-        throws IOException, IllegalArgumentException, IllegalStateException;
+        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
 
     /**
      * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 354f2c9..5dfbe01 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -155,6 +155,8 @@
     } else {  // Throw exception!
         if ( opStatus == (status_t) INVALID_OPERATION ) {
             jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
+            jniThrowException(env, "java/lang/SecurityException", NULL);
         } else if ( opStatus != (status_t) OK ) {
             if (strlen(message) > 230) {
                // if the message is too long, don't bother displaying the status code
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 52885d2..bd89ad8 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -21,14 +21,20 @@
 #include <binder/Parcel.h>
 
 #include <media/IMediaPlayer.h>
+#include <media/IStreamSource.h>
+
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/Surface.h>
 #include <gui/ISurfaceTexture.h>
+#include <utils/String8.h>
 
 namespace android {
 
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SET_DATA_SOURCE_URL,
+    SET_DATA_SOURCE_FD,
+    SET_DATA_SOURCE_STREAM,
     SET_VIDEO_SURFACE,
     PREPARE_ASYNC,
     START,
@@ -68,6 +74,43 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
+    status_t setDataSource(const char* url,
+            const KeyedVector<String8, String8>* headers)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeCString(url);
+        if (headers == NULL) {
+            data.writeInt32(0);
+        } else {
+            // serialize the headers
+            data.writeInt32(headers->size());
+            for (size_t i = 0; i < headers->size(); ++i) {
+                data.writeString8(headers->keyAt(i));
+                data.writeString8(headers->valueAt(i));
+            }
+        }
+        remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setDataSource(int fd, int64_t offset, int64_t length) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeFileDescriptor(fd);
+        data.writeInt64(offset);
+        data.writeInt64(length);
+        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t setDataSource(const sp<IStreamSource> &source) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeStrongBinder(source->asBinder());
+        return reply.readInt32();
+    }
+
     // pass the buffered Surface to the media player service
     status_t setVideoSurface(const sp<Surface>& surface)
     {
@@ -273,6 +316,34 @@
             disconnect();
             return NO_ERROR;
         } break;
+        case SET_DATA_SOURCE_URL: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            const char* url = data.readCString();
+            KeyedVector<String8, String8> headers;
+            int32_t numHeaders = data.readInt32();
+            for (int i = 0; i < numHeaders; ++i) {
+                String8 key = data.readString8();
+                String8 value = data.readString8();
+                headers.add(key, value);
+            }
+            reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL));
+            return NO_ERROR;
+        } break;
+        case SET_DATA_SOURCE_FD: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            int fd = data.readFileDescriptor();
+            int64_t offset = data.readInt64();
+            int64_t length = data.readInt64();
+            reply->writeInt32(setDataSource(fd, offset, length));
+            return NO_ERROR;
+        }
+        case SET_DATA_SOURCE_STREAM: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            sp<IStreamSource> source =
+                interface_cast<IStreamSource>(data.readStrongBinder());
+            reply->writeInt32(setDataSource(source));
+            return NO_ERROR;
+        }
         case SET_VIDEO_SURFACE: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<Surface> surface = Surface::readFromParcel(data);
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 17a0362..8e4dd04 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -30,9 +30,7 @@
 namespace android {
 
 enum {
-    CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
-    CREATE_FD,
-    CREATE_STREAM,
+    CREATE = IBinder::FIRST_CALL_TRANSACTION,
     DECODE_URL,
     DECODE_FD,
     CREATE_MEDIA_RECORDER,
@@ -60,28 +58,14 @@
     }
 
     virtual sp<IMediaPlayer> create(
-            pid_t pid, const sp<IMediaPlayerClient>& client,
-            const char* url, const KeyedVector<String8, String8> *headers, int audioSessionId) {
+            pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId) {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeStrongBinder(client->asBinder());
-        data.writeCString(url);
-
-        if (headers == NULL) {
-            data.writeInt32(0);
-        } else {
-            // serialize the headers
-            data.writeInt32(headers->size());
-            for (size_t i = 0; i < headers->size(); ++i) {
-                data.writeString8(headers->keyAt(i));
-                data.writeString8(headers->valueAt(i));
-            }
-        }
         data.writeInt32(audioSessionId);
 
-        remote()->transact(CREATE_URL, data, &reply);
-
+        remote()->transact(CREATE, data, &reply);
         return interface_cast<IMediaPlayer>(reply.readStrongBinder());
     }
 
@@ -94,38 +78,6 @@
         return interface_cast<IMediaRecorder>(reply.readStrongBinder());
     }
 
-    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd,
-            int64_t offset, int64_t length, int audioSessionId)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        data.writeInt32(pid);
-        data.writeStrongBinder(client->asBinder());
-        data.writeFileDescriptor(fd);
-        data.writeInt64(offset);
-        data.writeInt64(length);
-        data.writeInt32(audioSessionId);
-
-        remote()->transact(CREATE_FD, data, &reply);
-
-        return interface_cast<IMediaPlayer>(reply.readStrongBinder());;
-    }
-
-    virtual sp<IMediaPlayer> create(
-            pid_t pid, const sp<IMediaPlayerClient> &client,
-            const sp<IStreamSource> &source, int audioSessionId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        data.writeInt32(static_cast<int32_t>(pid));
-        data.writeStrongBinder(client->asBinder());
-        data.writeStrongBinder(source->asBinder());
-        data.writeInt32(static_cast<int32_t>(audioSessionId));
-
-        remote()->transact(CREATE_STREAM, data, &reply);
-
-        return interface_cast<IMediaPlayer>(reply.readStrongBinder());;
-    }
-
     virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
     {
         Parcel data, reply;
@@ -181,62 +133,16 @@
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch(code) {
-        case CREATE_URL: {
+        case CREATE: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             pid_t pid = data.readInt32();
             sp<IMediaPlayerClient> client =
                 interface_cast<IMediaPlayerClient>(data.readStrongBinder());
-            const char* url = data.readCString();
-
-            KeyedVector<String8, String8> headers;
-            int32_t numHeaders = data.readInt32();
-            for (int i = 0; i < numHeaders; ++i) {
-                String8 key = data.readString8();
-                String8 value = data.readString8();
-                headers.add(key, value);
-            }
             int audioSessionId = data.readInt32();
-
-            sp<IMediaPlayer> player = create(
-                    pid, client, url, numHeaders > 0 ? &headers : NULL, audioSessionId);
-
+            sp<IMediaPlayer> player = create(pid, client, audioSessionId);
             reply->writeStrongBinder(player->asBinder());
             return NO_ERROR;
         } break;
-        case CREATE_FD: {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-            pid_t pid = data.readInt32();
-            sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
-            int fd = dup(data.readFileDescriptor());
-            int64_t offset = data.readInt64();
-            int64_t length = data.readInt64();
-            int audioSessionId = data.readInt32();
-
-            sp<IMediaPlayer> player = create(pid, client, fd, offset, length, audioSessionId);
-            reply->writeStrongBinder(player->asBinder());
-            return NO_ERROR;
-        } break;
-        case CREATE_STREAM:
-        {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-
-            pid_t pid = static_cast<pid_t>(data.readInt32());
-
-            sp<IMediaPlayerClient> client =
-                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
-
-            sp<IStreamSource> source =
-                interface_cast<IStreamSource>(data.readStrongBinder());
-
-            int audioSessionId = static_cast<int>(data.readInt32());
-
-            sp<IMediaPlayer> player =
-                create(pid, client, source, audioSessionId);
-
-            reply->writeStrongBinder(player->asBinder());
-            return OK;
-            break;
-        }
         case DECODE_URL: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             const char* url = data.readCString();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 67a66a2..0fc6a8a 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -108,7 +108,7 @@
 }
 
 
-status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
+status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player)
 {
     status_t err = UNKNOWN_ERROR;
     sp<IMediaPlayer> p;
@@ -117,7 +117,7 @@
 
         if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
                 (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
-            LOGE("setDataSource called in state %d", mCurrentState);
+            LOGE("attachNewPlayer called in state %d", mCurrentState);
             return INVALID_OPERATION;
         }
 
@@ -147,9 +147,11 @@
     if (url != NULL) {
         const sp<IMediaPlayerService>& service(getMediaPlayerService());
         if (service != 0) {
-            sp<IMediaPlayer> player(
-                    service->create(getpid(), this, url, headers, mAudioSessionId));
-            err = setDataSource(player);
+            sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
+            err = attachNewPlayer(player);
+            if (err == NO_ERROR) {
+                err = mPlayer->setDataSource(url, headers);
+            }
         }
     }
     return err;
@@ -161,8 +163,26 @@
     status_t err = UNKNOWN_ERROR;
     const sp<IMediaPlayerService>& service(getMediaPlayerService());
     if (service != 0) {
-        sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId));
-        err = setDataSource(player);
+        sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
+        err = attachNewPlayer(player);
+        if (err == NO_ERROR) {
+            err = mPlayer->setDataSource(fd, offset, length);
+        }
+    }
+    return err;
+}
+
+status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
+{
+    LOGV("setDataSource");
+    status_t err = UNKNOWN_ERROR;
+    const sp<IMediaPlayerService>& service(getMediaPlayerService());
+    if (service != 0) {
+        sp<IMediaPlayer> player(service->create(getpid(), this, mAudioSessionId));
+        err = attachNewPlayer(player);
+        if (err == NO_ERROR) {
+            err = mPlayer->setDataSource(source);
+        }
     }
     return err;
 }
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 2051b3b..0386d4b 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -176,6 +176,16 @@
 
 namespace android {
 
+static bool checkPermission(const char* permissionString) {
+#ifndef HAVE_ANDROID_OS
+    return true;
+#endif
+    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
+    bool ok = checkCallingPermission(String16(permissionString));
+    if (!ok) LOGE("Request requires %s", permissionString);
+    return ok;
+}
+
 // TODO: Temp hack until we can register players
 typedef struct {
     const char *extension;
@@ -245,31 +255,8 @@
     return retriever;
 }
 
-sp<IMediaPlayer> MediaPlayerService::create(
-        pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
-        const KeyedVector<String8, String8> *headers, int audioSessionId)
-{
-    int32_t connId = android_atomic_inc(&mNextConnId);
-
-    sp<Client> c = new Client(
-            this, pid, connId, client, audioSessionId,
-            IPCThreadState::self()->getCallingUid());
-
-    LOGV("Create new client(%d) from pid %d, uid %d, url=%s, connId=%d, audioSessionId=%d",
-            connId, pid, IPCThreadState::self()->getCallingUid(), url, connId, audioSessionId);
-    if (NO_ERROR != c->setDataSource(url, headers))
-    {
-        c.clear();
-        return c;
-    }
-    wp<Client> w = c;
-    Mutex::Autolock lock(mLock);
-    mClients.add(w);
-    return c;
-}
-
 sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
-        int fd, int64_t offset, int64_t length, int audioSessionId)
+        int audioSessionId)
 {
     int32_t connId = android_atomic_inc(&mNextConnId);
 
@@ -277,40 +264,14 @@
             this, pid, connId, client, audioSessionId,
             IPCThreadState::self()->getCallingUid());
 
-    LOGV("Create new client(%d) from pid %d, uid %d, fd=%d, offset=%lld, "
-         "length=%lld, audioSessionId=%d", connId, pid,
-         IPCThreadState::self()->getCallingUid(), fd, offset, length, audioSessionId);
-    if (NO_ERROR != c->setDataSource(fd, offset, length)) {
-        c.clear();
-    } else {
-        wp<Client> w = c;
+    LOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
+         IPCThreadState::self()->getCallingUid());
+
+    wp<Client> w = c;
+    {
         Mutex::Autolock lock(mLock);
         mClients.add(w);
     }
-    ::close(fd);
-    return c;
-}
-
-sp<IMediaPlayer> MediaPlayerService::create(
-        pid_t pid, const sp<IMediaPlayerClient> &client,
-        const sp<IStreamSource> &source, int audioSessionId) {
-    int32_t connId = android_atomic_inc(&mNextConnId);
-
-    sp<Client> c = new Client(
-            this, pid, connId, client, audioSessionId,
-            IPCThreadState::self()->getCallingUid());
-
-    LOGV("Create new client(%d) from pid %d, audioSessionId=%d",
-         connId, pid, audioSessionId);
-
-    if (OK != c->setDataSource(source)) {
-        c.clear();
-    } else {
-        wp<Client> w = c;
-        Mutex::Autolock lock(mLock);
-        mClients.add(w);
-    }
-
     return c;
 }
 
@@ -701,6 +662,14 @@
     if (url == NULL)
         return UNKNOWN_ERROR;
 
+    if ((strncmp(url, "http://", 7) == 0) ||
+        (strncmp(url, "https://", 8) == 0) ||
+        (strncmp(url, "rtsp://", 7) == 0)) {
+        if (!checkPermission("android.permission.INTERNET")) {
+            return PERMISSION_DENIED;
+        }
+    }
+
     if (strncmp(url, "content://", 10) == 0) {
         // get a filedescriptor for the content Uri and
         // pass it to the setDataSource(fd) method
@@ -781,6 +750,7 @@
     // now set data source
     mStatus = p->setDataSource(fd, offset, length);
     if (mStatus == NO_ERROR) mPlayer = p;
+
     return mStatus;
 }
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index e32b92a..53e625a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -188,16 +188,7 @@
     void    removeMediaRecorderClient(wp<MediaRecorderClient> client);
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
 
-    // House keeping for media player clients
-    virtual sp<IMediaPlayer>    create(
-            pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
-            const KeyedVector<String8, String8> *headers, int audioSessionId);
-
-    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId);
-
-    virtual sp<IMediaPlayer>    create(
-            pid_t pid, const sp<IMediaPlayerClient> &client,
-            const sp<IStreamSource> &source, int audioSessionId);
+    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId);
 
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
@@ -284,13 +275,13 @@
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
 
-                status_t        setDataSource(
+        virtual status_t        setDataSource(
                         const char *url,
                         const KeyedVector<String8, String8> *headers);
 
-                status_t        setDataSource(int fd, int64_t offset, int64_t length);
+        virtual status_t        setDataSource(int fd, int64_t offset, int64_t length);
 
-                status_t        setDataSource(const sp<IStreamSource> &source);
+        virtual status_t        setDataSource(const sp<IStreamSource> &source);
 
         static  void            notify(void* cookie, int msg,
                                        int ext1, int ext2, const Parcel *obj);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f98b0de..47224cc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -978,7 +978,7 @@
             CHECK(!mAudioPlayer->isSeeking());
 
             // We will have finished the seek while starting the audio player.
-            postAudioSeekComplete_l();
+            postAudioSeekComplete();
         }
     } else {
         mAudioPlayer->resume();
@@ -1877,7 +1877,8 @@
     mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll);
 }
 
-void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) {
+void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) {
+    Mutex::Autolock autoLock(mAudioLock);
     if (mAudioStatusEventPending) {
         return;
     }
@@ -1886,14 +1887,18 @@
 }
 
 void AwesomePlayer::onCheckAudioStatus() {
-    Mutex::Autolock autoLock(mLock);
-    if (!mAudioStatusEventPending) {
-        // Event was dispatched and while we were blocking on the mutex,
-        // has already been cancelled.
-        return;
+    {
+        Mutex::Autolock autoLock(mAudioLock);
+        if (!mAudioStatusEventPending) {
+            // Event was dispatched and while we were blocking on the mutex,
+            // has already been cancelled.
+            return;
+        }
+
+        mAudioStatusEventPending = false;
     }
 
-    mAudioStatusEventPending = false;
+    Mutex::Autolock autoLock(mLock);
 
     if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) {
         mWatchForAudioSeekComplete = false;
@@ -2239,17 +2244,11 @@
 }
 
 void AwesomePlayer::postAudioEOS(int64_t delayUs) {
-    Mutex::Autolock autoLock(mLock);
-    postCheckAudioStatusEvent_l(delayUs);
+    postCheckAudioStatusEvent(delayUs);
 }
 
 void AwesomePlayer::postAudioSeekComplete() {
-    Mutex::Autolock autoLock(mLock);
-    postAudioSeekComplete_l();
-}
-
-void AwesomePlayer::postAudioSeekComplete_l() {
-    postCheckAudioStatusEvent_l(0 /* delayUs */);
+    postCheckAudioStatusEvent(0);
 }
 
 status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index f2f3500..0794f57 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -110,6 +110,8 @@
 }
 
 status_t FileSource::getSize(off64_t *size) {
+    Mutex::Autolock autoLock(mLock);
+
     if (mFd < 0) {
         return NO_INIT;
     }
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 24cf77c..8e73121 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -148,6 +148,7 @@
     mutable Mutex mLock;
     Mutex mMiscStateLock;
     mutable Mutex mStatsLock;
+    Mutex mAudioLock;
 
     OMXClient mClient;
     TimedEventQueue mQueue;
@@ -223,7 +224,7 @@
     void postVideoEvent_l(int64_t delayUs = -1);
     void postBufferingEvent_l();
     void postStreamDoneEvent_l(status_t status);
-    void postCheckAudioStatusEvent_l(int64_t delayUs);
+    void postCheckAudioStatusEvent(int64_t delayUs);
     void postVideoLagEvent_l();
     status_t play_l();
 
@@ -295,7 +296,6 @@
     void ensureCacheIsFetching_l();
 
     status_t startAudioPlayer_l(bool sendErrorNotification = true);
-    void postAudioSeekComplete_l();
 
     void shutdownVideoDecoder_l();
     status_t setNativeWindow_l(const sp<ANativeWindow> &native);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 017d01c..e13464e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -89,7 +89,7 @@
     unsigned pid() const { return mElementaryPID; }
     void setPID(unsigned pid) { mElementaryPID = pid; }
 
-    void parse(
+    status_t parse(
             unsigned payload_unit_start_indicator,
             ABitReader *br);
 
@@ -114,8 +114,8 @@
 
     ElementaryStreamQueue *mQueue;
 
-    void flush();
-    void parsePES(ABitReader *br);
+    status_t flush();
+    status_t parsePES(ABitReader *br);
 
     void onPayloadData(
             unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
@@ -159,7 +159,7 @@
         return false;
     }
 
-    mStreams.editValueAt(index)->parse(
+    *err = mStreams.editValueAt(index)->parse(
             payload_unit_start_indicator, br);
 
     return true;
@@ -438,10 +438,10 @@
     mQueue = NULL;
 }
 
-void ATSParser::Stream::parse(
+status_t ATSParser::Stream::parse(
         unsigned payload_unit_start_indicator, ABitReader *br) {
     if (mQueue == NULL) {
-        return;
+        return OK;
     }
 
     if (payload_unit_start_indicator) {
@@ -450,14 +450,18 @@
             // of a PES packet that we never saw the start of and assuming
             // we have a a complete PES packet.
 
-            flush();
+            status_t err = flush();
+
+            if (err != OK) {
+                return err;
+            }
         }
 
         mPayloadStarted = true;
     }
 
     if (!mPayloadStarted) {
-        return;
+        return OK;
     }
 
     size_t payloadSizeBits = br->numBitsLeft();
@@ -478,6 +482,8 @@
 
     memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
     mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
+
+    return OK;
 }
 
 void ATSParser::Stream::signalDiscontinuity(
@@ -526,7 +532,7 @@
     }
 }
 
-void ATSParser::Stream::parsePES(ABitReader *br) {
+status_t ATSParser::Stream::parsePES(ABitReader *br) {
     unsigned packet_startcode_prefix = br->getBits(24);
 
     LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -534,7 +540,8 @@
     if (packet_startcode_prefix != 1) {
         LOGV("Supposedly payload_unit_start=1 unit does not start "
              "with startcode.");
-        return;
+
+        return ERROR_MALFORMED;
     }
 
     CHECK_EQ(packet_startcode_prefix, 0x000001u);
@@ -661,6 +668,14 @@
             unsigned dataLength =
                 PES_packet_length - 3 - PES_header_data_length;
 
+            if (br->numBitsLeft() < dataLength * 8) {
+                LOGE("PES packet does not carry enough data to contain "
+                     "payload. (numBitsLeft = %d, required = %d)",
+                     br->numBitsLeft(), dataLength * 8);
+
+                return ERROR_MALFORMED;
+            }
+
             CHECK_GE(br->numBitsLeft(), dataLength * 8);
 
             onPayloadData(
@@ -684,19 +699,24 @@
         CHECK_NE(PES_packet_length, 0u);
         br->skipBits(PES_packet_length * 8);
     }
+
+    return OK;
 }
 
-void ATSParser::Stream::flush() {
+status_t ATSParser::Stream::flush() {
     if (mBuffer->size() == 0) {
-        return;
+        return OK;
     }
 
     LOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size());
 
     ABitReader br(mBuffer->data(), mBuffer->size());
-    parsePES(&br);
+
+    status_t err = parsePES(&br);
 
     mBuffer->setRange(0, 0);
+
+    return err;
 }
 
 void ATSParser::Stream::onPayloadData(
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index ddad2d3..ca62908 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -95,12 +95,12 @@
         if (fgets(cmdline, sizeof(cmdline) - 1, file))
         {
             if (!strcmp(value, cmdline))
-                sEGLTraceLevel = 1;
+                gEGLDebugLevel = 1;
         }
         fclose(file);
     }
 
-    if (sEGLTraceLevel > 0)
+    if (gEGLDebugLevel > 0)
     {
         property_get("debug.egl.debug_port", value, "5039");
         const unsigned short port = (unsigned short)atoi(value);
@@ -117,7 +117,7 @@
     if (sEGLTraceLevel > 0) {
         setGlTraceThreadSpecific(value);
         setGlThreadSpecific(&gHooksTrace);
-    } else if (sEGLTraceLevel > 0 && value != &gHooksNoContext) {
+    } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
         setGlTraceThreadSpecific(value);
         setGlThreadSpecific(&gHooksDebug);
     } else {
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index ff9be3c..9e77665 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -88,7 +88,7 @@
     msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
     Send(msg, cmd);
 
-    *(DbgContext **)pthread_getspecific(dbgEGLThreadLocalStorageKey) = dbg;
+    pthread_setspecific(dbgEGLThreadLocalStorageKey, dbg);
     return dbg;
 }
 
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 87c7be6..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
index 4f4ae78..4362836 100644
--- a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png
new file mode 100644
index 0000000..335d5a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..1ad16f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 23aabce..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..6e806ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 0b0765b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png b/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
deleted file mode 100644
index 52354bd..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index ce01276..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png
deleted file mode 100644
index 1848fcd..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png
deleted file mode 100644
index 61a3f87..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png
deleted file mode 100644
index b6aca49..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 226aaac..0000000
--- a/packages/SystemUI/res/drawable-large-hdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png b/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
deleted file mode 100644
index 001811f..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 3d0fbf2..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4362836..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
deleted file mode 100644
index f4ccd7e..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 6392fa1..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index f6ee596..0000000
--- a/packages/SystemUI/res/drawable-large-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 87c7be6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
index 4f4ae78..4362836 100644
--- a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png
new file mode 100644
index 0000000..724a5cd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..82ba091
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 23aabce..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..7376085
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 0b0765b..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..4ac131a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png
index 4f4ae78..4362836 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png
deleted file mode 100644
index 5f4c035..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 87a67c9..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index a1c39e6..0000000
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png
new file mode 100644
index 0000000..59908ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_bg_protect_tile.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..3938502
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..e1e08c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png
new file mode 100644
index 0000000..1bd018a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_callout_line.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
new file mode 100644
index 0000000..0352aca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
new file mode 100644
index 0000000..507ee22
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/recents_thumbnail_bg_press.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png
deleted file mode 100644
index 52354bd..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png
deleted file mode 100644
index ce01276..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png
deleted file mode 100644
index 1848fcd..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png
deleted file mode 100644
index 846bc49..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png
deleted file mode 100644
index a983e12..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index 7c6e44e..0000000
--- a/packages/SystemUI/res/drawable-xlarge-hdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png b/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png
deleted file mode 100644
index 001811f..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/app_icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png
deleted file mode 100644
index 3d0fbf2..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_bg_protect_tile.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png
deleted file mode 100644
index 4362836..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_blue_glow.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png
deleted file mode 100644
index f4ccd7e..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_callout_line.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png
deleted file mode 100644
index 6392fa1..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png
deleted file mode 100644
index f6ee596..0000000
--- a/packages/SystemUI/res/drawable-xlarge-mdpi/recents_thumbnail_bg_press.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
index 200bac4..6d05095 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
@@ -15,5 +15,6 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+    <item android:drawable="@drawable/recents_thumbnail_bg" android:state_activated="true" />
     <item android:drawable="@*android:color/transparent"/>
 </selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 16008a3..e99888c 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -19,70 +19,74 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<RelativeLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_height="wrap_content"
-    android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+    android:layout_height="match_parent"
+    android:layout_width="wrap_content">
 
-    <FrameLayout android:id="@+id/app_thumbnail"
-        android:layout_width="wrap_content"
+    <RelativeLayout android:id="@+id/recent_item"
+        android:layout_gravity="bottom"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
-        android:scaleType="center"
-        android:clickable="true"
-        android:background="@drawable/recents_thumbnail_bg"
-        android:foreground="@drawable/recents_thumbnail_overlay">
-        <ImageView android:id="@+id/app_thumbnail_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:paddingBottom="@*android:dimen/status_bar_height">
+
+        <FrameLayout android:id="@+id/app_thumbnail"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentTop="true"
+            android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+            android:scaleType="center"
+            android:clickable="true"
+            android:background="@drawable/recents_thumbnail_overlay">
+            <ImageView android:id="@+id/app_thumbnail_image"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:visibility="invisible"
+            />
+        </FrameLayout>
+
+        <ImageView android:id="@+id/app_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignLeft="@id/app_thumbnail"
+            android:layout_alignTop="@id/app_thumbnail"
+            android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+            android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+            android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+            android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
+            android:adjustViewBounds="true"
             android:visibility="invisible"
         />
-    </FrameLayout>
 
-    <ImageView android:id="@+id/app_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignLeft="@id/app_thumbnail"
-        android:layout_alignTop="@id/app_thumbnail"
-        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-        android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
-        android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
-        android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
-        android:adjustViewBounds="true"
-        android:visibility="invisible"
-    />
+        <TextView android:id="@+id/app_label"
+            android:layout_width="@dimen/status_bar_recents_app_label_width"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/status_bar_recents_app_label_text_size"
+            android:fadingEdge="horizontal"
+            android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+            android:scrollHorizontally="true"
+            android:layout_alignLeft="@id/app_thumbnail"
+            android:layout_below="@id/app_thumbnail"
+            android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:visibility="invisible"
+        />
 
-    <TextView android:id="@+id/app_label"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_label_text_size"
-        android:fadingEdge="horizontal"
-        android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
-        android:scrollHorizontally="true"
-        android:layout_alignLeft="@id/app_thumbnail"
-        android:layout_below="@id/app_thumbnail"
-        android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
-        android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-        android:visibility="invisible"
-    />
+        <TextView android:id="@+id/app_description"
+            android:layout_width="@dimen/status_bar_recents_app_label_width"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/status_bar_recents_app_description_text_size"
+            android:fadingEdge="horizontal"
+            android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+            android:scrollHorizontally="true"
+            android:layout_alignLeft="@id/app_thumbnail"
+            android:layout_below="@id/app_label"
+            android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+        />
 
-    <TextView android:id="@+id/app_description"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_description_text_size"
-        android:fadingEdge="horizontal"
-        android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
-        android:scrollHorizontally="true"
-        android:layout_alignLeft="@id/app_thumbnail"
-        android:layout_below="@id/app_label"
-        android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
-        android:layout_marginLeft="@dimen/recents_thumbnail_bg_padding_left"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-    />
-
-</RelativeLayout>
+    </RelativeLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index 20ef7cf..f84cc19 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -30,13 +30,12 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_alignParentBottom="true"
-        android:paddingBottom="@*android:dimen/status_bar_height"
         android:clipToPadding="false"
         android:clipChildren="false">
 
         <LinearLayout android:id="@+id/recents_glow"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="match_parent"
             android:layout_gravity="bottom|right"
             android:orientation="horizontal"
             android:clipToPadding="false"
@@ -44,7 +43,7 @@
             >
             <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="match_parent"
                 android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
                 android:divider="@null"
                 android:stackFromBottom="true"
@@ -58,7 +57,7 @@
 
                 <LinearLayout android:id="@+id/recents_linear_layout"
                     android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
+                    android:layout_height="match_parent"
                     android:orientation="horizontal"
                     android:clipToPadding="false"
                     android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index c0fce71..73ca335 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -19,79 +19,83 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<RelativeLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+    android:layout_width="match_parent">
 
-    <FrameLayout android:id="@+id/app_thumbnail"
-        android:layout_width="wrap_content"
+    <RelativeLayout android:id="@+id/recent_item"
         android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:clickable="true"
-        android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
-        android:scaleType="center"
-        android:background="@drawable/recents_thumbnail_bg"
-        android:foreground="@drawable/recents_thumbnail_overlay">
-        <ImageView android:id="@+id/app_thumbnail_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:visibility="invisible"
+        android:layout_width="match_parent">
+
+        <FrameLayout android:id="@+id/app_thumbnail"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentTop="true"
+            android:clickable="true"
+            android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+            android:scaleType="center"
+            android:background="@drawable/recents_thumbnail_overlay">
+            <ImageView android:id="@+id/app_thumbnail_image"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:visibility="invisible"
+            />
+        </FrameLayout>
+
+        <ImageView android:id="@+id/app_icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignLeft="@id/app_thumbnail"
+            android:layout_alignTop="@id/app_thumbnail"
+            android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
+            android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
+            android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+            android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
+            android:adjustViewBounds="true"
         />
-    </FrameLayout>
 
-    <ImageView android:id="@+id/app_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignLeft="@id/app_thumbnail"
-        android:layout_alignTop="@id/app_thumbnail"
-        android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
-        android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-        android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
-        android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
-        android:adjustViewBounds="true"
-    />
+        <TextView android:id="@+id/app_label"
+            android:layout_width="@dimen/status_bar_recents_app_label_width"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/status_bar_recents_app_label_text_size"
+            android:fadingEdge="horizontal"
+            android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+            android:scrollHorizontally="true"
+            android:layout_alignParentLeft="true"
+            android:layout_alignTop="@id/app_icon"
+            android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+        />
 
-    <TextView android:id="@+id/app_label"
-        android:layout_width="@dimen/status_bar_recents_app_label_width"
-        android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_label_text_size"
-        android:fadingEdge="horizontal"
-        android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
-        android:scrollHorizontally="true"
-        android:layout_alignParentLeft="true"
-        android:layout_alignTop="@id/app_icon"
-        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-    />
+        <View android:id="@+id/recents_callout_line"
+            android:layout_width="@dimen/status_bar_recents_app_label_width"
+            android:layout_height="1dip"
+            android:layout_alignParentLeft="true"
+            android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+            android:layout_toLeftOf="@id/app_thumbnail"
+            android:layout_below="@id/app_label"
+            android:layout_marginRight="3dip"
+            android:layout_marginTop="3dip"
+            android:background="@drawable/recents_callout_line"
+        />
 
-    <View android:id="@+id/recents_callout_line"
-        android:layout_width="@dimen/status_bar_recents_app_label_width"
-        android:layout_height="1dip"
-        android:layout_alignParentLeft="true"
-        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
-        android:layout_toLeftOf="@id/app_thumbnail"
-        android:layout_below="@id/app_label"
-        android:layout_marginRight="3dip"
-        android:layout_marginTop="3dip"
-        android:background="@drawable/recents_callout_line"
-    />
+        <TextView android:id="@+id/app_description"
+            android:layout_width="@dimen/status_bar_recents_app_label_width"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/status_bar_recents_app_description_text_size"
+            android:fadingEdge="horizontal"
+            android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+            android:scrollHorizontally="true"
+            android:layout_alignParentLeft="true"
+            android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
+            android:layout_below="@id/recents_callout_line"
+            android:layout_marginTop="3dip"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+        />
 
-    <TextView android:id="@+id/app_description"
-        android:layout_width="@dimen/status_bar_recents_app_label_width"
-        android:layout_height="wrap_content"
-        android:textSize="@dimen/status_bar_recents_app_description_text_size"
-        android:fadingEdge="horizontal"
-        android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
-        android:scrollHorizontally="true"
-        android:layout_alignParentLeft="true"
-        android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
-        android:layout_below="@id/recents_callout_line"
-        android:layout_marginTop="3dip"
-        android:singleLine="true"
-        android:ellipsize="marquee"
-    />
-
-</RelativeLayout>
+    </RelativeLayout>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index c680b8e..dd25cf9 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -40,7 +40,7 @@
             android:layout_marginTop="@*android:dimen/status_bar_height">
             <com.android.systemui.recent.RecentsVerticalScrollView
                 android:id="@+id/recents_container"
-                android:layout_width="@dimen/status_bar_recents_width"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="0dp"
                 android:divider="@null"
@@ -53,7 +53,7 @@
                 android:clipChildren="false">
 
                 <LinearLayout android:id="@+id/recents_linear_layout"
-                    android:layout_width="wrap_content"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
                     android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 5306508..cab90fd 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -19,21 +19,20 @@
 -->
 
 <!--    android:background="@drawable/status_bar_closed_default_background" -->
-<RelativeLayout
+<RelativeLayout android:id="@+id/recent_item"
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+    android:layout_width="wrap_content">
 
     <FrameLayout android:id="@+id/app_thumbnail"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
+        android:clickable="true"
         android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
         android:scaleType="center"
-        android:clickable="true"
-        android:background="@drawable/recents_thumbnail_bg"
-        android:foreground="@drawable/recents_thumbnail_overlay">
+        android:background="@drawable/recents_thumbnail_overlay">
         <ImageView android:id="@+id/app_thumbnail_image"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
@@ -48,8 +47,8 @@
         android:layout_alignTop="@id/app_thumbnail"
         android:layout_marginLeft="@dimen/status_bar_recents_app_icon_left_margin"
         android:layout_marginTop="@dimen/status_bar_recents_app_icon_top_margin"
-        android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
-        android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
+        android:maxWidth="@dimen/status_bar_recents_app_icon_max_width"
+        android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
         android:adjustViewBounds="true"
     />
 
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 2c9a152..4ef602e 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -47,7 +47,7 @@
             android:clipChildren="false"
             >
             <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
-                android:layout_width="@dimen/status_bar_recents_width"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
                 android:divider="@null"
diff --git a/packages/SystemUI/res/values-hdpi/dimens.xml b/packages/SystemUI/res/values-hdpi/dimens.xml
index 287e0d1..6b6fd4d 100644
--- a/packages/SystemUI/res/values-hdpi/dimens.xml
+++ b/packages/SystemUI/res/values-hdpi/dimens.xml
@@ -16,12 +16,6 @@
 */
 -->
 <resources>
-    <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
-    <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
-
     <!-- thickness (height) of each notification row, including any separators or padding -->
     <!-- Note: this is 64dip + 1px divider = 97px. -->
     <dimen name="notification_height">97px</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 3919685..ca74b8b 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -20,18 +20,14 @@
     <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen>
 
     <!-- Recent Applications parameters -->
-    <!-- Width of a recent app view, including all content -->
-    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
     <!-- How far the thumbnail for a recent app appears from left edge -->
     <dimen name="status_bar_recents_thumbnail_left_margin">8dp</dimen>
     <!-- How far the thumbnail for a recent app appears from top edge -->
     <dimen name="status_bar_recents_thumbnail_top_margin">12dp</dimen>
-    <!-- Width of scrollable area in recents -->
-    <dimen name="status_bar_recents_width">128dp</dimen>
     <!-- Padding for text descriptions -->
     <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
     <!-- Width of application label text -->
-    <dimen name="status_bar_recents_app_label_width">97dip</dimen>
+    <dimen name="status_bar_recents_app_label_width">156dip</dimen>
     <!-- Left margin of application label text -->
     <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
     <!-- Margin between recents container and glow on the right -->
diff --git a/packages/SystemUI/res/values-mdpi/dimens.xml b/packages/SystemUI/res/values-mdpi/dimens.xml
deleted file mode 100644
index 741b75a..0000000
--- a/packages/SystemUI/res/values-mdpi/dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2011, 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.
-*/
--->
-<resources>
-    <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
-    <dimen name="recents_thumbnail_bg_padding_left">6px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_top">7px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_right">6px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_bottom">6px</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-port/dimens.xml b/packages/SystemUI/res/values-port/dimens.xml
index 54c25fa..b89a610 100644
--- a/packages/SystemUI/res/values-port/dimens.xml
+++ b/packages/SystemUI/res/values-port/dimens.xml
@@ -17,18 +17,14 @@
 -->
 <resources>
     <!-- Recent Applications parameters -->
-    <!-- Width of a recent app view, including all content -->
-    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
     <!-- How far the thumbnail for a recent app appears from left edge -->
     <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
-    <!-- Width of scrollable area in recents -->
-    <dimen name="status_bar_recents_width">356dp</dimen>
     <!-- Padding for text descriptions -->
     <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
     <!-- Width of application label text -->
     <dimen name="status_bar_recents_app_label_width">97dip</dimen>
     <!-- Left margin of application label text -->
-    <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
+    <dimen name="status_bar_recents_app_label_left_margin">8dip</dimen>
     <!-- Margin between recents container and glow on the right -->
     <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
new file mode 100644
index 0000000..3e2ec59
--- /dev/null
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, 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.
+*/
+-->
+
+<resources>
+
+    <!-- Whether we're using the tablet-optimized recents interface (we use this
+     value at runtime for some things) -->
+    <bool name="config_recents_interface_for_tablets">true</bool>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index a5bea5c..fe9245d 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -30,16 +30,19 @@
     <dimen name="panel_float">56dp</dimen>
 
     <!-- Recent Applications parameters -->
-    <!-- Width of a recent app view, including all content -->
-    <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
     <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_left_margin">121dp</dimen>
     <!-- Upper width limit for application icon -->
-    <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+    <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
     <!-- Upper height limit for application icon -->
-    <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
-    <!-- Width of scrollable area in recents -->
-    <dimen name="status_bar_recents_width">356dp</dimen>
+    <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
+
+    <!-- Size of application icon -->
+    <dimen name="status_bar_recents_thumbnail_width">245dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_height">144dp</dimen>
+
+    <!-- Width of recents panel -->
+    <dimen name="status_bar_recents_width">600dp</dimen>
     <!-- Padding for text descriptions -->
     <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
     <!-- Size of application label text -->
@@ -55,12 +58,6 @@
     <!-- Margin between recents container and glow on the right -->
     <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
 
-    <!-- Offsets for rendering thumbnails over drawable recents_thumbnail_bg -->
-    <dimen name="recents_thumbnail_bg_padding_left">15px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_top">8px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_right">12px</dimen>
-    <dimen name="recents_thumbnail_bg_padding_bottom">8px</dimen>
-
     <!-- Where to place the app icon over the thumbnail -->
     <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
     <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5d14fa8..4c222f9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -22,5 +22,6 @@
     <drawable name="ticker_background_color">#ff1d1d1d</drawable>
     <drawable name="status_bar_background">#ff000000</drawable>
     <drawable name="status_bar_recents_background">#b3000000</drawable>
+    <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
     <drawable name="status_bar_notification_row_background_color">#ff000000</drawable>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d7d7817..4ac89b2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -21,6 +21,10 @@
      for different hardware and product builds. -->
 <resources>
 
+    <!-- Whether we're using the tablet-optimized recents interface (we use this
+     value at runtime for some things) -->
+    <bool name="config_recents_interface_for_tablets">false</bool>
+
     <!-- Control whether status bar should distinguish HSPA data icon form UMTS
     data icon on devices -->
     <bool name="config_hspa_data_distinguishable">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f633825c..d0ece6c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -21,17 +21,21 @@
 
     <!-- Recent Applications parameters -->
     <!-- Upper width limit for application icon -->
-    <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+    <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
     <!-- Upper height limit for application icon -->
-    <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
+    <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
     <!-- Where to place the app icon over the thumbnail -->
     <dimen name="status_bar_recents_app_icon_left_margin">13dp</dimen>
     <dimen name="status_bar_recents_app_icon_top_margin">13dp</dimen>
 
+    <!-- Size of application thumbnail -->
+    <dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
+    <dimen name="status_bar_recents_thumbnail_height">164dp</dimen>
+
     <!-- Size of application label text -->
-    <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+    <dimen name="status_bar_recents_app_label_text_size">16dip</dimen>
     <!-- Size of application description text -->
-    <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+    <dimen name="status_bar_recents_app_description_text_size">16dip</dimen>
     <!-- Size of fading edge for scroll effect -->
     <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
     <!-- Margin between recents container and glow on the right -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7779703..bad7e1f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -36,10 +36,10 @@
     <string name="status_bar_please_disturb_button">Show notifications</string>
 
     <!-- Title shown in recents popup for removing an application from the list -->
-    <string name="status_bar_recent_remove_item_title">Remove</string>
+    <string name="status_bar_recent_remove_item_title">Remove from list</string>
 
     <!-- Title shown in recents popup for inspecting an application's properties -->
-    <string name="status_bar_recent_inspect_item_title">Inspect</string>
+    <string name="status_bar_recent_inspect_item_title">App info</string>
 
     <!-- The label in the bar at the top of the status bar when there are no notifications
          showing.  [CHAR LIMIT=40]-->
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index e7ed052..14743f4 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -33,20 +33,19 @@
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_INVALIDATE = false;
     private static final boolean SLOW_ANIMATIONS = false; // DEBUG;
+    private static final boolean CONSTRAIN_SWIPE = true;
+    private static final boolean FADE_OUT_DURING_SWIPE = true;
+    private static final boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
 
     public static final int X = 0;
     public static final int Y = 1;
 
-    private boolean CONSTRAIN_SWIPE = true;
-    private boolean FADE_OUT_DURING_SWIPE = true;
-    private boolean DISMISS_IF_SWIPED_FAR_ENOUGH = true;
-
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
     private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms
     private int MAX_DISMISS_VELOCITY = 1000; // dp/sec
     private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
 
-    public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width
+    public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
                                                  // where fade starts
     static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width
                                               // beyond which alpha->0
@@ -59,6 +58,8 @@
     private float mInitialTouchPos;
     private boolean mDragging;
     private View mCurrView;
+    private View mCurrAnimView;
+    private boolean mCanCurrViewBeDimissed;
     private float mDensityScale;
 
     public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
@@ -82,8 +83,8 @@
         return mSwipeDirection == X ? ev.getX() : ev.getY();
     }
 
-    private float getPos(View v) {
-        return mSwipeDirection == X ? v.getX() : v.getY();
+    private float getTranslation(View v) {
+        return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
     }
 
     private float getVelocity(VelocityTracker vt) {
@@ -115,19 +116,15 @@
                 v.getMeasuredHeight();
     }
 
-    private float getContentSize(View v) {
-        View content = mCallback.getChildContentView(v);
-        return getSize(content);
-    }
-
-    private float getAlphaForOffset(View view, float thumbSize) {
-        final float fadeSize = ALPHA_FADE_END * thumbSize;
+    private float getAlphaForOffset(View view) {
+        float viewSize = getSize(view);
+        final float fadeSize = ALPHA_FADE_END * viewSize;
         float result = 1.0f;
-        float pos = getPos(view);
-        if (pos >= thumbSize * ALPHA_FADE_START) {
-            result = 1.0f - (pos - thumbSize * ALPHA_FADE_START) / fadeSize;
-        } else if (pos < thumbSize * (1.0f - ALPHA_FADE_START)) {
-            result = 1.0f + (thumbSize * ALPHA_FADE_START + pos) / fadeSize;
+        float pos = getTranslation(view);
+        if (pos >= viewSize * ALPHA_FADE_START) {
+            result = 1.0f - (pos - viewSize * ALPHA_FADE_START) / fadeSize;
+        } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
+            result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
         }
         return result;
     }
@@ -168,6 +165,8 @@
             case MotionEvent.ACTION_DOWN:
                 mDragging = false;
                 mCurrView = mCallback.getChildAtPosition(ev);
+                mCurrAnimView = mCallback.getChildContentView(mCurrView);
+                mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
                 mVelocityTracker.clear();
                 mVelocityTracker.addMovement(ev);
                 mInitialTouchPos = getPos(ev);
@@ -180,21 +179,24 @@
                     if (Math.abs(delta) > mPagingTouchSlop) {
                         mCallback.onBeginDrag(mCurrView);
                         mDragging = true;
-                        mInitialTouchPos = getPos(ev) - getPos(mCurrView);
+                        mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
                     }
                 }
                 break;
             case MotionEvent.ACTION_UP:
                 mDragging = false;
                 mCurrView = null;
+                mCurrAnimView = null;
                 break;
         }
         return mDragging;
     }
 
-    public void dismissChild(final View animView, float velocity) {
+    public void dismissChild(final View view, float velocity) {
+        final View animView = mCallback.getChildContentView(view);
+        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
         float newPos;
-        if (velocity < 0 || (velocity == 0 && getPos(animView) < 0)) {
+        if (velocity < 0 || (velocity == 0 && getTranslation(animView) < 0)) {
             newPos = -getSize(animView);
         } else {
             newPos = getSize(animView);
@@ -202,7 +204,7 @@
         int duration = MAX_ESCAPE_ANIMATION_DURATION;
         if (velocity != 0) {
             duration = Math.min(duration,
-                                (int) (Math.abs(newPos - getPos(animView)) * 1000f / Math
+                                (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
                                         .abs(velocity)));
         }
         ObjectAnimator anim = createTranslationAnimation(animView, newPos);
@@ -216,17 +218,17 @@
             }
 
             public void onAnimationEnd(Animator animation) {
-                mCallback.onChildDismissed(animView);
+                mCallback.onChildDismissed(view);
             }
 
             public void onAnimationCancel(Animator animation) {
-                mCallback.onChildDismissed(animView);
+                mCallback.onChildDismissed(view);
             }
         });
         anim.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
-                if (FADE_OUT_DURING_SWIPE) {
-                    animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView)));
+                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
+                    animView.setAlpha(getAlphaForOffset(animView));
                 }
                 invalidateGlobalRegion(animView);
             }
@@ -234,14 +236,16 @@
         anim.start();
     }
 
-    public void snapChild(final View animView, float velocity) {
+    public void snapChild(final View view, float velocity) {
+        final View animView = mCallback.getChildContentView(view);
+        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
         ObjectAnimator anim = createTranslationAnimation(animView, 0);
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             public void onAnimationUpdate(ValueAnimator animation) {
-                if (FADE_OUT_DURING_SWIPE) {
-                    animView.setAlpha(getAlphaForOffset(animView, getContentSize(animView)));
+                if (FADE_OUT_DURING_SWIPE && canAnimViewBeDismissed) {
+                    animView.setAlpha(getAlphaForOffset(animView));
                 }
                 invalidateGlobalRegion(animView);
             }
@@ -264,7 +268,7 @@
                     // don't let items that can't be dismissed be dragged more than
                     // maxScrollDistance
                     if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
-                        float size = getSize(mCurrView);
+                        float size = getSize(mCurrAnimView);
                         float maxScrollDistance = 0.15f * size;
                         if (Math.abs(delta) >= size) {
                             delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
@@ -272,9 +276,9 @@
                             delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
                         }
                     }
-                    setTranslation(mCurrView, delta);
-                    if (FADE_OUT_DURING_SWIPE) {
-                        mCurrView.setAlpha(getAlphaForOffset(mCurrView, getContentSize(mCurrView)));
+                    setTranslation(mCurrAnimView, delta);
+                    if (FADE_OUT_DURING_SWIPE && mCanCurrViewBeDimissed) {
+                        mCurrAnimView.setAlpha(getAlphaForOffset(mCurrAnimView));
                     }
                     invalidateGlobalRegion(mCurrView);
                 }
@@ -290,10 +294,10 @@
 
                     // Decide whether to dismiss the current view
                     boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
-                            Math.abs(getPos(mCurrView)) > 0.4 * getSize(mCurrView);
+                            Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
                     boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
                             (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
-                            (velocity > 0) == (getPos(mCurrView) > 0);
+                            (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
 
                     boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) &&
                             (childSwipedFastEnough || childSwipedFarEnough);
@@ -303,6 +307,7 @@
                         dismissChild(mCurrView, childSwipedFastEnough ? velocity : 0f);
                     } else {
                         // snappity
+                        mCallback.onDragCancelled(mCurrView);
                         snapChild(mCurrView, velocity);
                     }
                 }
@@ -321,5 +326,7 @@
         void onBeginDrag(View v);
 
         void onChildDismissed(View v);
+
+        void onDragCancelled(View v);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 5609ead..2de4185 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -27,4 +27,8 @@
     void handleOnClick(View selectedView);
     void handleSwipe(View selectedView);
     void handleLongPress(View selectedView, View anchorView);
+    void handleShowBackground(boolean show);
+
+    // TODO: find another way to get this info from RecentsPanelView
+    boolean isRecentsVisible();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 8da2db6..85cde7c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
+import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -41,6 +42,8 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
+    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+
     private OnLongClickListener mOnLongClick = new OnLongClickListener() {
         public boolean onLongClick(View v) {
             final View anchorView = v.findViewById(R.id.app_description);
@@ -49,15 +52,12 @@
         }
     };
 
-    public RecentsHorizontalScrollView(Context context) {
-        this(context, null);
-    }
-
     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);
     }
 
     private int scrollPositionOfMostRecent() {
@@ -71,7 +71,11 @@
             view.setLongClickable(true);
             view.setOnLongClickListener(mOnLongClick);
 
-            final View thumbnail = getChildContentView(view);
+            if (mPerformanceHelper != null) {
+                mPerformanceHelper.addViewCallback(view);
+            }
+
+            final View thumbnail = view.findViewById(R.id.app_thumbnail);
             // thumbnail is set to clickable in the layout file
             thumbnail.setOnClickListener(new OnClickListener() {
                 public void onClick(View v) {
@@ -123,6 +127,11 @@
         // We do this so the underlying ScrollView knows that it won't get
         // the chance to intercept events anymore
         requestDisallowInterceptTouchEvent(true);
+        v.setActivated(true);
+    }
+
+    public void onDragCancelled(View v) {
+        v.setActivated(false);
     }
 
     public View getChildAtPosition(MotionEvent ev) {
@@ -139,7 +148,60 @@
     }
 
     public View getChildContentView(View v) {
-        return v.findViewById(R.id.app_thumbnail);
+        return v.findViewById(R.id.recent_item);
+    }
+
+    @Override
+    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.onLayoutCallback();
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        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,
+                    left, right, top, bottom, mScrollX, mScrollY,
+                    0, 0,
+                    getLeftFadingEdgeStrength(), getRightFadingEdgeStrength());
+        }
+    }
+
+    @Override
+    public int getVerticalFadingEdgeLength() {
+        if (mPerformanceHelper != null) {
+            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        } else {
+            return super.getVerticalFadingEdgeLength();
+        }
+    }
+
+    @Override
+    public int getHorizontalFadingEdgeLength() {
+        if (mPerformanceHelper != null) {
+            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        } else {
+            return super.getHorizontalFadingEdgeLength();
+        }
     }
 
     @Override
@@ -153,6 +215,14 @@
     }
 
     @Override
+    public void onAttachedToWindow() {
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.onAttachedToWindowCallback(
+                    mCallback, mLinearLayout, isHardwareAccelerated());
+        }
+    }
+
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         float densityScale = getResources().getDisplayMetrics().density;
@@ -192,6 +262,12 @@
         });
     }
 
+    public void onRecentsVisibilityChanged() {
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.updateShowBackground();
+        }
+    }
+
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -220,6 +296,9 @@
 
     @Override
     public void setLayoutTransition(LayoutTransition transition) {
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.setLayoutTransitionCallback(transition);
+        }
         // The layout transition applies to our embedded LinearLayout
         mLinearLayout.setLayoutTransition(transition);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
deleted file mode 100644
index d8b086b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2011 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.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ListView;
-
-import com.android.systemui.R;
-
-public class RecentsListView extends ListView {
-    private int mLastVisiblePosition;
-    private RecentsCallback mCallback;
-
-    public RecentsListView(Context context) {
-        this(context, null);
-    }
-
-    public RecentsListView(Context context, AttributeSet attrs) {
-        super(context, attrs, 0);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        LayoutInflater inflater = (LayoutInflater)
-                mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
-        View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, this, false);
-        setScrollbarFadingEnabled(true);
-        addFooterView(footer, null, false);
-        final int leftPadding = mContext.getResources()
-            .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
-        setOverScrollEffectPadding(leftPadding, 0);
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        // Keep track of the last visible item in the list so we can restore it
-        // to the bottom when the orientation changes.
-        final int childCount = getChildCount();
-        if (childCount > 0) {
-            mLastVisiblePosition = getFirstVisiblePosition() + childCount - 1;
-            View view = getChildAt(childCount - 1);
-            final int distanceFromBottom = getHeight() - view.getTop();
-
-            // This has to happen post-layout, so run it "in the future"
-            post(new Runnable() {
-                public void run() {
-                    setSelectionFromTop(mLastVisiblePosition, getHeight() - distanceFromBottom);
-                }
-            });
-        }
-    }
-
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-        // scroll to bottom after reloading
-        int count = getAdapter().getCount();
-        mLastVisiblePosition = count - 1;
-        if (visibility == View.VISIBLE && changedView == this) {
-            post(new Runnable() {
-                public void run() {
-                    setSelection(mLastVisiblePosition);
-                }
-            });
-        }
-    }
-
-    public void setCallback(RecentsCallback callback) {
-        mCallback = callback;
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 9cc2c29..e59c109 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -56,7 +56,6 @@
 import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
 import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
 import android.widget.BaseAdapter;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
@@ -64,6 +63,7 @@
 import android.widget.RelativeLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.StatusBar;
@@ -73,7 +73,7 @@
 
 public class RecentsPanelView extends RelativeLayout
         implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener {
-    static final String TAG = "RecentsListView";
+    static final String TAG = "RecentsPanelView";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
     private static final int DISPLAY_TASKS = 20;
     private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
@@ -84,12 +84,8 @@
     private View mRecentsScrim;
     private View mRecentsGlowView;
     private ViewGroup mRecentsContainer;
-    private Bitmap mGlowBitmap;
-    // TODO: add these widgets attributes to the layout file
-    private int mGlowBitmapPaddingLeftPx;
-    private int mGlowBitmapPaddingTopPx;
-    private int mGlowBitmapPaddingRightPx;
-    private int mGlowBitmapPaddingBottomPx;
+    private Bitmap mAppThumbnailBackground;
+
     private boolean mShowing;
     private Choreographer mChoreo;
     private View mRecentsDismissButton;
@@ -129,7 +125,7 @@
         }
 
         public void setThumbnail(Bitmap thumbnail) {
-            mThumbnail = compositeBitmap(mGlowBitmap, thumbnail);
+            mThumbnail = compositeBitmap(mAppThumbnailBackground, thumbnail);
         }
 
         public Bitmap getThumbnail() {
@@ -178,7 +174,7 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             ViewHolder holder;
             if (convertView == null) {
-                convertView = mInflater.inflate(R.layout.status_bar_recent_item, null);
+                convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
                 holder = new ViewHolder();
                 holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
                 holder.thumbnailViewImage = (ImageView) convertView.findViewById(
@@ -247,6 +243,28 @@
         }
     }
 
+    public void hide(boolean animate) {
+        mShowing = false;
+        if (!animate) {
+            setVisibility(View.GONE);
+        }
+        if (mBar != null) {
+            mBar.animateCollapse();
+        }
+    }
+
+    public void handleShowBackground(boolean show) {
+        if (show) {
+            mRecentsScrim.setBackgroundResource(R.drawable.status_bar_recents_background);
+        } else {
+            mRecentsScrim.setBackgroundDrawable(null);
+        }
+    }
+
+    public boolean isRecentsVisible() {
+        return getVisibility() == VISIBLE;
+    }
+
     public void onAnimationCancel(Animator animation) {
     }
 
@@ -315,15 +333,12 @@
 
         mIconDpi = xlarge ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
 
-        mGlowBitmap = BitmapFactory.decodeResource(res, R.drawable.recents_thumbnail_bg);
-        mGlowBitmapPaddingLeftPx =
-                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_left);
-        mGlowBitmapPaddingTopPx =
-                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_top);
-        mGlowBitmapPaddingRightPx =
-                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_right);
-        mGlowBitmapPaddingBottomPx =
-                res.getDimensionPixelSize(R.dimen.recents_thumbnail_bg_padding_bottom);
+        int width = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_width);
+        int height = (int) res.getDimension(R.dimen.status_bar_recents_thumbnail_height);
+        int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
+        mAppThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(mAppThumbnailBackground);
+        c.drawColor(color);
     }
 
     @Override
@@ -332,12 +347,7 @@
         mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
         mListAdapter = new ActivityDescriptionAdapter(mContext);
-        if (mRecentsContainer instanceof RecentsListView) {
-            RecentsListView listView = (RecentsListView) mRecentsContainer;
-            listView.setAdapter(mListAdapter);
-            listView.setOnItemClickListener(this);
-            listView.setCallback(this);
-        } else if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+        if (mRecentsContainer instanceof RecentsHorizontalScrollView){
             RecentsHorizontalScrollView scrollView
                     = (RecentsHorizontalScrollView) mRecentsContainer;
             scrollView.setAdapter(mListAdapter);
@@ -349,7 +359,7 @@
             scrollView.setCallback(this);
         }
         else {
-            throw new IllegalArgumentException("missing RecentsListView/RecentsScrollView");
+            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
         }
 
 
@@ -382,6 +392,14 @@
         if (visibility == View.VISIBLE && changedView == this) {
             refreshApplicationList();
         }
+
+        if (mRecentsContainer instanceof RecentsHorizontalScrollView) {
+            ((RecentsHorizontalScrollView) mRecentsContainer).onRecentsVisibilityChanged();
+        } else if (mRecentsContainer instanceof RecentsVerticalScrollView) {
+            ((RecentsVerticalScrollView) mRecentsContainer).onRecentsVisibilityChanged();
+        } else {
+            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
+        }
     }
 
     Drawable getFullResDefaultActivityIcon() {
@@ -555,6 +573,9 @@
             mThumbnailLoader = null;
         }
         mActivityDescriptions = getRecentTasks();
+        for (ActivityDescription ad : mActivityDescriptions) {
+            ad.setThumbnail(mAppThumbnailBackground);
+        }
         mListAdapter.notifyDataSetInvalidated();
         if (mActivityDescriptions.size() > 0) {
             if (DEBUG) Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
@@ -629,14 +650,8 @@
             paint.setAntiAlias(true);
             paint.setFilterBitmap(true);
             paint.setAlpha(255);
-            final int srcWidth = thumbnail.getWidth();
-            final int srcHeight = thumbnail.getHeight();
-            if (DEBUG) Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
-            canvas.drawBitmap(thumbnail,
-                    new Rect(0, 0, srcWidth-1, srcHeight-1),
-                    new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
-                            outBitmap.getWidth() - mGlowBitmapPaddingRightPx,
-                            outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint);
+            canvas.drawBitmap(thumbnail, null,
+                    new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
             canvas.setBitmap(null);
         }
         return outBitmap;
@@ -649,15 +664,6 @@
         mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
     }
 
-    public void hide(boolean animate) {
-        if (!animate) {
-            setVisibility(View.GONE);
-        }
-        if (mBar != null) {
-            mBar.animateCollapse();
-        }
-    }
-
     public void handleOnClick(View view) {
         ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
         final Context context = view.getContext();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
new file mode 100644
index 0000000..b7e656e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2011 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.animation.LayoutTransition;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+public class RecentsScrollViewPerformanceHelper {
+    public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
+    public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
+    private View mScrollView;
+    private LinearLayout mLinearLayout;
+    private RecentsCallback mCallback;
+
+    private boolean mShowBackground = false;
+    private int mFadingEdgeLength;
+    private Drawable.ConstantState mBackgroundDrawable;
+    private Context mContext;
+    private boolean mIsVertical;
+    private boolean mFirstTime = true;
+    private boolean mSoftwareRendered = false;
+    private boolean mAttachedToWindow = false;
+
+    public static RecentsScrollViewPerformanceHelper 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);
+        } else {
+            return null;
+        }
+    }
+
+    public RecentsScrollViewPerformanceHelper(Context context,
+            AttributeSet attrs, View scrollView, boolean isVertical) {
+        mScrollView = scrollView;
+        mContext = context;
+        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
+        mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
+                ViewConfiguration.get(context).getScaledFadingEdgeLength());
+        mIsVertical = isVertical;
+    }
+
+    public void onAttachedToWindowCallback(
+            RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
+        mSoftwareRendered = !hardwareAccelerated;
+        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
+                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
+            mScrollView.setVerticalFadingEdgeEnabled(false);
+            mScrollView.setHorizontalFadingEdgeEnabled(false);
+        }
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            mCallback = callback;
+            mLinearLayout = layout;
+            mAttachedToWindow = true;
+            mBackgroundDrawable = mContext.getResources()
+                .getDrawable(R.drawable.status_bar_recents_background).getConstantState();
+            updateShowBackground();
+        }
+
+    }
+
+    public void addViewCallback(View newLinearLayoutChild) {
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            final View view = newLinearLayoutChild;
+            if (mShowBackground) {
+                view.setBackgroundDrawable(mBackgroundDrawable.newDrawable());
+                view.setDrawingCacheEnabled(true);
+                view.buildDrawingCache();
+            } else {
+                view.setBackgroundDrawable(null);
+                view.setDrawingCacheEnabled(false);
+                view.destroyDrawingCache();
+            }
+        }
+    }
+
+    public void onLayoutCallback() {
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            mScrollView.post(new Runnable() {
+                public void run() {
+                    updateShowBackground();
+                }
+            });
+        }
+    }
+
+    public void drawCallback(Canvas canvas,
+            int left, int right, int top, int bottom, int scrollX, int scrollY,
+            float topFadingEdgeStrength, float bottomFadingEdgeStrength,
+            float leftFadingEdgeStrength, float rightFadingEdgeStrength) {
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            if (mIsVertical) {
+                if (scrollY < 0) {
+                    Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+                    d.setBounds(0, scrollY, mScrollView.getWidth(), 0);
+                    d.draw(canvas);
+                } else {
+                    final int childHeight = mLinearLayout.getHeight();
+                    if (scrollY + mScrollView.getHeight() > childHeight) {
+                        Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+                        d.setBounds(0, childHeight, mScrollView.getWidth(),
+                                scrollY + mScrollView.getHeight());
+                        d.draw(canvas);
+                    }
+                }
+            } else {
+                if (scrollX < 0) {
+                    Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+                    d.setBounds(scrollX, 0, 0, mScrollView.getHeight());
+                    d.draw(canvas);
+                } else {
+                    final int childWidth = mLinearLayout.getWidth();
+                    if (scrollX + mScrollView.getWidth() > childWidth) {
+                        Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
+                        d.setBounds(childWidth, 0,
+                                scrollX + mScrollView.getWidth(), mScrollView.getHeight());
+                        d.draw(canvas);
+                    }
+                }
+            }
+        }
+
+        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
+                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
+            Paint p = new Paint();
+            Matrix matrix = new Matrix();
+            // use use a height of 1, and then wack the matrix each time we
+            // actually use it.
+            Shader fade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
+            // PULL OUT THIS CONSTANT
+
+            p.setShader(fade);
+
+            // draw the fade effect
+            boolean drawTop = false;
+            boolean drawBottom = false;
+            boolean drawLeft = false;
+            boolean drawRight = false;
+
+            float topFadeStrength = 0.0f;
+            float bottomFadeStrength = 0.0f;
+            float leftFadeStrength = 0.0f;
+            float rightFadeStrength = 0.0f;
+
+            final float fadeHeight = mFadingEdgeLength;
+            int length = (int) fadeHeight;
+
+            // clip the fade length if top and bottom fades overlap
+            // overlapping fades produce odd-looking artifacts
+            if (mIsVertical && (top + length > bottom - length)) {
+                length = (bottom - top) / 2;
+            }
+
+            // also clip horizontal fades if necessary
+            if (!mIsVertical && (left + length > right - length)) {
+                length = (right - left) / 2;
+            }
+
+            if (mIsVertical) {
+                topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
+                drawTop = topFadeStrength * fadeHeight > 1.0f;
+                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
+                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
+            }
+
+            if (!mIsVertical) {
+                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
+                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
+                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
+                drawRight = rightFadeStrength * fadeHeight > 1.0f;
+            }
+
+            if (drawTop) {
+                matrix.setScale(1, fadeHeight * topFadeStrength);
+                matrix.postTranslate(left, top);
+                fade.setLocalMatrix(matrix);
+                canvas.drawRect(left, top, right, top + length, p);
+            }
+
+            if (drawBottom) {
+                matrix.setScale(1, fadeHeight * bottomFadeStrength);
+                matrix.postRotate(180);
+                matrix.postTranslate(left, bottom);
+                fade.setLocalMatrix(matrix);
+                canvas.drawRect(left, bottom - length, right, bottom, p);
+            }
+
+            if (drawLeft) {
+                matrix.setScale(1, fadeHeight * leftFadeStrength);
+                matrix.postRotate(-90);
+                matrix.postTranslate(left, top);
+                fade.setLocalMatrix(matrix);
+                canvas.drawRect(left, top, left + length, bottom, p);
+            }
+
+            if (drawRight) {
+                matrix.setScale(1, fadeHeight * rightFadeStrength);
+                matrix.postRotate(90);
+                matrix.postTranslate(right, top);
+                fade.setLocalMatrix(matrix);
+                canvas.drawRect(right - length, top, right, bottom, p);
+            }
+        }
+    }
+
+    public int getVerticalFadingEdgeLengthCallback() {
+        return mFadingEdgeLength;
+    }
+
+    public int getHorizontalFadingEdgeLengthCallback() {
+        return mFadingEdgeLength;
+    }
+
+    public void setLayoutTransitionCallback(LayoutTransition transition) {
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            if (transition != null) {
+                transition.addTransitionListener(new LayoutTransition.TransitionListener() {
+                    @Override
+                    public void startTransition(LayoutTransition transition,
+                            ViewGroup container, View view, int transitionType) {
+                        updateShowBackground();
+                    }
+
+                    @Override
+                    public void endTransition(LayoutTransition transition,
+                            ViewGroup container, View view, int transitionType) {
+                        updateShowBackground();
+                    }
+                });
+            }
+        }
+    }
+
+    // Turn on/off drawing the background in our ancestor, and turn on/off drawing
+    // in the items in LinearLayout contained by this scrollview.
+    // Moving the background drawing to our children, and turning on a drawing cache
+    // for each of them, gives us a ~20fps gain when Recents is rendered in software
+    public void updateShowBackground() {
+        if (!mAttachedToWindow) {
+            // We haven't been initialized yet-- we'll get called again when we are
+            return;
+        }
+        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
+            LayoutTransition transition = mLinearLayout.getLayoutTransition();
+            int linearLayoutSize =
+                mIsVertical ? mLinearLayout.getHeight() : mLinearLayout.getWidth();
+            int scrollViewSize =
+                mIsVertical ? mScrollView.getHeight() : mScrollView.getWidth();
+            boolean show = !mScrollView.isHardwareAccelerated() &&
+                (linearLayoutSize > scrollViewSize) &&
+                !(transition != null && transition.isRunning()) &&
+                mCallback.isRecentsVisible();
+
+            if (!mFirstTime && show == mShowBackground) return;
+            mShowBackground = show;
+            mFirstTime = false;
+
+            mCallback.handleShowBackground(!show);
+            for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+                View v = mLinearLayout.getChildAt(i);
+                if (show) {
+                    v.setBackgroundDrawable(mBackgroundDrawable.newDrawable());
+                    v.setDrawingCacheEnabled(true);
+                    v.buildDrawingCache();
+                } else {
+                    v.setDrawingCacheEnabled(false);
+                    v.destroyDrawingCache();
+                    v.setBackgroundDrawable(null);
+                }
+            }
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b1a30d9..3acef08 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.database.DataSetObserver;
+import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -40,6 +41,7 @@
     private RecentsCallback mCallback;
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
+    private RecentsScrollViewPerformanceHelper mPerformanceHelper;
 
     private OnLongClickListener mOnLongClick = new OnLongClickListener() {
         public boolean onLongClick(View v) {
@@ -49,15 +51,13 @@
         }
     };
 
-    public RecentsVerticalScrollView(Context context) {
-        this(context, null);
-    }
-
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+
+        mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
     }
 
     private int scrollPositionOfMostRecent() {
@@ -77,11 +77,15 @@
             }
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
+            if (mPerformanceHelper != null) {
+                mPerformanceHelper.addViewCallback(view);
+            }
+
             if (old == null) {
                 view.setClickable(true);
                 view.setOnLongClickListener(mOnLongClick);
 
-                final View thumbnail = getChildContentView(view);
+                final View thumbnail = view.findViewById(R.id.app_thumbnail);
                 // thumbnail is set to clickable in the layout file
                 thumbnail.setOnClickListener(new OnClickListener() {
                     public void onClick(View v) {
@@ -138,6 +142,11 @@
         // We do this so the underlying ScrollView knows that it won't get
         // the chance to intercept events anymore
         requestDisallowInterceptTouchEvent(true);
+        v.setActivated(true);
+    }
+
+    public void onDragCancelled(View v) {
+        v.setActivated(false);
     }
 
     public View getChildAtPosition(MotionEvent ev) {
@@ -155,7 +164,60 @@
     }
 
     public View getChildContentView(View v) {
-        return v.findViewById(R.id.app_thumbnail);
+        return v.findViewById(R.id.recent_item);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.onLayoutCallback();
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        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,
+                    left, right, top, bottom, mScrollX, mScrollY,
+                    getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
+                    0, 0);
+        }
+    }
+
+    @Override
+    public int getVerticalFadingEdgeLength() {
+        if (mPerformanceHelper != null) {
+            return mPerformanceHelper.getVerticalFadingEdgeLengthCallback();
+        } else {
+            return super.getVerticalFadingEdgeLength();
+        }
+    }
+
+    @Override
+    public int getHorizontalFadingEdgeLength() {
+        if (mPerformanceHelper != null) {
+            return mPerformanceHelper.getHorizontalFadingEdgeLengthCallback();
+        } else {
+            return super.getHorizontalFadingEdgeLength();
+        }
     }
 
     @Override
@@ -169,6 +231,14 @@
     }
 
     @Override
+    public void onAttachedToWindow() {
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.onAttachedToWindowCallback(
+                    mCallback, mLinearLayout, isHardwareAccelerated());
+        }
+    }
+
+    @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         float densityScale = getResources().getDisplayMetrics().density;
@@ -208,6 +278,12 @@
         });
     }
 
+    public void onRecentsVisibilityChanged() {
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.updateShowBackground();
+        }
+    }
+
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -236,6 +312,9 @@
 
     @Override
     public void setLayoutTransition(LayoutTransition transition) {
+        if (mPerformanceHelper != null) {
+            mPerformanceHelper.setLayoutTransitionCallback(transition);
+        }
         // The layout transition applies to our embedded LinearLayout
         mLinearLayout.setLayoutTransition(transition);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e6c0b96..98dca92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -70,6 +70,14 @@
         return mCurrentView.findViewById(R.id.menu);
     }
 
+    public View getBackButton() {
+        return mCurrentView.findViewById(R.id.back);
+    }
+
+    public View getHomeButton() {
+        return mCurrentView.findViewById(R.id.home);
+    }
+
     public NavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e3ea0de..3d23abe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -380,7 +380,7 @@
     }
 
     protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
-        boolean translucent = false;
+        boolean opaque = false;
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 layoutParams.width,
                 layoutParams.height,
@@ -388,7 +388,7 @@
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                (translucent ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
+                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
         if (ActivityManager.isHighEndGfx(mDisplay)) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
@@ -404,7 +404,7 @@
         // Recents Panel
         boolean visible = false;
         if (mRecentsPanel != null) {
-            visible = mRecentsPanel.getVisibility() == View.VISIBLE;
+            visible = mRecentsPanel.isShowing();
             WindowManagerImpl.getDefault().removeView(mRecentsPanel);
         }
 
@@ -1091,18 +1091,9 @@
             }
         }
 
-        if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
-            if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
-                Slog.d(TAG, "DISABLE_NAVIGATION: yes");
-
-                // close recents if it's visible
-                mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
-                mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
-            }
-
-            if (mNavigationBarView != null) {
-                mNavigationBarView.setEnabled((state & StatusBarManager.DISABLE_NAVIGATION) == 0);
-            }
+        if ((diff & (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)) != 0) {
+            setNavigationVisibility(state &
+                    (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK));
         }
 
         if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
@@ -1127,6 +1118,32 @@
         }
     }
 
+    private void setNavigationVisibility(int visibility) {
+        boolean disableNavigation = ((visibility & StatusBarManager.DISABLE_NAVIGATION) != 0);
+        boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0);
+
+        Slog.i(TAG, "DISABLE_BACK: " + (disableBack ? "yes" : "no"));
+        Slog.i(TAG, "DISABLE_NAVIGATION: " + (disableNavigation ? "yes" : "no"));
+
+        if (mNavigationBarView != null) {
+            if (disableNavigation && disableBack) {
+                mNavigationBarView.setEnabled(false);
+            } else {
+                mNavigationBarView.getBackButton().setEnabled(!disableBack);
+                mNavigationBarView.getHomeButton().setEnabled(!disableNavigation);
+                mNavigationBarView.getRecentsButton().setEnabled(!disableNavigation);
+
+                mNavigationBarView.setEnabled(true);
+            }
+        }
+
+        if (disableNavigation) {
+            // close recents if it's visible
+            mHandler.removeMessages(MSG_CLOSE_RECENTS_PANEL);
+            mHandler.sendEmptyMessage(MSG_CLOSE_RECENTS_PANEL);
+        }
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 60dfdac..3c85814 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -130,6 +130,8 @@
     int mLastDataTypeIconId = -1;
     String mLastLabel = "";
 
+    private boolean mHasMobileDataFeature;
+
     boolean mDataAndWifiStacked = false;
 
     // yuck -- stop doing this here and put it in the framework
@@ -147,6 +149,10 @@
     public NetworkController(Context context) {
         mContext = context;
 
+        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        mHasMobileDataFeature = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
         // set up the default wifi icon, used when no radios have ever appeared
         updateWifiIcons();
 
@@ -229,7 +235,7 @@
                 mWifiIconId,
                 mWifiActivityIconId);
         cluster.setMobileDataIndicators(
-                hasMobileDataFeature(),
+                mHasMobileDataFeature,
                 mPhoneSignalIconId,
                 mMobileActivityIconId,
                 mDataTypeIconId);
@@ -376,12 +382,6 @@
         }
     }
 
-    private boolean hasMobileDataFeature() {
-        // XXX: HAX: replace when a more reliable method is available
-        return (! "wifi-only".equals(SystemProperties.get("ro.carrier")));
-    }
-
-
     private void updateAirplaneMode() {
         mAirplaneMode = (Settings.System.getInt(mContext.getContentResolver(),
             Settings.System.AIRPLANE_MODE_ON, 0) == 1);
@@ -828,8 +828,8 @@
             label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
             // On devices without mobile radios, we want to show the wifi icon
             combinedSignalIconId =
-                hasMobileDataFeature() ? mDataSignalIconId : mWifiIconId;
-            mContentDescriptionCombinedSignal = hasMobileDataFeature()
+                mHasMobileDataFeature ? mDataSignalIconId : mWifiIconId;
+            mContentDescriptionCombinedSignal = mHasMobileDataFeature
                 ? mContentDescriptionDataType : mContentDescriptionWifi;
             mDataTypeIconId = 0;
         }
@@ -866,7 +866,7 @@
                         mWifiIconId,
                         mWifiActivityIconId);
                 cluster.setMobileDataIndicators(
-                        hasMobileDataFeature(),
+                        mHasMobileDataFeature,
                         mPhoneSignalIconId,
                         mMobileActivityIconId,
                         mDataTypeIconId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 469b462..e287b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -124,6 +124,9 @@
         requestDisallowInterceptTouchEvent(true);
     }
 
+    public void onDragCancelled(View v) {
+    }
+
     public View getChildAtPosition(MotionEvent ev) {
         // find the view under the pointer, accounting for GONE views
         final int count = getChildCount();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 2ab667d..cc73d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -306,7 +306,7 @@
         mStatusBarView.setIgnoreChildren(2, mRecentButton, mRecentsPanel);
 
         lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
+                (int) res.getDimension(R.dimen.status_bar_recents_width),
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
                 WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
@@ -949,29 +949,34 @@
                 mTicker.halt();
             }
         }
-        if ((diff & StatusBarManager.DISABLE_NAVIGATION) != 0) {
-            if ((state & StatusBarManager.DISABLE_NAVIGATION) != 0) {
-                Slog.i(TAG, "DISABLE_NAVIGATION: yes");
-                mNavigationArea.setVisibility(View.INVISIBLE);
-                mInputMethodSwitchButton.setScreenLocked(true);
-            } else {
-                Slog.i(TAG, "DISABLE_NAVIGATION: no");
-                mNavigationArea.setVisibility(View.VISIBLE);
-                mInputMethodSwitchButton.setScreenLocked(false);
-            }
+        if ((diff & (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK)) != 0) {
+            setNavigationVisibility(state &
+                    (StatusBarManager.DISABLE_NAVIGATION | StatusBarManager.DISABLE_BACK));
         }
-        if ((diff & StatusBarManager.DISABLE_BACK) != 0) {
-            if ((state & StatusBarManager.DISABLE_BACK) != 0) {
-                Slog.i(TAG, "DISABLE_BACK: yes");
-                mBackButton.setEnabled(false);
-                mInputMethodSwitchButton.setScreenLocked(true);
-            } else {
-                Slog.i(TAG, "DISABLE_BACK: no");
-                mBackButton.setEnabled(true);
-                mInputMethodSwitchButton.setScreenLocked(false);
-            }
+    }
+
+    private void setNavigationVisibility(int visibility) {
+        boolean disableNavigation = ((visibility & StatusBarManager.DISABLE_NAVIGATION) != 0);
+        boolean disableBack = ((visibility & StatusBarManager.DISABLE_BACK) != 0);
+
+        Slog.i(TAG, "DISABLE_BACK: " + (disableBack ? "yes" : "no"));
+        Slog.i(TAG, "DISABLE_NAVIGATION: " + (disableNavigation ? "yes" : "no"));
+
+        if (disableNavigation && disableBack) {
+            mNavigationArea.setVisibility(View.INVISIBLE);
+        } else {
+            int backVisiblity = (disableBack ? View.INVISIBLE : View.VISIBLE);
+            int navVisibility = (disableNavigation ? View.INVISIBLE : View.VISIBLE);
+
+            mBackButton.setVisibility(backVisiblity);
+            mHomeButton.setVisibility(navVisibility);
+            mRecentButton.setVisibility(navVisibility);
+            // don't change menu button visibility here
+
+            mNavigationArea.setVisibility(View.VISIBLE);
         }
 
+        mInputMethodSwitchButton.setScreenLocked(disableNavigation);
     }
 
     private boolean hasTicker(Notification n) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 162381d..a544167 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -1185,15 +1185,19 @@
             }
 
             int flags = StatusBarManager.DISABLE_NONE;
-            if (mShowing && !mHidden) {
-                // showing lockscreen exclusively; disable various extra
-                // statusbar components.
+            if (mShowing) {
+                // disable navigation status bar components if lock screen is up
                 flags |= StatusBarManager.DISABLE_NAVIGATION;
-                flags |= StatusBarManager.DISABLE_CLOCK;
-            }
-            if (mShowing && (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND)) {
-                // showing secure lockscreen; disable expanding.
-                flags |= StatusBarManager.DISABLE_EXPAND;
+                if (!mHidden) {
+                    // showing lockscreen exclusively (no activities in front of it)
+                    // disable clock and back button too
+                    flags |= StatusBarManager.DISABLE_BACK;
+                    flags |= StatusBarManager.DISABLE_CLOCK;
+                }
+                if (isSecure() || !ENABLE_INSECURE_STATUS_BAR_EXPAND) {
+                    // showing secure lockscreen; disable expanding.
+                    flags |= StatusBarManager.DISABLE_EXPAND;
+                }
             }
 
             if (DEBUG) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8b450f6..2f5deba 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -267,6 +267,7 @@
     int mLidOpen = LID_ABSENT;
 
     boolean mSystemReady;
+    boolean mSystemBooted;
     boolean mHdmiPlugged;
     int mUiMode = Configuration.UI_MODE_TYPE_NORMAL;
     int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -2497,6 +2498,11 @@
                                         mKeyguardMediator.isShowingAndNotHidden() :
                                         mKeyguardMediator.isShowing());
 
+        if (!mSystemBooted) {
+            // If we have not yet booted, don't let key events do anything.
+            return 0;
+        }
+
         if (false) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
                   + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
@@ -3100,6 +3106,13 @@
         }
     }
 
+    /** {@inheritDoc} */
+    public void systemBooted() {
+        synchronized (mLock) {
+            mSystemBooted = true;
+        }
+    }
+
     ProgressDialog mBootMsgDialog = null;
 
     /** {@inheritDoc} */
@@ -3492,7 +3505,8 @@
 
     public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
-                pw.print(" mSystemRead="); pw.println(mSystemReady);
+                pw.print(" mSystemReady="); pw.print(mSystemReady);
+                pw.print(" mSystemBooted="); pw.println(mSystemBooted);
         pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
                 pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
                 pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e193be0..b178fd9 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -769,11 +769,6 @@
     status_t result = checkPidAndHardware();
     if (result != NO_ERROR) return result;
 
-    if (mHardware->recordingEnabled()) {
-        LOGE("Cannot take picture during recording.");
-        return INVALID_OPERATION;
-    }
-
     if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
         (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
         LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 3815c3b..2348d76 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -703,6 +703,12 @@
         return result.toArray(new NetworkInfo[result.size()]);
     }
 
+    @Override
+    public boolean isNetworkSupported(int networkType) {
+        enforceAccessPermission();
+        return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null));
+    }
+
     /**
      * Return LinkProperties for the active (i.e., connected) default
      * network interface.  It is assumed that at most one default network
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 5429c0c..f0b5958 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -137,3 +137,10 @@
 # [ 8- 3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
 # [ 2- 0] Network type (as defined by ConnectivityManager)
 50020 connectivity_state_changed (custom|1|5)
+
+
+# ---------------------------
+# NetworkStatsService.java
+# ---------------------------
+51100 netstats_mobile_sample (iface_rx|2|2),(iface_tx|2|2),(uid_rx|2|2),(uid_tx|2|2)
+51101 netstats_wifi_sample (iface_rx|2|2),(iface_tx|2|2),(uid_rx|2|2),(uid_tx|2|2)
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index bb831f5..0e1a1e3 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -655,7 +655,7 @@
         List<InputMethodSubtype> enabledSubtypes =
                 mSettings.getEnabledInputMethodSubtypeListLocked(imi);
         if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
-            enabledSubtypes = getApplicableSubtypesLocked(mRes, getSubtypes(imi));
+            enabledSubtypes = getImplicitlyApplicableSubtypesLocked(mRes, imi);
         }
         return InputMethodSubtype.sort(mContext, 0, imi, enabledSubtypes);
     }
@@ -1668,13 +1668,13 @@
     }
 
     @Override
-    public boolean setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
+    public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
         // By this IPC call, only a process which shares the same uid with the IME can add
         // additional input method subtypes to the IME.
-        if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return false;
+        if (TextUtils.isEmpty(imiId) || subtypes == null || subtypes.length == 0) return;
         synchronized (mMethodMap) {
             final InputMethodInfo imi = mMethodMap.get(imiId);
-            if (imi == null) return false;
+            if (imi == null) return;
             final PackageManager pm = mContext.getPackageManager();
             final String[] packageInfos = pm.getPackagesForUid(Binder.getCallingUid());
             if (packageInfos != null) {
@@ -1688,12 +1688,12 @@
                         } finally {
                             Binder.restoreCallingIdentity(ident);
                         }
-                        return true;
+                        return;
                     }
                 }
             }
         }
-        return false;
+        return;
     }
 
     private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
@@ -1903,6 +1903,20 @@
         return subtypes;
     }
 
+
+    private static ArrayList<InputMethodSubtype> getOverridingImplicitlyEnabledSubtypes(
+            InputMethodInfo imi, String mode) {
+        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+        final int subtypeCount = imi.getSubtypeCount();
+        for (int i = 0; i < subtypeCount; ++i) {
+            final InputMethodSubtype subtype = imi.getSubtypeAt(i);
+            if (subtype.overridesImplicitlyEnabledSubtype() && subtype.getMode().equals(mode)) {
+                subtypes.add(subtype);
+            }
+        }
+        return subtypes;
+    }
+
     private boolean chooseNewDefaultIMELocked() {
         List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked();
         if (enabled != null && enabled.size() > 0) {
@@ -2357,8 +2371,9 @@
         return NOT_A_SUBTYPE_ID;
     }
 
-    private static ArrayList<InputMethodSubtype> getApplicableSubtypesLocked(
-            Resources res, List<InputMethodSubtype> subtypes) {
+    private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
+            Resources res, InputMethodInfo imi) {
+        final List<InputMethodSubtype> subtypes = getSubtypes(imi);
         final String systemLocale = res.getConfiguration().locale.toString();
         if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
         HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
@@ -2366,6 +2381,19 @@
         final int N = subtypes.size();
         boolean containsKeyboardSubtype = false;
         for (int i = 0; i < N; ++i) {
+            // scan overriding implicitly enabled subtypes.
+            InputMethodSubtype subtype = subtypes.get(i);
+            if (subtype.overridesImplicitlyEnabledSubtype()) {
+                final String mode = subtype.getMode();
+                if (!applicableModeAndSubtypesMap.containsKey(mode)) {
+                    applicableModeAndSubtypesMap.put(mode, subtype);
+                }
+            }
+        }
+        if (applicableModeAndSubtypesMap.size() > 0) {
+            return new ArrayList<InputMethodSubtype>(applicableModeAndSubtypesMap.values());
+        }
+        for (int i = 0; i < N; ++i) {
             InputMethodSubtype subtype = subtypes.get(i);
             final String locale = subtype.getLocale();
             final String mode = subtype.getMode();
@@ -2489,16 +2517,21 @@
                 subtype = findLastResortApplicableSubtypeLocked(
                         mRes, enabledSubtypes, mode, null, true);
             }
+            final ArrayList<InputMethodSubtype> overridingImplicitlyEnabledSubtypes =
+                    getOverridingImplicitlyEnabledSubtypes(imi, mode);
+            final ArrayList<InputMethodSubtype> subtypesForSearch =
+                    overridingImplicitlyEnabledSubtypes.isEmpty()
+                            ? getSubtypes(imi) : overridingImplicitlyEnabledSubtypes;
             // 4. Search by the current subtype's locale from all subtypes.
             if (subtype == null && mCurrentSubtype != null) {
                 subtype = findLastResortApplicableSubtypeLocked(
-                        mRes, getSubtypes(imi), mode, mCurrentSubtype.getLocale(), false);
+                        mRes, subtypesForSearch, mode, mCurrentSubtype.getLocale(), false);
             }
             // 5. Search by the system locale from all subtypes.
             // 6. Search the first enabled subtype matched with mode from all subtypes.
             if (subtype == null) {
                 subtype = findLastResortApplicableSubtypeLocked(
-                        mRes, getSubtypes(imi), mode, null, true);
+                        mRes, subtypesForSearch, mode, null, true);
             }
             if (subtype != null) {
                 if (imiId.equals(mCurMethodId)) {
@@ -2945,12 +2978,12 @@
                     if (explicitlyEnabledSubtypes.size() == 0) {
                         // If there are no explicitly enabled subtypes, applicable subtypes are
                         // enabled implicitly.
-                        InputMethodInfo ime = mMethodMap.get(imeId);
+                        InputMethodInfo imi = mMethodMap.get(imeId);
                         // If IME is enabled and no subtypes are enabled, applicable subtypes
                         // are enabled implicitly, so needs to treat them to be enabled.
-                        if (ime != null && ime.getSubtypeCount() > 0) {
+                        if (imi != null && imi.getSubtypeCount() > 0) {
                             List<InputMethodSubtype> implicitlySelectedSubtypes =
-                                    getApplicableSubtypesLocked(mRes, getSubtypes(ime));
+                                    getImplicitlyApplicableSubtypesLocked(mRes, imi);
                             if (implicitlySelectedSubtypes != null) {
                                 final int N = implicitlySelectedSubtypes.size();
                                 for (int i = 0; i < N; ++i) {
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 85d8cece..1497511 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1033,6 +1033,38 @@
         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
         final NetworkStats.Entry entry = new NetworkStats.Entry();
 
+        final HashSet<String> knownIfaces = Sets.newHashSet();
+        final HashSet<String> activeIfaces = Sets.newHashSet();
+
+        // collect any historical stats and active state
+        // TODO: migrate to reading from single file
+        if (mBandwidthControlEnabled) {
+            for (String iface : fileListWithoutNull(mStatsXtIface)) {
+                final File ifacePath = new File(mStatsXtIface, iface);
+
+                final long active = readSingleLongFromFile(new File(ifacePath, "active"));
+                if (active == 1) {
+                    knownIfaces.add(iface);
+                    activeIfaces.add(iface);
+                } else if (active == 0) {
+                    knownIfaces.add(iface);
+                } else {
+                    continue;
+                }
+
+                entry.iface = iface;
+                entry.uid = UID_ALL;
+                entry.set = SET_DEFAULT;
+                entry.tag = TAG_NONE;
+                entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
+                entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
+                entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
+                entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
+
+                stats.addValues(entry);
+            }
+        }
+
         final ArrayList<String> values = Lists.newArrayList();
 
         BufferedReader reader = null;
@@ -1058,7 +1090,13 @@
                     entry.txBytes = Long.parseLong(values.get(9));
                     entry.txPackets = Long.parseLong(values.get(10));
 
-                    stats.addValues(entry);
+                    if (activeIfaces.contains(entry.iface)) {
+                        // combine stats when iface is active
+                        stats.combineValues(entry);
+                    } else if (!knownIfaces.contains(entry.iface)) {
+                        // add stats when iface is unknown
+                        stats.addValues(entry);
+                    }
                 } catch (NumberFormatException e) {
                     Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
                 }
@@ -1073,24 +1111,6 @@
             IoUtils.closeQuietly(reader);
         }
 
-        // splice in historical stats not reflected in mStatsIface
-        if (mBandwidthControlEnabled) {
-            for (String iface : fileListWithoutNull(mStatsXtIface)) {
-                final File ifacePath = new File(mStatsXtIface, iface);
-
-                entry.iface = iface;
-                entry.uid = UID_ALL;
-                entry.set = SET_DEFAULT;
-                entry.tag = TAG_NONE;
-                entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
-                entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
-                entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
-                entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
-
-                stats.combineValues(entry);
-            }
-        }
-
         return stats;
     }
 
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index cbd986f..bbc26d6 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -853,6 +853,14 @@
                 if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
                     int oldWakeLockState = mWakeLockState;
                     mWakeLockState = mLocks.reactivateScreenLocksLocked();
+
+                    // Disable proximity sensor if if user presses power key while we are in the
+                    // "waiting for proximity sensor to go negative" state.
+                    if ((mWakeLockState & SCREEN_ON_BIT) != 0
+                            && mProximitySensorActive && mProximityWakeLockCount == 0) {
+                        mProximitySensorActive = false;
+                    }
+
                     if (mSpew) {
                         Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
                                 + " mWakeLockState=0x"
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d0e8b5e..2714fc5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -350,7 +350,6 @@
                 Slog.i(TAG, "Wi-Fi Service");
                 wifi = new WifiService(context);
                 ServiceManager.addService(Context.WIFI_SERVICE, wifi);
-                wifi.checkAndStartWifi();
             } catch (Throwable e) {
                 reportWtf("starting Wi-Fi Service", e);
             }
@@ -361,6 +360,7 @@
                 ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
                 networkStats.bindConnectivityManager(connectivity);
                 networkPolicy.bindConnectivityManager(connectivity);
+                wifi.checkAndStartWifi();
                 wifiP2p.connectivityServiceReady();
             } catch (Throwable e) {
                 reportWtf("starting Connectivity Service", e);
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index e0dc96f..4d54fd4 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -31,6 +31,8 @@
 import static android.net.NetworkStats.SET_FOREGROUND;
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateWifi;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
 import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
@@ -76,6 +78,7 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
+import android.util.EventLog;
 import android.util.NtpTrustedTime;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -83,6 +86,7 @@
 
 import com.android.internal.os.AtomicFile;
 import com.android.internal.util.Objects;
+import com.android.server.EventLogTags;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
@@ -387,7 +391,9 @@
                     entry.uid = UID_ALL;
                     entry.tag = TAG_NONE;
                     entry.rxBytes = historyEntry.rxBytes;
+                    entry.rxPackets = historyEntry.rxPackets;
                     entry.txBytes = historyEntry.txBytes;
+                    entry.txPackets = historyEntry.txPackets;
 
                     stats.combineValues(entry);
                 }
@@ -716,6 +722,11 @@
             Slog.v(TAG, "performPollLocked() took " + duration + "ms");
         }
 
+        // sample stats after detailed poll
+        if (detailedPoll) {
+            performSample();
+        }
+
         // finally, dispatch updated event to any listeners
         final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED);
         updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -809,6 +820,33 @@
     }
 
     /**
+     * Sample recent statistics summary into {@link EventLog}.
+     */
+    private void performSample() {
+        // take sample as total over last 4 hours
+        final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
+        final long start = end - (4 * HOUR_IN_MILLIS);
+
+        NetworkTemplate template = null;
+        NetworkStats.Entry ifaceTotal = null;
+        NetworkStats.Entry uidTotal = null;
+
+        // collect mobile sample
+        template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
+        ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
+        uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+        EventLogTags.writeNetstatsMobileSample(
+                ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes);
+
+        // collect wifi sample
+        template = buildTemplateWifi();
+        ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal);
+        uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+        EventLogTags.writeNetstatsWifiSample(
+                ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes);
+    }
+
+    /**
      * Clean up {@link #mUidStats} after UID is removed.
      */
     private void removeUidLocked(int uid) {
@@ -1249,6 +1287,12 @@
         }
     };
 
+    private static String getActiveSubscriberId(Context context) {
+        final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
+                Context.TELEPHONY_SERVICE);
+        return telephony.getSubscriberId();
+    }
+
     /**
      * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
      */
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index b8797d18..bfb244b 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -78,8 +78,6 @@
 import android.os.Environment;
 import android.os.FileObserver;
 import android.os.FileUtils;
-import android.os.FileUtils.FileStatus;
-import android.os.Debug;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -706,6 +704,7 @@
                         Runtime.getRuntime().gc();
                     }
                     if (msg.obj != null) {
+                        @SuppressWarnings("unchecked")
                         Set<SdInstallArgs> args = (Set<SdInstallArgs>) msg.obj;
                         if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading all containers");
                         // Unload containers
@@ -3039,10 +3038,6 @@
             return null;
         }
         mScanningPath = scanFile;
-        if (pkg == null) {
-            mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
-            return null;
-        }
 
         if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f5a5e2e..755a268 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2498,6 +2498,10 @@
             int attrChanges = 0;
             int flagChanges = 0;
             if (attrs != null) {
+                if (win.mAttrs.type != attrs.type) {
+                    throw new IllegalArgumentException(
+                            "Window type can not be changed after the window is added.");
+                }
                 flagChanges = win.mAttrs.flags ^= attrs.flags;
                 attrChanges = win.mAttrs.copyFrom(attrs);
             }
@@ -4703,6 +4707,8 @@
             mH.sendMessageDelayed(msg, 30*1000);
         }
 
+        mPolicy.systemBooted();
+
         performEnableScreen();
     }
 
@@ -7921,13 +7927,13 @@
                 if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
                     if (DEBUG_WALLPAPER) Slog.v(TAG,
                             "Detached wallpaper changed from " + mWindowDetachedWallpaper
-                            + windowDetachedWallpaper);
+                            + " to " + windowDetachedWallpaper);
                     mWindowDetachedWallpaper = windowDetachedWallpaper;
                     wallpaperMayChange = true;
                 }
 
                 if (windowAnimationBackgroundColor != 0) {
-                    // If this window that wants black is the current wallpaper
+                    // If the window that wants black is the current wallpaper
                     // target, then the black goes *below* the wallpaper so we
                     // don't cause the wallpaper to suddenly disappear.
                     WindowState target = windowAnimationBackground;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 598220f..b4c5dec 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -817,6 +817,20 @@
     mHwWorkListDirty = false;
     HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
     if (hwc.initCheck() == NO_ERROR) {
+
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        uint32_t flags = hw.getFlags();
+        if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
+            (flags & DisplayHardware::BUFFER_PRESERVED))
+        {
+            // we need to redraw everything (the whole screen)
+            // NOTE: we could be more subtle here and redraw only
+            // the area which will end-up in an overlay. But since this
+            // shouldn't happen often, we invalidate everything.
+            mDirtyRegion.set(hw.bounds());
+            mInvalidRegion = mDirtyRegion;
+        }
+
         const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
         const size_t count = currentLayers.size();
         hwc.createWorkList(count);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index ecf78d9..2a25866 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -106,6 +106,7 @@
 
     public void testNetworkStatsSummaryDown() throws Exception {
         stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+        stageLong(1L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/active"));
         stageLong(1024L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_bytes"));
         stageLong(128L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_packets"));
         stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
@@ -119,6 +120,7 @@
 
     public void testNetworkStatsCombined() throws Exception {
         stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+        stageLong(1L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/active"));
         stageLong(10L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_bytes"));
         stageLong(20L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_packets"));
         stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
@@ -129,6 +131,18 @@
                 2205L + 20L, 489339L + 30L, 2237L + 40L);
     }
 
+    public void testNetworkStatsCombinedInactive() throws Exception {
+        stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+        stageLong(0L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/active"));
+        stageLong(10L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_bytes"));
+        stageLong(20L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/rx_packets"));
+        stageLong(30L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_bytes"));
+        stageLong(40L, new File(mTestProc, "net/xt_qtaguid/iface_stat/rmnet0/tx_packets"));
+
+        final NetworkStats stats = mService.getNetworkStatsSummary();
+        assertStatsEntry(stats, "rmnet0", UID_ALL, SET_DEFAULT, TAG_NONE, 10L, 20L, 30L, 40L);
+    }
+
     public void testKernelTags() throws Exception {
         assertEquals("0", tagToKernel(0x0));
         assertEquals("214748364800", tagToKernel(0x32));
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 3e13a86..bd35058 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.ConnectivityManager;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.AsyncResult;
@@ -230,8 +231,6 @@
 
     Object     mLastNITZTimeInfo;
 
-    private static final String WIFI_ONLY_CARRIER = "wifi-only";
-
     //***** Events
 
     static final int EVENT_SEND                 = 1;
@@ -626,10 +625,9 @@
         Looper looper = mSenderThread.getLooper();
         mSender = new RILSender(looper);
 
-        // TODO: Provide a common API for determining if a
-        // device is wifi-only. bug: 3480713
-        String carrier = SystemProperties.get("ro.carrier");
-        if (WIFI_ONLY_CARRIER.equals(carrier)) {
+        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
             riljLog("Not starting RILReceiver: wifi-only");
         } else {
             riljLog("Starting RILReceiver");
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 92f5b64..fb4067a 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -575,12 +575,19 @@
 
 // ==========================================================
 void
-generate_dep_file(const Options& options)
+generate_dep_file(const Options& options, const document_item_type* items)
 {
-   /* we open the file in binary mode to ensure that the same output is
-    * generated on all platforms !!
-    */
-    FILE* to = fopen(options.depFileName.c_str(), "wb");
+    /* we open the file in binary mode to ensure that the same output is
+     * generated on all platforms !!
+     */
+    FILE* to = NULL;
+    if (options.autoDepFile) {
+        string fileName = options.outputFileName + ".d";
+        to = fopen(fileName.c_str(), "wb");
+    } else {
+        to = fopen(options.depFileName.c_str(), "wb");
+    }
+
     if (to == NULL) {
         return;
     }
@@ -591,7 +598,12 @@
         slash = "";
     }
 
-    fprintf(to, "%s: \\\n", options.outputFileName.c_str());
+    if (items->item_type == INTERFACE_TYPE) {
+        fprintf(to, "%s: \\\n", options.outputFileName.c_str());
+    } else {
+        // parcelable: there's no output file.
+        fprintf(to, " : \\\n");
+    }
     fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
 
     while (import) {
@@ -611,44 +623,60 @@
 
 // ==========================================================
 static string
-generate_outputFileName(const Options& options, const document_item_type* items)
+generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
 {
     string result;
 
-    // items has already been checked to have only one interface.
-    if (items->item_type == INTERFACE_TYPE) {
-        interface_type* type = (interface_type*)items;
+    // create the path to the destination folder based on the
+    // interface package name
+    result = options.outputBaseFolder;
+    result += OS_PATH_SEPARATOR;
 
-        // create the path to the destination folder based on the
-        // interface package name
-        result = options.outputBaseFolder;
-        result += OS_PATH_SEPARATOR;
-
-        string package = type->package;
-        size_t len = package.length();
-        for (size_t i=0; i<len; i++) {
-            if (package[i] == '.') {
-                package[i] = OS_PATH_SEPARATOR;
-            }
+    string packageStr = package;
+    size_t len = packageStr.length();
+    for (size_t i=0; i<len; i++) {
+        if (packageStr[i] == '.') {
+            packageStr[i] = OS_PATH_SEPARATOR;
         }
-
-        result += package;
-        
-        // add the filename by replacing the .aidl extension to .java
-        const char* p = strchr(type->name.data, '.');
-        len = p ? p-type->name.data : strlen(type->name.data);
-
-        result += OS_PATH_SEPARATOR;
-        result.append(type->name.data, len);
-        result += ".java";
     }
 
+    result += packageStr;
+
+    // add the filename by replacing the .aidl extension to .java
+    const char* p = strchr(name.data, '.');
+    len = p ? p-name.data : strlen(name.data);
+
+    result += OS_PATH_SEPARATOR;
+    result.append(name.data, len);
+    result += ".java";
+
     return result;
 }
 
 // ==========================================================
+static string
+generate_outputFileName(const Options& options, const document_item_type* items)
+{
+    // items has already been checked to have only one interface.
+    if (items->item_type == INTERFACE_TYPE) {
+        interface_type* type = (interface_type*)items;
+
+        return generate_outputFileName2(options, type->name, type->package);
+    } else if (items->item_type == PARCELABLE_TYPE) {
+        parcelable_type* type = (parcelable_type*)items;
+        return generate_outputFileName2(options, type->name, type->package);
+    }
+
+    // I don't think we can come here, but safer than returning NULL.
+    string result;
+    return result;
+}
+
+
+
+// ==========================================================
 static void
-check_outputFileName(const string& path) {
+check_outputFilePath(const string& path) {
     size_t len = path.length();
     for (size_t i=0; i<len ; i++) {
         if (path[i] == OS_PATH_SEPARATOR) {
@@ -756,7 +784,7 @@
 
 // ==========================================================
 static int
-compile_aidl(const Options& options)
+compile_aidl(Options& options)
 {
     int err = 0, N;
 
@@ -850,27 +878,30 @@
         return 1;
     }
 
+    // if needed, generate the outputFileName from the outputBaseFolder
+    if (options.outputFileName.length() == 0 &&
+            options.outputBaseFolder.length() > 0) {
+        options.outputFileName = generate_outputFileName(options, mainDoc);
+    }
+
+    // if we were asked to, generate a make dependency file
+    // unless it's a parcelable *and* it's supposed to fail on parcelable
+    if ((options.autoDepFile || options.depFileName != "") &&
+            !(onlyParcelable && options.failOnParcelable)) {
+        // make sure the folders of the output file all exists
+        check_outputFilePath(options.outputFileName);
+        generate_dep_file(options, mainDoc);
+    }
+
     // they didn't ask to fail on parcelables, so just exit quietly.
     if (onlyParcelable && !options.failOnParcelable) {
         return 0;
     }
 
-    // if we were asked to, generate a make dependency file
-    if (options.depFileName != "") {
-        generate_dep_file(options);
-    }
-
-    // if needed, generate the outputFileName from the outputBaseFolder
-    string outputFileName = options.outputFileName;
-    if (outputFileName.length() == 0 &&
-            options.outputBaseFolder.length() > 0) {
-        outputFileName = generate_outputFileName(options, mainDoc);
-    }
-    
     // make sure the folders of the output file all exists
-    check_outputFileName(outputFileName);
+    check_outputFilePath(options.outputFileName);
 
-    err = generate_java(outputFileName, options.inputFileName.c_str(),
+    err = generate_java(options.outputFileName, options.inputFileName.c_str(),
                         (interface_type*)mainDoc);
 
     return err;
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 0aa7db2..7b2daeb 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -15,6 +15,7 @@
             "OPTIONS:\n"
             "   -I<DIR>    search path for import statements.\n"
             "   -d<FILE>   generate dependency file.\n"
+            "   -a         generate dependency file next to the output file with the name based on the input file.\n"
             "   -p<FILE>   file created by --preprocess to import.\n"
             "   -o<FOLDER> base output folder for generated files.\n"
             "   -b         fail when trying to compile a parcelable.\n"
@@ -49,6 +50,7 @@
 
     options->task = COMPILE_AIDL;
     options->failOnParcelable = false;
+    options->autoDepFile = false;
 
     // OPTIONS
     while (i < argc) {
@@ -73,6 +75,9 @@
                         return usage();
                     }
                 }
+                else if (s[1] == 'a') {
+                    options->autoDepFile = true;
+                }
                 else if (s[1] == 'p') {
                     if (len > 2) {
                         options->preprocessedFiles.push_back(s+2);
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index d88d988..387e37d 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -23,6 +23,7 @@
     string outputFileName;
     string outputBaseFolder;
     string depFileName;
+    bool autoDepFile;
 
     vector<string> filesToPreprocess;
 };
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 23e0ca1..2a52888 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -107,10 +107,9 @@
 
     }
 
-    public boolean setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
+    public void setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
-        return false;
     }
 
     public boolean setCurrentInputMethodSubtype(InputMethodSubtype arg0) throws RemoteException {
@@ -187,11 +186,4 @@
         // TODO Auto-generated method stub
         return null;
     }
-
-    public boolean setAdditionalInputMethodSubtypes(IBinder arg0, InputMethodSubtype[] arg1)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
 }
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 274edae..c52142d 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -36,6 +36,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
@@ -174,7 +175,7 @@
      * It triggers a disableNetwork call if a DNS check fails.
      */
     public boolean mDisableAPNextFailure = false;
-    private ConnectivityManager mConnectivityManager;
+    private static boolean sWifiOnly = false;
     private boolean mNotificationShown;
     public boolean mHasConnectedWifiManager = false;
 
@@ -219,9 +220,14 @@
 
     public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
         ContentResolver contentResolver = context.getContentResolver();
+
+        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        sWifiOnly = (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false);
+
         // Disable for wifi only devices.
         if (Settings.Secure.getString(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON) == null &&
-                "wifi-only".equals(SystemProperties.get("ro.carrier"))) {
+                sWifiOnly) {
             putSettingsBoolean(contentResolver, Settings.Secure.WIFI_WATCHDOG_ON, false);
         }
         WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
@@ -508,22 +514,6 @@
         }
     }
 
-    /**
-     * @return true if there is definitely no mobile data (we'll be less aggressive)
-     */
-    private boolean hasNoMobileData() {
-        if (mConnectivityManager == null) {
-            mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
-                    Context.CONNECTIVITY_SERVICE);
-        }
-        NetworkInfo mobileNetInfo = mConnectivityManager.getNetworkInfo(
-                ConnectivityManager.TYPE_MOBILE);
-        if (mobileNetInfo == null || !mobileNetInfo.isAvailable()) {
-            return true;
-        }
-        return false;
-    }
-
     class DefaultState extends State {
         @Override
         public boolean processMessage(Message msg) {
@@ -941,7 +931,7 @@
 
             if (mDisableAPNextFailure || mNumCheckFailures >= mBssids.size()
                     || mNumCheckFailures >= mMaxSsidBlacklists) {
-                if (hasNoMobileData()) {
+                if (sWifiOnly) {
                     Slog.w(WWSM_TAG, "Would disable bad network, but device has no mobile data!" +
                             "  Going idle...");
                     // This state should be called idle -- will be changing flow.
diff --git a/wifi/java/android/net/wifi/WpsConfiguration.java b/wifi/java/android/net/wifi/WpsConfiguration.java
index 2e7689a..0c2adfd 100644
--- a/wifi/java/android/net/wifi/WpsConfiguration.java
+++ b/wifi/java/android/net/wifi/WpsConfiguration.java
@@ -46,16 +46,21 @@
 
     public Setup setup;
 
+    /** @hide */
     public String BSSID;
 
     public String pin;
 
+    /** @hide */
     public IpAssignment ipAssignment;
 
+    /** @hide */
     public ProxySettings proxySettings;
 
+    /** @hide */
     public LinkProperties linkProperties;
 
+    /** @hide */
     public WpsConfiguration() {
         setup = Setup.INVALID;
         BSSID = null;
@@ -65,6 +70,7 @@
         linkProperties = new LinkProperties();
     }
 
+    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append(" setup: ").append(setup.toString());
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 2d57363..686d698 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -28,11 +28,6 @@
 public class WifiP2pConfig implements Parcelable {
 
     /**
-     * Device name
-     */
-    public String deviceName;
-
-    /**
      * Device address
      */
     public String deviceAddress;
@@ -53,6 +48,7 @@
 
     /**
      * Indicates whether the configuration is saved
+     * @hide
      */
     public enum Persist {
         SYSTEM_DEFAULT,
@@ -60,6 +56,7 @@
         NO
     }
 
+    /** @hide */
     public Persist persist = Persist.SYSTEM_DEFAULT;
 
     public WifiP2pConfig() {
@@ -110,7 +107,6 @@
 
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
-        sbuf.append("Device: ").append(deviceName);
         sbuf.append("\n address: ").append(deviceAddress);
         sbuf.append("\n wps: ").append(wpsConfig);
         sbuf.append("\n groupOwnerIntent: ").append(groupOwnerIntent);
@@ -132,7 +128,6 @@
 
     /** Implement the Parcelable interface {@hide} */
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(deviceName);
         dest.writeString(deviceAddress);
         dest.writeParcelable(wpsConfig, flags);
         dest.writeInt(groupOwnerIntent);
@@ -144,7 +139,6 @@
         new Creator<WifiP2pConfig>() {
             public WifiP2pConfig createFromParcel(Parcel in) {
                 WifiP2pConfig config = new WifiP2pConfig();
-                config.deviceName = in.readString();
                 config.deviceAddress = in.readString();
                 config.wpsConfig = (WpsConfiguration) in.readParcelable(null);
                 config.groupOwnerIntent = in.readInt();
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index ca6e4d5..14246b4 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -69,7 +69,7 @@
     }
 
     /**
-     * @param string formats supported include
+     * @param supplicantEvent formats supported include
      *
      *  P2P-GROUP-STARTED p2p-wlan0-0 [client|GO] ssid="DIRECT-W8" freq=2437
      *  [psk=2182b2e50e53f260d04f3c7b25ef33c965a3291b9b36b455a82d77fd82ca15bc|
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index 9dc2fbf..a02175e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -34,9 +34,11 @@
 
     public InetAddress groupOwnerAddress;
 
-    public WifiP2pInfo() {
+    /** @hide */
+    WifiP2pInfo() {
     }
 
+    /** @hide */
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("groupFormed: ").append(groupFormed)
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 25daf1c..0bdd269 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -35,25 +35,64 @@
 import com.android.internal.util.Protocol;
 
 /**
- * This class provides the API for managing Wi-Fi p2p
- * connectivity. Get an instance of this class by calling
- * {@link android.content.Context#getSystemService(String)
+ * This class provides the API for managing Wi-Fi peer-to-peer connectivity. This lets an
+ * application discover available peers, setup connection to peers and query for the list of peers.
+ * When a p2p connection is formed over wifi, the device continues to maintain the uplink
+ * connection over mobile or any other available network for internet connectivity on the device.
+ *
+ * <p> The API is asynchronous and response to a request from an application is sent in the form
+ * of a {@link android.os.Message} on a {@link android.os.Handler} that needs to be initialized
+ * by the application right at the beginning before any p2p operations are performed via
+ * {@link #initialize}.
+ *
+ * <p> An application can request for the current list of peers using {@link #requestPeers}. The
+ * {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is available.
+ * Use {@link #peersInResponse} to extract the peer device list upon the receiving the
+ * {@link #RESPONSE_PEERS} message.
+ *
+ * <p> If an application needs to initiate a discovery, use {@link #discoverPeers} and listen
+ * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to initiate a request to fetch
+ * list of peers with {@link #requestPeers}. An initiated discovery request from an application
+ * stays active until the device starts connecting to a peer or forms a p2p group.
+ *
+ * <p> An application can initiate a connection request to a peer through {@link #connect}. See
+ * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
+ * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
+ * which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
+ *
+ * <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
+ * use {@link #requestConnectionInfo} to fetch the connection details. Connection information
+ * can be obtained with {@link #connectionInfoInResponse} on a {@link #RESPONSE_CONNECTION_INFO}
+ * message. The connection info {@link WifiP2pInfo} contains the address of the group owner
+ * {@link WifiP2pInfo#groupOwnerAddress} and a flag {@link #WifiP2pInfo#isGroupOwner} to indicate
+ * if the current device is a p2p group owner. A p2p client can thus communicate with
+ * the p2p group owner through a socket connection.
+ *
+ * <p> Android has no platform support for service discovery yet, so applications could
+ * run a service discovery protocol to discover services on the peer-to-peer netework.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * Registering an application handler with {@link #initialize} requires the permissions
+ * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
+ * {@link android.Manifest.permission#CHANGE_WIFI_STATE} to perform any further peer-to-peer
+ * operations.
+ *
+ * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
  * Context.getSystemService(Context.WIFI_P2P_SERVICE)}.
  *
- * It deals with the following:
- * <ul>
- * <li>Wi-Fi peer discovery and connection setup. Allows applications to initiate a discovery to
- * find available peers and then setup a connection </li>
- * <li>Configuration and status query. Allows applications to fetch the current list
- * of available and connected peers and query connection status </li>
- * <li>Intent actions that are broadcast to track operations
- * on a p2p connection</li>
- * </ul>
+ * {@see WifiP2pConfig}
+ * {@see WifiP2pInfo}
+ * {@see WifiP2pGroup}
+ * {@see WifiP2pDevice}
+ * {@see WifiP2pDeviceList}
  * @hide
  */
 public class WifiP2pManager {
     /**
-     * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled.
+     * Broadcast intent action to indicate whether Wi-Fi p2p is enabled or disabled. An
+     * extra {@link #EXTRA_WIFI_STATE} provides the state information as int.
+     *
+     * @see #EXTRA_WIFI_STATE
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_STATE_CHANGED_ACTION =
@@ -72,7 +111,6 @@
      * Wi-Fi p2p is disabled.
      *
      * @see #WIFI_P2P_STATE_CHANGED_ACTION
-     * @see #getWifiP2pState()
      */
     public static final int WIFI_P2P_STATE_DISABLED = 1;
 
@@ -80,14 +118,16 @@
      * Wi-Fi p2p is enabled.
      *
      * @see #WIFI_P2P_STATE_CHANGED_ACTION
-     * @see #getWifiP2pState()
      */
     public static final int WIFI_P2P_STATE_ENABLED = 2;
 
     /**
      * Broadcast intent action indicating that the state of Wi-Fi p2p connectivity
-     * has changed. One extra provides the new state
-     * in the form of a {@link android.net.NetworkInfo} object.
+     * has changed. One extra {@link #EXTRA_WIFI_P2P_INFO} provides the p2p connection info in
+     * the form of a {@link WifiP2pInfo} object. Another extra {@link #EXTRA_NETWORK_INFO} provides
+     * the network info in the form of a {@link android.net.NetworkInfo}.
+     *
+     * @see #EXTRA_WIFI_P2P_INFO
      * @see #EXTRA_NETWORK_INFO
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -124,7 +164,8 @@
     public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";
 
     /**
-     * Broadcast intent action indicating that the available peer list has changed
+     * Broadcast intent action indicating that the available peer list has changed. Fetch
+     * the changed list of peers with {@link #requestPeers}
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String WIFI_P2P_PEERS_CHANGED_ACTION =
@@ -134,6 +175,7 @@
      * Activity Action: Pick a Wi-Fi p2p network to connect to.
      * <p>Input: Nothing.
      * <p>Output: Nothing.
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PICK_WIFI_P2P_NETWORK =
@@ -141,47 +183,169 @@
 
     IWifiP2pManager mService;
 
-    /* AsyncChannel notifications to apps */
-    public static final int HANDLER_CONNECTION = AsyncChannel.CMD_CHANNEL_HALF_CONNECTED;
+    /**
+     * Message {@link android.os.Message#what} sent on the application handler specified
+     * at {@link #initialize} indicating the asynchronous channel has disconnected. An
+     * application could choose to reconnect with {@link #initialize}
+     */
     public static final int HANDLER_DISCONNECTION = AsyncChannel.CMD_CHANNEL_DISCONNECTED;
 
     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
 
+    /** @hide */
     public static final int ENABLE_P2P                              = BASE + 1;
+    /** @hide */
     public static final int ENABLE_P2P_FAILED                       = BASE + 2;
+    /** @hide */
     public static final int ENABLE_P2P_SUCCEEDED                    = BASE + 3;
 
+    /** @hide */
     public static final int DISABLE_P2P                             = BASE + 4;
+    /** @hide */
     public static final int DISABLE_P2P_FAILED                      = BASE + 5;
+    /** @hide */
     public static final int DISABLE_P2P_SUCCEEDED                   = BASE + 6;
 
+    /** @hide */
     public static final int DISCOVER_PEERS                          = BASE + 7;
+
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
+     * operation failed.
+     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+     * or {@link #ALREADY_IN_EFFECT}
+     */
     public static final int DISCOVER_PEERS_FAILED                   = BASE + 8;
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #discoverPeers}
+     * operation succeeded.
+     * <p> The application can register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent
+     * to listen for changes in the peer list as a result of the discovery process.
+     */
     public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 9;
 
+    /** @hide */
     public static final int CONNECT                                 = BASE + 10;
+
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #connect}
+     * operation failed.
+     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+     * or {@link #ALREADY_IN_EFFECT}
+     */
     public static final int CONNECT_FAILED                          = BASE + 11;
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #connect}
+     * operation succeeded.
+     * <p> The application can register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent
+     * to listen for connectivity change as a result of the connect operation
+     */
     public static final int CONNECT_SUCCEEDED                       = BASE + 12;
 
+    /** @hide */
     public static final int CREATE_GROUP                            = BASE + 13;
+
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
+     * operation failed.
+     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+     * or {@link #ALREADY_IN_EFFECT}
+     */
     public static final int CREATE_GROUP_FAILED                     = BASE + 14;
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #createGroup}
+     * operation succeeded.
+     * <p> The application can request the group details with {@link #requestGroupInfo}
+     */
     public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 15;
 
+    /** @hide */
     public static final int REMOVE_GROUP                            = BASE + 16;
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
+     * operation failed.
+     * <p> The reason for failure could be one of {@link #P2P_UNSUPPORTED}, {@link #P2P_DISABLED}
+     * or {@link #ALREADY_IN_EFFECT}
+     */
     public static final int REMOVE_GROUP_FAILED                     = BASE + 17;
+    /**
+     * Message {@link android.os.Message#what} value indicating that the {@link #removeGroup}
+     * operation succeeded.
+     */
     public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 18;
 
-    public static final int REQUEST_PEERS                           = BASE + 19;
-    public static final int RESPONSE_PEERS                          = BASE + 20;
-
-    public static final int REQUEST_CONNECTION_INFO                 = BASE + 21;
-    public static final int RESPONSE_CONNECTION_INFO                = BASE + 22;
-
-    /* arg1 values on response messages from the framework */
+    /**
+     * Supported {@link android.os.Message#arg1} value on the following response messages:
+     * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
+     * and {@link #REMOVE_GROUP_FAILED}
+     *
+     * <p> This indicates that the reason for failure is because p2p is unsupported on the
+     * device
+     */
     public static final int P2P_UNSUPPORTED     = 1;
 
+    /**
+     * Supported {@link android.os.Message#arg1} value on the following response messages:
+     * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
+     * and {@link #REMOVE_GROUP_FAILED}
+     *
+     * <p> This indicates that the reason for failure is because p2p is currently disabled
+     * by the user
+     */
+    public static final int P2P_DISABLED        = 2;
+
+    /**
+     * Supported {@link android.os.Message#arg1} value on the following response messages:
+     * {@link #DISCOVER_PEERS_FAILED}, {@link #CONNECT_FAILED}, {@link #CREATE_GROUP_FAILED}
+     * and {@link #REMOVE_GROUP_FAILED}
+     *
+     * <p> This indicates that the reason for failure is because the operation is already in
+     * effect
+     */
+    public static final int ALREADY_IN_EFFECT   = 3;
+
+
+    /** @hide */
+    public static final int REQUEST_PEERS                           = BASE + 19;
+    /**
+     * Message {@link android.os.Message#what} delivered on the application hander
+     * in response to a {@link #requestPeers} call from the application.
+     *
+     * <p> Extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
+     * on the message object
+     */
+    public static final int RESPONSE_PEERS                          = BASE + 20;
+
+    /** @hide */
+    public static final int REQUEST_CONNECTION_INFO                 = BASE + 21;
+
+    /**
+     * Message {@link android.os.Message#what} delivered on the application hander
+     * in response to a {@link #requestConnectionInfo} call from the application.
+     *
+     * <p> Extract a {@link WifiP2pInfo} object by calling {@link #connectionInfoInResponse}
+     * on the message object
+     */
+    public static final int RESPONSE_CONNECTION_INFO                = BASE + 22;
+
+    /** @hide */
+    public static final int REQUEST_GROUP_INFO                      = BASE + 23;
+
+    /**
+     * Message {@link android.os.Message#what} delivered on the application hander
+     * in response to a {@link #requestGroupInfo} call from the application.
+     *
+     * <p> Extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
+     * on the message object
+     */
+
+    public static final int RESPONSE_GROUP_INFO                     = BASE + 24;
+
+    /** @hide */
     public static final int WPS_PBC                                 = BASE + 23;
+    /** @hide */
     public static final int WPS_PIN                                 = BASE + 24;
+    /** @hide */
     public static final int WPS_PIN_AVAILABLE                       = BASE + 25;
 
     /**
@@ -199,7 +363,8 @@
 
     /**
      * A channel that connects the application handler to the Wifi framework.
-     * All p2p operations are performed on a channel.
+     * Most p2p operations require a Channel as an argument. An instance of Channel is obtained
+     * by doing a call on {@link #initialize}
      */
     public class Channel {
         Channel(AsyncChannel c) {
@@ -210,10 +375,17 @@
 
     /**
      * Registers the application handler with the Wi-Fi framework. This function
-     * must be the first to be called before any p2p control or query operations can be performed.
+     * must be the first to be called before any p2p operations are performed.
+     *
+     * <p class="note"><strong>Note:</strong>
+     * The handler registered with the framework should only handle messages
+     * with {@link android.os.Message#what} values defined in this file. Adding application
+     * specific private {@link android.os.Message#what} types should be done on a seperate handler
+     *
      * @param srcContext is the context of the source
-     * @param srcHandler is the handler on which the source receives messages
-     * @return Channel instance that is necessary for performing p2p operations
+     * @param srcHandler is the handler on which the source will receive message responses
+     * asynchronously
+     * @return Channel instance that is necessary for performing any further p2p operations
      */
     public Channel initialize(Context srcContext, Handler srcHandler) {
         Messenger messenger = getMessenger();
@@ -229,6 +401,7 @@
         }
     }
 
+    /** @hide */
     public boolean isP2pSupported() {
         try {
             return mService.isP2pSupported();
@@ -240,6 +413,7 @@
     /**
      * Sends in a request to the system to enable p2p. This will pop up a dialog
      * to the user and upon authorization will enable p2p.
+     * @hide
      */
     public void enableP2p(Channel c) {
         if (c == null) return;
@@ -249,6 +423,7 @@
     /**
      * Sends in a request to the system to disable p2p. This will pop up a dialog
      * to the user and upon authorization will enable p2p.
+     * @hide
      */
     public void disableP2p(Channel c) {
         if (c == null) return;
@@ -256,7 +431,22 @@
     }
 
     /**
-     * Initiates peer discovery
+     * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
+     * for the purpose of establishing a connection.
+     *
+     * <p> The function call immediately returns after sending a discovery request
+     * to the framework. The application handler is notified of a success or failure to initiate
+     * discovery with {@link #DISCOVER_PEERS_SUCCEEDED} or {@link #DISCOVER_PEERS_FAILED}.
+     *
+     * <p> The discovery remains active until a connection is initiated or
+     * a p2p group is formed. Register for {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent to
+     * determine when the framework notifies of a change as peers are discovered.
+     *
+     * <p> Upon receiving a {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent, an application
+     * can request for the list of peers using {@link #requestPeers} which will deliver a
+     * {@link #RESPONSE_PEERS} message on the application handler. The application can then
+     * extract a {@link WifiP2pDeviceList} object by calling {@link #peersInResponse}
+     * on the message.
      */
     public void discoverPeers(Channel c) {
         if (c == null) return;
@@ -264,9 +454,23 @@
     }
 
     /**
-     * Start a p2p connection
+     * Start a p2p connection to a device with the specified configuration.
      *
-     * @param peer Configuration described in a {@link WifiP2pConfig} object.
+     * <p> The function call immediately returns after sending a connection request
+     * to the framework. The application handler is notified of a success or failure to initiate
+     * connectivity with {@link #CONNECT_SUCCEEDED} or {@link #CONNECT_FAILED}.
+     *
+     * <p> Register for {@link #WIFI_P2P_CONNECTION_CHANGED_ACTION} intent to
+     * determine when the framework notifies of a change in connectivity.
+     *
+     * <p> If the current device is not part of a p2p group, a connect request initiates
+     * a group negotiation with the peer.
+     *
+     * <p> If the current device is part of an existing p2p group or has created
+     * a p2p group with {@link #createGroup}, an invitation to join the group is sent to
+     * the peer device.
+     *
+     * @param config options as described in {@link WifiP2pConfig} class.
      */
     public void connect(Channel c, WifiP2pConfig config) {
         if (c == null) return;
@@ -274,8 +478,20 @@
     }
 
     /**
-     * Create a p2p group. This is essentially an access point that can accept
-     * client connections.
+     * Create a p2p group with the current device as the group owner. This essentially creates
+     * an access point that can accept connections from legacy clients as well as other p2p
+     * devices.
+     * <p> For p2p operation, this would normally not be used unless the current device needs
+     * to form a p2p connection with a legacy client
+     *
+     * <p> The function call immediately returns after sending a group creation request
+     * to the framework. The application handler is notified of a success or failure to create
+     * group with {@link #CREATE_GROUP_SUCCEEDED} or {@link #CREATE_GROUP_FAILED}.
+     *
+     * <p> Application can request for the group details with {@link #requestGroupInfo} which will
+     * deliver a {@link #RESPONSE_GROUP_INFO} message on the application handler. The application
+     * can then extract a {@link WifiP2pGroup} object by calling {@link #groupInfoInResponse}
+     * on the message.
      */
     public void createGroup(Channel c) {
         if (c == null) return;
@@ -283,8 +499,11 @@
     }
 
     /**
-     * Remove the current group. This also removes the p2p interface created
-     * during group formation.
+     * Remove the current p2p group.
+     *
+     * <p> The function call immediately returns after sending a group removal request
+     * to the framework. The application handler is notified of a success or failure to remove
+     * a group with {@link #REMOVE_GROUP_SUCCEEDED} or {@link #REMOVE_GROUP_FAILED}.
      */
     public void removeGroup(Channel c) {
         if (c == null) return;
@@ -292,8 +511,9 @@
     }
 
     /**
-     * Request the list of peers. This returns a RESPONSE_PEERS on the source
-     * handler.
+     * Request the current list of peers. This returns a {@link #RESPONSE_PEERS} on the application
+     * handler. The {@link #RESPONSE_PEERS} message on the handler indicates that the peer list is
+     * available. Use {@link #peersInResponse} to extract {@link WifiP2pDeviceList} from the message
      */
     public void requestPeers(Channel c) {
         if (c == null) return;
@@ -301,15 +521,18 @@
     }
 
     /**
-     * Fetch device list from a RESPONSE_PEERS message
+     * Upon receiving a {@link #RESPONSE_PEERS} on the application handler, an application
+     * can extract the peer device list using this function.
      */
     public WifiP2pDeviceList peersInResponse(Message msg) {
         return (WifiP2pDeviceList) msg.obj;
     }
 
     /**
-     * Request device connection info. This returns a RESPONSE_CONNECTION_INFO on
-     * the source handler.
+     * Request device connection info. This returns a {@link #RESPONSE_CONNECTION_INFO} on
+     * the application handler. The {@link #RESPONSE_CONNECTION_INFO} message on the handler
+     * indicates that connection info is available. Use {@link #connectionInfoInResponse} to
+     * extract {@link WifiP2pInfo} from the message.
      */
     public void requestConnectionInfo(Channel c) {
         if (c == null) return;
@@ -317,12 +540,31 @@
     }
 
     /**
-     * Fetch p2p connection status from a RESPONSE_CONNECTION_INFO message
+     * Upon receiving a {@link #RESPONSE_CONNECTION_INFO} on the application handler, an application
+     * can extract the connection info using this function.
      */
     public WifiP2pInfo connectionInfoInResponse(Message msg) {
         return (WifiP2pInfo) msg.obj;
     }
 
+    /**
+     * Request p2p group info. This returns a {@link #RESPONSE_GROUP_INFO} on
+     * the application handler. The {@link #RESPONSE_GROUP_INFO} message on the handler
+     * indicates that group info is available. Use {@link #groupInfoInResponse} to
+     * extract {@link WifiP2pGroup} from the message.
+     */
+    public void requestGroupInfo(Channel c) {
+        if (c == null) return;
+        c.mAsyncChannel.sendMessage(REQUEST_GROUP_INFO);
+    }
+
+    /**
+     * Upon receiving a {@link #RESPONSE_GROUP_INFO} on the application handler, an application
+     * can extract the group info using this function.
+     */
+    public WifiP2pGroup groupInfoInResponse(Message msg) {
+        return (WifiP2pGroup) msg.obj;
+    }
 
     /**
      * Get a reference to WifiP2pService handler. This is used to establish
@@ -339,7 +581,6 @@
         }
     }
 
-
     /**
      * Setup DNS connectivity on the current process to the connected Wi-Fi p2p peers
      *