Merge "Change URI type metadata back to text" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 5710415..152760f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -602,6 +602,7 @@
     field public static final int focusableInTouchMode = 16842971; // 0x10100db
     field public static final int focusedMonthDateColor = 16843587; // 0x1010343
     field public static final int fontFamily = 16843692; // 0x10103ac
+    field public static final int fontFeatureSettings = 16843962; // 0x10104ba
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
@@ -711,6 +712,7 @@
     field public static final int innerRadiusRatio = 16843163; // 0x101019b
     field public static final deprecated int inputMethod = 16843112; // 0x1010168
     field public static final int inputType = 16843296; // 0x1010220
+    field public static final int inset = 16843960; // 0x10104b8
     field public static final int insetBottom = 16843194; // 0x10101ba
     field public static final int insetLeft = 16843191; // 0x10101b7
     field public static final int insetRight = 16843192; // 0x10101b8
@@ -836,6 +838,7 @@
     field public static final int layout_x = 16843135; // 0x101017f
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
+    field public static final int letterSpacing = 16843961; // 0x10104b9
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -2054,6 +2057,13 @@
     field public static final int TextAppearance_StatusBar_EventContent = 16973927; // 0x1030067
     field public static final int TextAppearance_StatusBar_EventContent_Title = 16973928; // 0x1030068
     field public static final int TextAppearance_StatusBar_Icon = 16973926; // 0x1030066
+    field public static final int TextAppearance_StatusBar_Material = 16974559; // 0x10302df
+    field public static final int TextAppearance_StatusBar_Material_EventContent = 16974560; // 0x10302e0
+    field public static final int TextAppearance_StatusBar_Material_EventContent_Emphasis = 16974565; // 0x10302e5
+    field public static final int TextAppearance_StatusBar_Material_EventContent_Info = 16974563; // 0x10302e3
+    field public static final int TextAppearance_StatusBar_Material_EventContent_Line2 = 16974562; // 0x10302e2
+    field public static final int TextAppearance_StatusBar_Material_EventContent_Time = 16974564; // 0x10302e4
+    field public static final int TextAppearance_StatusBar_Material_EventContent_Title = 16974561; // 0x10302e1
     field public static final int TextAppearance_StatusBar_Title = 16973925; // 0x1030065
     field public static final int TextAppearance_SuggestionHighlight = 16974104; // 0x1030118
     field public static final int TextAppearance_Theme = 16973888; // 0x1030040
@@ -8675,10 +8685,10 @@
     method public abstract void onSuccess();
     method public abstract void onUserActionRequired(android.content.Intent);
     field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+    field public static final int FAILURE_ABORTED = 5; // 0x5
     field public static final int FAILURE_CONFLICT = 2; // 0x2
     field public static final int FAILURE_INCOMPATIBLE = 4; // 0x4
     field public static final int FAILURE_INVALID = 1; // 0x1
-    field public static final int FAILURE_REJECTED = 5; // 0x5
     field public static final int FAILURE_STORAGE = 3; // 0x3
     field public static final int FAILURE_UNKNOWN = 0; // 0x0
   }
@@ -8705,9 +8715,12 @@
 
   public static abstract class PackageInstaller.UninstallCallback {
     ctor public PackageInstaller.UninstallCallback();
-    method public abstract void onFailure(java.lang.String);
+    method public abstract void onFailure(int, java.lang.String, android.os.Bundle);
     method public abstract void onSuccess();
     method public abstract void onUserActionRequired(android.content.Intent);
+    field public static final int FAILURE_ABORTED = 2; // 0x2
+    field public static final int FAILURE_BLOCKED = 1; // 0x1
+    field public static final int FAILURE_UNKNOWN = 0; // 0x0
   }
 
   public class PackageItemInfo {
@@ -11027,12 +11040,14 @@
     method public android.graphics.ColorFilter getColorFilter();
     method public boolean getFillPath(android.graphics.Path, android.graphics.Path);
     method public int getFlags();
+    method public java.lang.String getFontFeatureSettings();
     method public float getFontMetrics(android.graphics.Paint.FontMetrics);
     method public android.graphics.Paint.FontMetrics getFontMetrics();
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
     method public float getFontSpacing();
     method public int getHinting();
+    method public float getLetterSpacing();
     method public android.graphics.MaskFilter getMaskFilter();
     method public android.graphics.PathEffect getPathEffect();
     method public deprecated android.graphics.Rasterizer getRasterizer();
@@ -11082,7 +11097,9 @@
     method public void setFakeBoldText(boolean);
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
+    method public void setFontFeatureSettings(java.lang.String);
     method public void setHinting(int);
+    method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
     method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
@@ -15133,6 +15150,7 @@
     method public boolean containsKey(java.lang.String);
     method public int describeContents();
     method public android.graphics.Bitmap getBitmap(java.lang.String);
+    method public android.media.MediaMetadata.Description getDescription();
     method public long getLong(java.lang.String);
     method public android.media.Rating getRating(java.lang.String);
     method public java.lang.String getString(java.lang.String);
@@ -15180,6 +15198,14 @@
     method public android.media.MediaMetadata.Builder putText(java.lang.String, java.lang.CharSequence);
   }
 
+  public final class MediaMetadata.Description {
+    method public java.lang.CharSequence getDescription();
+    method public android.graphics.Bitmap getIcon();
+    method public android.net.Uri getIconUri();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+  }
+
   public abstract deprecated class MediaMetadataEditor {
     method public synchronized void addEditableKey(int);
     method public abstract void apply();
@@ -28599,6 +28625,7 @@
     method public void swapWithBackgroundCall();
     method public void unhold();
     field public static final int STATE_ACTIVE = 4; // 0x4
+    field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
     field public static final int STATE_DISCONNECTED = 7; // 0x7
     field public static final int STATE_HOLDING = 3; // 0x3
@@ -28691,6 +28718,7 @@
     method public static android.telecomm.CallState valueOf(java.lang.String);
     method public static final android.telecomm.CallState[] values();
     enum_constant public static final android.telecomm.CallState ACTIVE;
+    enum_constant public static final android.telecomm.CallState CONNECTING;
     enum_constant public static final android.telecomm.CallState DIALING;
     enum_constant public static final android.telecomm.CallState DISCONNECTED;
     enum_constant public static final android.telecomm.CallState NEW;
@@ -35535,6 +35563,7 @@
     method public int getSystemWindowInsetTop();
     method public boolean hasInsets();
     method public boolean hasSystemWindowInsets();
+    method public boolean isConsumed();
     method public boolean isRound();
     method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
   }
@@ -39656,6 +39685,7 @@
     method public int getExtendedPaddingBottom();
     method public int getExtendedPaddingTop();
     method public android.text.InputFilter[] getFilters();
+    method public java.lang.String getFontFeatureSettings();
     method public boolean getFreezesText();
     method public int getGravity();
     method public int getHighlightColor();
@@ -39669,6 +39699,7 @@
     method public int getInputType();
     method public final android.text.method.KeyListener getKeyListener();
     method public final android.text.Layout getLayout();
+    method public float getLetterSpacing();
     method public int getLineBounds(int, android.graphics.Rect);
     method public int getLineCount();
     method public int getLineHeight();
@@ -39752,6 +39783,7 @@
     method public void setError(java.lang.CharSequence, android.graphics.drawable.Drawable);
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
+    method public void setFontFeatureSettings(java.lang.String);
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -39768,6 +39800,7 @@
     method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public void setInputType(int);
     method public void setKeyListener(android.text.method.KeyListener);
+    method public void setLetterSpacing(float);
     method public void setLineSpacing(float, float);
     method public void setLines(int);
     method public final void setLinkTextColor(int);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 84b5516..a935dc0 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -28,7 +28,6 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstallObserver;
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
@@ -53,7 +52,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
@@ -1655,39 +1653,6 @@
                 new UserHandle(mContext.getUserId()));
     }
 
-    private static class LegacyPackageInstallObserver extends PackageInstallObserver {
-        private final IPackageInstallObserver mLegacy;
-
-        public LegacyPackageInstallObserver(IPackageInstallObserver legacy) {
-            mLegacy = legacy;
-        }
-
-        @Override
-        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
-                Bundle extras) {
-            try {
-                mLegacy.packageInstalled(basePackageName, returnCode);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
-    private static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
-        private final IPackageDeleteObserver mLegacy;
-
-        public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
-            mLegacy = legacy;
-        }
-
-        @Override
-        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
-            try {
-                mLegacy.packageDeleted(basePackageName, returnCode);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
-
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/app/backup/RestoreObserver.java b/core/java/android/app/backup/RestoreObserver.java
index dbddb78..b4a23d0 100644
--- a/core/java/android/app/backup/RestoreObserver.java
+++ b/core/java/android/app/backup/RestoreObserver.java
@@ -17,6 +17,8 @@
 package android.app.backup;
 
 import java.lang.String;
+
+import android.annotation.SystemApi;
 import android.app.backup.RestoreSet;
 
 /**
@@ -36,6 +38,7 @@
      *
      * @hide
      */
+    @SystemApi
     public void restoreSetsAvailable(RestoreSet[] result) {
     }
 
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index edf823e..7070bae 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -21,6 +21,7 @@
 import android.bluetooth.le.AdvertiseData;
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanSettings;
+import android.bluetooth.le.ResultStorageDescriptor;
 import android.os.ParcelUuid;
 
 import android.bluetooth.IBluetoothGattCallback;
@@ -34,7 +35,8 @@
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
 
     void startScan(in int appIf, in boolean isServer, in ScanSettings settings,
-                   in List<ScanFilter> filters);
+                   in List<ScanFilter> filters,
+                   in List scanStorages);
     void stopScan(in int appIf, in boolean isServer);
     void flushPendingBatchResults(in int appIf, in boolean isServer);
     void startMultiAdvertising(in int appIf,
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 6667cc4..7c3cbc6 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -16,20 +16,19 @@
 
 package android.bluetooth.le;
 
+import android.annotation.SystemApi;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothGatt;
 import android.bluetooth.BluetoothGattCallbackWrapper;
 import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -100,6 +99,11 @@
      */
     public void startScan(List<ScanFilter> filters, ScanSettings settings,
             final ScanCallback callback) {
+        startScan(filters, settings, callback, null);
+    }
+
+    private void startScan(List<ScanFilter> filters, ScanSettings settings,
+            final ScanCallback callback, List<List<ResultStorageDescriptor>> resultStorages) {
         checkAdapterState();
         if (settings == null || callback == null) {
             throw new IllegalArgumentException("settings or callback is null");
@@ -125,7 +129,7 @@
                 return;
             }
             BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
-                    settings, callback);
+                    settings, callback, resultStorages);
             try {
                 UUID uuid = UUID.randomUUID();
                 gatt.registerClient(new ParcelUuid(uuid), wrapper);
@@ -155,7 +159,8 @@
         synchronized (mLeScanClients) {
             BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
             if (wrapper == null) {
-                if (DBG) Log.d(TAG, "could not find callback wrapper");
+                if (DBG)
+                    Log.d(TAG, "could not find callback wrapper");
                 return;
             }
             wrapper.stopLeScan();
@@ -185,6 +190,25 @@
     }
 
     /**
+     * Start truncated scan.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
+            final ScanCallback callback) {
+        int filterSize = truncatedFilters.size();
+        List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize);
+        List<List<ResultStorageDescriptor>> scanStorages =
+                new ArrayList<List<ResultStorageDescriptor>>(filterSize);
+        for (TruncatedFilter filter : truncatedFilters) {
+            scanFilters.add(filter.getFilter());
+            scanStorages.add(filter.getStorageDescriptors());
+        }
+        startScan(scanFilters, settings, callback, scanStorages);
+    }
+
+    /**
      * Bluetooth GATT interface callbacks
      */
     private static class BleScanCallbackWrapper extends BluetoothGattCallbackWrapper {
@@ -194,6 +218,7 @@
         private final List<ScanFilter> mFilters;
         private ScanSettings mSettings;
         private IBluetoothGatt mBluetoothGatt;
+        private List<List<ResultStorageDescriptor>> mResultStorages;
 
         // mLeHandle 0: not registered
         // -1: scan stopped
@@ -202,12 +227,13 @@
 
         public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
                 List<ScanFilter> filters, ScanSettings settings,
-                ScanCallback scanCallback) {
+                ScanCallback scanCallback, List<List<ResultStorageDescriptor>> resultStorages) {
             mBluetoothGatt = bluetoothGatt;
             mFilters = filters;
             mSettings = settings;
             mScanCallback = scanCallback;
             mClientIf = 0;
+            mResultStorages = resultStorages;
         }
 
         public boolean scanStarted() {
@@ -272,7 +298,8 @@
                 if (status == BluetoothGatt.GATT_SUCCESS) {
                     mClientIf = clientIf;
                     try {
-                        mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters);
+                        mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters,
+                                mResultStorages);
                     } catch (RemoteException e) {
                         Log.e(TAG, "fail to start le scan: " + e);
                         mClientIf = -1;
@@ -330,23 +357,26 @@
 
             // Check null in case the scan has been stopped
             synchronized (this) {
-                if (mClientIf <= 0) return;
+                if (mClientIf <= 0)
+                    return;
             }
             Handler handler = new Handler(Looper.getMainLooper());
             handler.post(new Runnable() {
                     @Override
                 public void run() {
                     if (onFound) {
-                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, scanResult);
+                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH,
+                                scanResult);
                     } else {
-                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, scanResult);
+                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST,
+                                scanResult);
                     }
                 }
             });
         }
     }
 
-    //TODO: move this api to a common util class.
+    // TODO: move this api to a common util class.
     private void checkAdapterState() {
         if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) {
             throw new IllegalStateException("BT Adapter is not turned ON");
diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.aidl b/core/java/android/bluetooth/le/ResultStorageDescriptor.aidl
new file mode 100644
index 0000000..f218a01
--- /dev/null
+++ b/core/java/android/bluetooth/le/ResultStorageDescriptor.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 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.bluetooth.le;
+
+/**
+ * {@hide}
+ */
+
+parcelable ResultStorageDescriptor;
diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.java b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
new file mode 100644
index 0000000..748f97d
--- /dev/null
+++ b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 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.bluetooth.le;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the way to store scan result.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ResultStorageDescriptor implements Parcelable {
+    private int mType;
+    private int mOffset;
+    private int mLength;
+
+    public int getType() {
+        return mType;
+    }
+
+    public int getOffset() {
+        return mOffset;
+    }
+
+    public int getLength() {
+        return mLength;
+    }
+
+    /**
+     * Constructor of {@link ResultStorageDescriptor}
+     *
+     * @param type Type of the data.
+     * @param offset Offset from start of the advertise packet payload.
+     * @param length Byte length of the data
+     */
+    public ResultStorageDescriptor(int type, int offset, int length) {
+        mType = type;
+        mOffset = offset;
+        mLength = length;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mOffset);
+        dest.writeInt(mLength);
+    }
+
+    private ResultStorageDescriptor(Parcel in) {
+        ReadFromParcel(in);
+    }
+
+    private void ReadFromParcel(Parcel in) {
+        mType = in.readInt();
+        mOffset = in.readInt();
+        mLength = in.readInt();
+    }
+
+    public static final Parcelable.Creator<ResultStorageDescriptor>
+            CREATOR = new Creator<ResultStorageDescriptor>() {
+                    @Override
+                public ResultStorageDescriptor createFromParcel(Parcel source) {
+                    return new ResultStorageDescriptor(source);
+                }
+
+                    @Override
+                public ResultStorageDescriptor[] newArray(int size) {
+                    return new ResultStorageDescriptor[size];
+                }
+            };
+}
diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java
new file mode 100644
index 0000000..6a6b3e3
--- /dev/null
+++ b/core/java/android/bluetooth/le/TruncatedFilter.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 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.bluetooth.le;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * A special scan filter that lets the client decide how the scan record should be stored.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TruncatedFilter {
+    private final ScanFilter mFilter;
+    private final List<ResultStorageDescriptor> mStorageDescriptors;
+
+    /**
+     * Constructor for {@link TruncatedFilter}.
+     *
+     * @param filter Scan filter of the truncated filter.
+     * @param storageDescriptors Describes how the scan should be stored.
+     */
+    public TruncatedFilter(ScanFilter filter, List<ResultStorageDescriptor> storageDescriptors) {
+        mFilter = filter;
+        mStorageDescriptors = storageDescriptors;
+    }
+
+    /**
+     * Returns the scan filter.
+     */
+    public ScanFilter getFilter() {
+        return mFilter;
+    }
+
+    /**
+     * Returns a list of descriptor for scan result storage.
+     */
+    public List<ResultStorageDescriptor> getStorageDescriptors() {
+        return mStorageDescriptors;
+    }
+
+
+}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 525142b..d70e22c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -92,6 +92,9 @@
      */
     public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
 
+    /** {@hide} */
+    public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
+
     private final PackageManager mPm;
     private final IPackageInstaller mInstaller;
     private final int mUserId;
@@ -554,6 +557,26 @@
      */
     public static abstract class UninstallCallback {
         /**
+         * Generic unknown failure. The system will always try to provide a more
+         * specific failure reason, but in some rare cases this may be
+         * delivered.
+         */
+        public static final int FAILURE_UNKNOWN = 0;
+
+        /**
+         * This uninstall was blocked. The package may be required for core
+         * system operation, or the user may be restricted. Attempting to
+         * uninstall again will have the same result.
+         */
+        public static final int FAILURE_BLOCKED = 1;
+
+        /**
+         * This uninstall was actively aborted. For example, the user declined
+         * to uninstall. You may try to uninstall again.
+         */
+        public static final int FAILURE_ABORTED = 2;
+
+        /**
          * User action is required to proceed. You can start the given intent
          * activity to involve the user and continue.
          * <p>
@@ -564,7 +587,7 @@
         public abstract void onUserActionRequired(Intent intent);
 
         public abstract void onSuccess();
-        public abstract void onFailure(String msg);
+        public abstract void onFailure(int failureReason, String msg, Bundle extras);
     }
 
     /** {@hide} */
@@ -585,8 +608,9 @@
             if (returnCode == PackageManager.DELETE_SUCCEEDED) {
                 target.onSuccess();
             } else {
+                final int failureReason = PackageManager.deleteStatusToFailureReason(returnCode);
                 msg = PackageManager.deleteStatusToString(returnCode) + ": " + msg;
-                target.onFailure(msg);
+                target.onFailure(failureReason, msg, null);
             }
         }
     }
@@ -639,13 +663,13 @@
         public static final int FAILURE_INCOMPATIBLE = 4;
 
         /**
-         * This install session failed because it was rejected. For example, the
-         * user declined requested permissions, or a package verifier rejected
-         * the session.
+         * This install session failed because it was actively aborted. For
+         * example, the user declined requested permissions, or a verifier
+         * rejected the session.
          *
          * @see PackageManager#VERIFICATION_REJECT
          */
-        public static final int FAILURE_REJECTED = 5;
+        public static final int FAILURE_ABORTED = 5;
 
         public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d5604cb..b957a15 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -21,6 +21,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
+import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.PackageInstaller.CommitCallback;
+import android.content.pm.PackageInstaller.UninstallCallback;
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -35,6 +37,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.AndroidException;
 
@@ -771,7 +774,7 @@
     public static final int NO_NATIVE_LIBRARIES = -114;
 
     /** {@hide} */
-    public static final int INSTALL_FAILED_REJECTED = -115;
+    public static final int INSTALL_FAILED_ABORTED = -115;
 
     /**
      * Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
@@ -845,7 +848,10 @@
      *
      * @hide
      */
-    public static final int DELETE_FAILED_OWNER_BLOCKED= -4;
+    public static final int DELETE_FAILED_OWNER_BLOCKED = -4;
+
+    /** {@hide} */
+    public static final int DELETE_FAILED_ABORTED = -5;
 
     /**
      * Return code that is passed to the {@link IPackageMoveObserver} by
@@ -3833,7 +3839,7 @@
             case INSTALL_FAILED_USER_RESTRICTED: return "INSTALL_FAILED_USER_RESTRICTED";
             case INSTALL_FAILED_DUPLICATE_PERMISSION: return "INSTALL_FAILED_DUPLICATE_PERMISSION";
             case INSTALL_FAILED_NO_MATCHING_ABIS: return "INSTALL_FAILED_NO_MATCHING_ABIS";
-            case INSTALL_FAILED_REJECTED: return "INSTALL_FAILED_REJECTED";
+            case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
             default: return Integer.toString(status);
         }
     }
@@ -3861,8 +3867,8 @@
             case INSTALL_FAILED_CONTAINER_ERROR: return CommitCallback.FAILURE_STORAGE;
             case INSTALL_FAILED_INVALID_INSTALL_LOCATION: return CommitCallback.FAILURE_STORAGE;
             case INSTALL_FAILED_MEDIA_UNAVAILABLE: return CommitCallback.FAILURE_STORAGE;
-            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_REJECTED;
-            case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_REJECTED;
+            case INSTALL_FAILED_VERIFICATION_TIMEOUT: return CommitCallback.FAILURE_ABORTED;
+            case INSTALL_FAILED_VERIFICATION_FAILURE: return CommitCallback.FAILURE_ABORTED;
             case INSTALL_FAILED_PACKAGE_CHANGED: return CommitCallback.FAILURE_INVALID;
             case INSTALL_FAILED_UID_CHANGED: return CommitCallback.FAILURE_INVALID;
             case INSTALL_FAILED_VERSION_DOWNGRADE: return CommitCallback.FAILURE_INVALID;
@@ -3880,7 +3886,7 @@
             case INSTALL_FAILED_USER_RESTRICTED: return CommitCallback.FAILURE_INCOMPATIBLE;
             case INSTALL_FAILED_DUPLICATE_PERMISSION: return CommitCallback.FAILURE_CONFLICT;
             case INSTALL_FAILED_NO_MATCHING_ABIS: return CommitCallback.FAILURE_INCOMPATIBLE;
-            case INSTALL_FAILED_REJECTED: return CommitCallback.FAILURE_REJECTED;
+            case INSTALL_FAILED_ABORTED: return CommitCallback.FAILURE_ABORTED;
             default: return CommitCallback.FAILURE_UNKNOWN;
         }
     }
@@ -3893,7 +3899,57 @@
             case DELETE_FAILED_DEVICE_POLICY_MANAGER: return "DELETE_FAILED_DEVICE_POLICY_MANAGER";
             case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED";
             case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED";
+            case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED";
             default: return Integer.toString(status);
         }
     }
+
+    /** {@hide} */
+    public static int deleteStatusToFailureReason(int status) {
+        switch (status) {
+            case DELETE_FAILED_INTERNAL_ERROR: return UninstallCallback.FAILURE_UNKNOWN;
+            case DELETE_FAILED_DEVICE_POLICY_MANAGER: return UninstallCallback.FAILURE_BLOCKED;
+            case DELETE_FAILED_USER_RESTRICTED: return UninstallCallback.FAILURE_BLOCKED;
+            case DELETE_FAILED_OWNER_BLOCKED: return UninstallCallback.FAILURE_BLOCKED;
+            case DELETE_FAILED_ABORTED: return UninstallCallback.FAILURE_ABORTED;
+            default: return UninstallCallback.FAILURE_UNKNOWN;
+        }
+    }
+
+    /** {@hide} */
+    public static class LegacyPackageInstallObserver extends PackageInstallObserver {
+        private final IPackageInstallObserver mLegacy;
+
+        public LegacyPackageInstallObserver(IPackageInstallObserver legacy) {
+            mLegacy = legacy;
+        }
+
+        @Override
+        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+                Bundle extras) {
+            if (mLegacy == null) return;
+            try {
+                mLegacy.packageInstalled(basePackageName, returnCode);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    /** {@hide} */
+    public static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
+        private final IPackageDeleteObserver mLegacy;
+
+        public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
+            mLegacy = legacy;
+        }
+
+        @Override
+        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+            if (mLegacy == null) return;
+            try {
+                mLegacy.packageDeleted(basePackageName, returnCode);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
 }
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 900b41d..3c290f7 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -233,7 +233,7 @@
             }
 
             if (alphaRes != 0) {
-                alpha = r.getFraction(alphaRes, 1, 1);
+                alpha = r.getFloat(alphaRes);
             }
 
             // Apply alpha modulation.
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 5face69..52d1c79 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -986,6 +986,34 @@
     }
 
     /**
+     * Retrieve a floating-point value for a particular resource ID.
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     *
+     * @return Returns the floating-point value contained in the resource.
+     *
+     * @throws NotFoundException Throws NotFoundException if the given ID does
+     *         not exist or is not a floating-point value.
+     * @hide Pending API council approval.
+     */
+    public float getFloat(int id) {
+        synchronized (mAccessLock) {
+            TypedValue value = mTmpValue;
+            if (value == null) {
+                mTmpValue = value = new TypedValue();
+            }
+            getValue(id, value, true);
+            if (value.type == TypedValue.TYPE_FLOAT) {
+                return value.getFloat();
+            }
+            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) + " type #0x"
+                    + Integer.toHexString(value.type) + " is not valid");
+        }
+    }
+
+    /**
      * Return an XmlResourceParser through which you can read a view layout
      * description for the given resource ID.  This parser has limited
      * functionality -- in particular, you can't change its input, and only
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ba79f91..7d086e1 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -159,7 +159,7 @@
     private static final long BYTES_PER_MB = 1048576; // 1024^2
     private static final long BYTES_PER_GB = 1073741824; //1024^3
     
-
+    private static final String VERSION_DATA = "vers";
     private static final String UID_DATA = "uid";
     private static final String APK_DATA = "apk";
     private static final String PROCESS_DATA = "pr";
@@ -1463,6 +1463,21 @@
     public abstract long getStartClockTime();
 
     /**
+     * Return platform version tag that we were running in when the battery stats started.
+     */
+    public abstract String getStartPlatformVersion();
+
+    /**
+     * Return platform version tag that we were running in when the battery stats ended.
+     */
+    public abstract String getEndPlatformVersion();
+
+    /**
+     * Return the internal version code of the parcelled format.
+     */
+    public abstract int getParcelVersion();
+
+    /**
      * Return whether we are currently running on battery.
      */
     public abstract boolean getIsOnBattery();
@@ -2008,7 +2023,8 @@
         } else {
             dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
                     getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
-                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+                    getDischargeAmountScreenOnSinceCharge(),
+                    getDischargeAmountScreenOffSinceCharge());
         }
         
         if (reqUid < 0) {
@@ -3876,6 +3892,9 @@
             if (didPid) {
                 pw.println();
             }
+        }
+
+        if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
             if (dumpDurationSteps(pw, "Discharge step durations:", getDischargeStepDurationsArray(),
                     getNumDischargeStepDurations(), false)) {
                 long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
@@ -3896,9 +3915,6 @@
                 }
                 pw.println();
             }
-        }
-
-        if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
             pw.println("Statistics since last charge:");
             pw.println("  System starts: " + getStartCount()
                     + ", currently on battery: " + getIsOnBattery());
@@ -3915,7 +3931,10 @@
     public void dumpCheckinLocked(Context context, PrintWriter pw,
             List<ApplicationInfo> apps, int flags, long histStart) {
         prepareForDumpLocked();
-        
+
+        dumpLine(pw, 0 /* uid */, "i" /* category */, VERSION_DATA,
+                "10", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
+
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
 
         final boolean filtering =
@@ -3976,7 +3995,7 @@
                 }
             }
         }
-        if (!filtering) {
+        if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
             dumpDurationSteps(pw, DISCHARGE_STEP_DATA, getDischargeStepDurationsArray(),
                     getNumDischargeStepDurations(), true);
             String[] lineArgs = new String[1];
@@ -3994,8 +4013,6 @@
                 dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA,
                         (Object[])lineArgs);
             }
-        }
-        if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
             dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1);
         }
         if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 328d67c..8c2048d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4649,16 +4649,18 @@
      *         otherwise is returned.
      */
     public boolean performClick() {
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
-
-        ListenerInfo li = mListenerInfo;
+        final boolean result;
+        final ListenerInfo li = mListenerInfo;
         if (li != null && li.mOnClickListener != null) {
             playSoundEffect(SoundEffectConstants.CLICK);
             li.mOnClickListener.onClick(this);
-            return true;
+            result = true;
+        } else {
+            result = false;
         }
 
-        return false;
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+        return result;
     }
 
     /**
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 1832cc3..571a8f0 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -266,7 +266,6 @@
      * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
      *
      * @return true if the insets have been fully consumed.
-     * @hide Pending API
      */
     public boolean isConsumed() {
         return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 33cc66e..d263625 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -351,6 +351,7 @@
         final int selectedPosition = mSelectedPosition;
 
         View child = null;
+        final int nextChildDir = isLayoutRtl ? -1 : +1;
         for (int pos = startPos; pos < last; pos++) {
             // is this the selected item?
             boolean selected = pos == selectedPosition;
@@ -359,9 +360,9 @@
             final int where = flow ? -1 : pos - startPos;
             child = makeAndAddView(pos, y, flow, nextLeft, selected, where);
 
-            nextLeft += (isLayoutRtl ? -1 : +1) * columnWidth;
+            nextLeft += nextChildDir * columnWidth;
             if (pos < last - 1) {
-                nextLeft += horizontalSpacing;
+                nextLeft += nextChildDir * horizontalSpacing;
             }
 
             if (selected && (hasFocus || inClick)) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a0f7baf..b162e54 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.R;
+import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
@@ -222,6 +223,8 @@
  * @attr ref android.R.styleable#TextView_imeActionId
  * @attr ref android.R.styleable#TextView_editorExtras
  * @attr ref android.R.styleable#TextView_elegantTextHeight
+ * @attr ref android.R.styleable#TextView_letterSpacing
+ * @attr ref android.R.styleable#TextView_fontFeatureSettings
  */
 @RemoteView
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -2702,7 +2705,6 @@
      *
      * @see #setLetterSpacing(float)
      * @see Paint#setLetterSpacing
-     * @hide
      */
     public float getLetterSpacing() {
         return mTextPaint.getLetterSpacing();
@@ -2716,7 +2718,6 @@
      * @see Paint#getLetterSpacing
      *
      * @attr ref android.R.styleable#TextView_letterSpacing
-     * @hide
      */
     @android.view.RemotableViewMethod
     public void setLetterSpacing(float letterSpacing) {
@@ -2736,8 +2737,8 @@
      *
      * @see #setFontFeatureSettings(String)
      * @see Paint#setFontFeatureSettings
-     * @hide
      */
+    @Nullable
     public String getFontFeatureSettings() {
         return mTextPaint.getFontFeatureSettings();
     }
@@ -2747,14 +2748,14 @@
      * font-feature-settings attribute:
      * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
      *
+     * @param fontFeatureSettings font feature settings represented as CSS compatible string
      * @see #getFontFeatureSettings()
      * @see Paint#getFontFeatureSettings
      *
      * @attr ref android.R.styleable#TextView_fontFeatureSettings
-     * @hide
      */
     @android.view.RemotableViewMethod
-    public void setFontFeatureSettings(String fontFeatureSettings) {
+    public void setFontFeatureSettings(@Nullable String fontFeatureSettings) {
         if (fontFeatureSettings != mTextPaint.getFontFeatureSettings()) {
             mTextPaint.setFontFeatureSettings(fontFeatureSettings);
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 50b86d0..ee0d14b 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -29,6 +29,7 @@
 import android.os.BadParcelableException;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
+import android.os.Build;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
@@ -91,7 +92,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 112 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 113 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -233,6 +234,8 @@
     int mStartCount;
 
     long mStartClockTime;
+    String mStartPlatformVersion;
+    String mEndPlatformVersion;
 
     long mUptime;
     long mUptimeStart;
@@ -341,7 +344,7 @@
     int mDischargeAmountScreenOff;
     int mDischargeAmountScreenOffSinceCharge;
 
-    static final int MAX_LEVEL_STEPS = 100;
+    static final int MAX_LEVEL_STEPS = 200;
 
     int mInitStepMode = 0;
     int mCurStepMode = 0;
@@ -2840,8 +2843,6 @@
                 }
             }
 
-            mInitStepMode = mCurStepMode;
-            mModStepMode = 0;
             if (state == Display.STATE_ON) {
                 // Screen turning on.
                 final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3928,6 +3929,18 @@
         return mStartClockTime;
     }
 
+    @Override public String getStartPlatformVersion() {
+        return mStartPlatformVersion;
+    }
+
+    @Override public String getEndPlatformVersion() {
+        return mEndPlatformVersion;
+    }
+
+    @Override public int getParcelVersion() {
+        return VERSION;
+    }
+
     @Override public boolean getIsOnBattery() {
         return mOnBattery;
     }
@@ -4592,6 +4605,7 @@
                     proc.detach();
                     mProcessStats.removeAt(ip);
                 } else {
+                    proc.reset();
                     active = true;
                 }
             }
@@ -4848,7 +4862,7 @@
             mProcessStats.clear();
             for (int k = 0; k < numProcs; k++) {
                 String processName = in.readString();
-                Uid.Proc proc = new Proc();
+                Uid.Proc proc = new Proc(processName);
                 proc.readFromParcelLocked(in);
                 mProcessStats.put(processName, proc);
             }
@@ -5097,6 +5111,11 @@
          */
         public final class Proc extends BatteryStats.Uid.Proc implements TimeBaseObs {
             /**
+             * The name of this process.
+             */
+            final String mName;
+
+            /**
              * Remains true until removed from the stats.
              */
             boolean mActive = true;
@@ -5190,7 +5209,8 @@
 
             ArrayList<ExcessivePower> mExcessivePower;
 
-            Proc() {
+            Proc(String name) {
+                mName = name;
                 mOnBatteryTimeBase.add(this);
                 mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
             }
@@ -5205,6 +5225,24 @@
             public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             }
 
+            void reset() {
+                mUserTime = mSystemTime = mForegroundTime = 0;
+                mStarts = 0;
+                mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
+                mLoadedStarts = 0;
+                mLastUserTime = mLastSystemTime = mLastForegroundTime = 0;
+                mLastStarts = 0;
+                mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
+                mUnpluggedStarts = 0;
+                for (int i = 0; i < mSpeedBins.length; i++) {
+                    SamplingCounter c = mSpeedBins[i];
+                    if (c != null) {
+                        c.reset(false);
+                    }
+                }
+                mExcessivePower = null;
+            }
+
             void detach() {
                 mActive = false;
                 mOnBatteryTimeBase.remove(this);
@@ -5793,7 +5831,7 @@
         public Proc getProcessStatsLocked(String name) {
             Proc ps = mProcessStats.get(name);
             if (ps == null) {
-                ps = new Proc();
+                ps = new Proc(name);
                 mProcessStats.put(name, ps);
             }
 
@@ -6147,6 +6185,7 @@
         long uptime = SystemClock.uptimeMillis() * 1000;
         long realtime = SystemClock.elapsedRealtime() * 1000;
         initTimes(uptime, realtime);
+        mStartPlatformVersion = mEndPlatformVersion = Build.ID;
         mDischargeStartLevel = 0;
         mDischargeUnplugLevel = 0;
         mDischargePlugLevel = -1;
@@ -7398,6 +7437,8 @@
             Slog.e("BatteryStats", "Error reading battery statistics", e);
         }
 
+        mEndPlatformVersion = Build.ID;
+
         if (mHistoryBuffer.dataPosition() > 0) {
             mRecordingHistory = true;
             final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -7554,6 +7595,8 @@
         mUptime = in.readLong();
         mRealtime = in.readLong();
         mStartClockTime = in.readLong();
+        mStartPlatformVersion = in.readString();
+        mEndPlatformVersion = in.readString();
         mOnBatteryTimeBase.readSummaryFromParcel(in);
         mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
         mDischargeUnplugLevel = in.readInt();
@@ -7847,6 +7890,8 @@
         out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
         out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
         out.writeLong(mStartClockTime);
+        out.writeString(mStartPlatformVersion);
+        out.writeString(mEndPlatformVersion);
         mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
         mOnBatteryScreenOffTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
         out.writeInt(mDischargeUnplugLevel);
@@ -8134,6 +8179,8 @@
 
         mStartCount = in.readInt();
         mStartClockTime = in.readLong();
+        mStartPlatformVersion = in.readString();
+        mEndPlatformVersion = in.readString();
         mUptime = in.readLong();
         mUptimeStart = in.readLong();
         mRealtime = in.readLong();
@@ -8289,6 +8336,8 @@
 
         out.writeInt(mStartCount);
         out.writeLong(mStartClockTime);
+        out.writeString(mStartPlatformVersion);
+        out.writeString(mEndPlatformVersion);
         out.writeLong(mUptime);
         out.writeLong(mUptimeStart);
         out.writeLong(mRealtime);
diff --git a/core/java/com/android/internal/util/JournaledFile.java b/core/java/com/android/internal/util/JournaledFile.java
index eeffc16..9f775d3 100644
--- a/core/java/com/android/internal/util/JournaledFile.java
+++ b/core/java/com/android/internal/util/JournaledFile.java
@@ -20,7 +20,7 @@
 import java.io.IOException;
 
 /**
- * @Deprecated Use {@link com.android.internal.os.AtomicFile} instead.  It would
+ * @deprecated Use {@link com.android.internal.os.AtomicFile} instead.  It would
  * be nice to update all existing uses of this to switch to AtomicFile, but since
  * their on-file semantics are slightly different that would run the risk of losing
  * data if at the point of the platform upgrade to the new code it would need to
diff --git a/core/res/res/color/btn_default_material_dark.xml b/core/res/res/color/btn_default_material_dark.xml
index 59555ae..7c904cd 100644
--- a/core/res/res/color/btn_default_material_dark.xml
+++ b/core/res/res/color/btn_default_material_dark.xml
@@ -15,6 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_material_dark"/>
+    <item android:state_enabled="false"
+        android:alpha="@dimen/disabled_alpha_material"
+        android:color="@color/button_material_dark"/>
     <item android:color="@color/button_material_dark"/>
 </selector>
diff --git a/core/res/res/color/btn_default_material_light.xml b/core/res/res/color/btn_default_material_light.xml
index 6511a22..738f9ad 100644
--- a/core/res/res/color/btn_default_material_light.xml
+++ b/core/res/res/color/btn_default_material_light.xml
@@ -15,6 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:alpha="0.5" android:color="@color/button_material_light"/>
+    <item android:state_enabled="false"
+        android:alpha="@dimen/disabled_alpha_material"
+        android:color="@color/button_material_light"/>
     <item android:color="@color/button_material_light"/>
 </selector>
diff --git a/core/res/res/color/primary_text_disable_only_material_dark.xml b/core/res/res/color/primary_text_disable_only_material_dark.xml
index cf7acaa..cdae790 100644
--- a/core/res/res/color/primary_text_disable_only_material_dark.xml
+++ b/core/res/res/color/primary_text_disable_only_material_dark.xml
@@ -15,6 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:alpha="0.5" android:color="@android:color/bright_foreground_material_dark"/>
-    <item android:color="@android:color/bright_foreground_material_dark"/>
+    <item android:state_enabled="false"
+        android:alpha="@dimen/disabled_alpha_material"
+        android:color="@color/bright_foreground_material_dark"/>
+    <item android:color="@color/bright_foreground_material_dark"/>
 </selector>
diff --git a/core/res/res/color/primary_text_disable_only_material_light.xml b/core/res/res/color/primary_text_disable_only_material_light.xml
index bf5d2c0..0bf14d0 100644
--- a/core/res/res/color/primary_text_disable_only_material_light.xml
+++ b/core/res/res/color/primary_text_disable_only_material_light.xml
@@ -15,6 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:alpha="0.5" android:color="@android:color/bright_foreground_material_light"/>
-    <item android:color="@android:color/bright_foreground_material_light"/>
+    <item android:state_enabled="false"
+        android:alpha="@dimen/disabled_alpha_material"
+        android:color="@color/bright_foreground_material_light"/>
+    <item android:color="@color/bright_foreground_material_light"/>
 </selector>
diff --git a/core/res/res/color/primary_text_material_dark.xml b/core/res/res/color/primary_text_material_dark.xml
index caef9d0..6ad837b 100644
--- a/core/res/res/color/primary_text_material_dark.xml
+++ b/core/res/res/color/primary_text_material_dark.xml
@@ -15,6 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_material_dark"/>
+    <item android:state_enabled="false"
+        android:alpha="@dimen/disabled_alpha_material"
+        android:color="@color/primary_text_default_material_dark"/>
     <item android:color="@color/primary_text_default_material_dark"/>
 </selector>
diff --git a/core/res/res/color/primary_text_material_light.xml b/core/res/res/color/primary_text_material_light.xml
index 81a593b..4c19e12 100644
--- a/core/res/res/color/primary_text_material_light.xml
+++ b/core/res/res/color/primary_text_material_light.xml
@@ -15,6 +15,8 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:alpha="0.5" android:color="@color/primary_text_default_material_light"/>
+    <item android:state_enabled="false"
+        android:alpha="@dimen/disabled_alpha_material"
+        android:color="@color/primary_text_default_material_light"/>
     <item android:color="@color/primary_text_default_material_light"/>
 </selector>
diff --git a/core/res/res/drawable/dialog_background_material.xml b/core/res/res/drawable/dialog_background_material.xml
index 7e5b003..2f8d1fa 100644
--- a/core/res/res/drawable/dialog_background_material.xml
+++ b/core/res/res/drawable/dialog_background_material.xml
@@ -14,12 +14,10 @@
      limitations under the License.
 -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-
-    <corners
-        android:radius="2dp" />
-    <solid
-        android:color="?attr/colorBackground" />
-
-</shape>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:inset="16dp">
+    <shape android:shape="rectangle">
+        <corners android:radius="2dp" />
+        <solid android:color="?attr/colorBackground" />
+    </shape>
+</inset>
diff --git a/core/res/res/drawable/switch_thumb_material_anim.xml b/core/res/res/drawable/switch_thumb_material_anim.xml
index 71f6cfd..30bc888 100644
--- a/core/res/res/drawable/switch_thumb_material_anim.xml
+++ b/core/res/res/drawable/switch_thumb_material_anim.xml
@@ -31,8 +31,7 @@
             android:src="@drawable/btn_switch_to_on_mtrl_00001"
             android:gravity="center"
             android:tintMode="multiply"
-            android:tint="?attr/colorButtonNormal"
-            android:alpha="?attr/disabledAlpha" />
+            android:tint="?attr/colorButtonNormal" />
     </item>
     <item
         android:state_checked="true"
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index b400644..0728055 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -18,12 +18,7 @@
     <item android:state_enabled="false" android:state_checked="true">
         <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
             android:tint="?attr/colorControlActivated"
-            android:alpha="0.15" />
-    </item>
-    <item android:state_enabled="false">
-        <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
-            android:tint="?attr/colorButtonNormal"
-            android:alpha="0.15" />
+            android:alpha="0.2" />
     </item>
     <item android:state_checked="true">
         <nine-patch android:src="@drawable/switch_track_mtrl_alpha"
diff --git a/core/res/res/raw/color_fade_frag.frag b/core/res/res/raw/color_fade_frag.frag
new file mode 100644
index 0000000..a66a5a7
--- /dev/null
+++ b/core/res/res/raw/color_fade_frag.frag
@@ -0,0 +1,42 @@
+#extension GL_OES_EGL_image_external : require
+
+precision mediump float;
+uniform samplerExternalOES texUnit;
+uniform float opacity;
+uniform float saturation;
+uniform float gamma;
+varying vec2 UV;
+
+vec3 rgb2hsl(vec3 rgb)
+{
+    float e = 1.0e-7;
+
+    vec4 p = rgb.g < rgb.b ? vec4(rgb.bg, -1.0, 2.0 / 3.0) : vec4(rgb.gb, 0.0, -1.0 / 3.0);
+    vec4 q = rgb.r < p.x ? vec4(p.xyw, rgb.r) : vec4(rgb.r, p.yzx);
+
+    float v = q.x;
+    float c = v - min(q.w, q.y);
+    float h = abs((q.w - q.y) / (6.0 * c + e) + q.z);
+    float l = v - c * 0.5;
+    float s = c / (1.0 - abs(2.0 * l - 1.0) + e);
+    return clamp(vec3(h, s, l), 0.0, 1.0);
+}
+
+vec3 hsl2rgb(vec3 hsl)
+{
+    vec3 h = vec3(hsl.x * 6.0);
+    vec3 p = abs(h - vec3(3.0, 2.0, 4.0));
+    vec3 q = 2.0 - p;
+
+    vec3 rgb = clamp(vec3(p.x - 1.0, q.yz), 0.0, 1.0);
+    float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
+    return (rgb - vec3(0.5)) * c + hsl.z;
+}
+
+void main()
+{
+    vec4 color = texture2D(texUnit, UV);
+    vec3 hsl = rgb2hsl(color.xyz);
+    vec3 rgb = pow(hsl2rgb(vec3(hsl.x, hsl.y * saturation, hsl.z * opacity)), vec3(gamma));
+    gl_FragColor = vec4(rgb, 1.0);
+}
diff --git a/core/res/res/raw/color_fade_vert.vert b/core/res/res/raw/color_fade_vert.vert
new file mode 100644
index 0000000..d17437f
--- /dev/null
+++ b/core/res/res/raw/color_fade_vert.vert
@@ -0,0 +1,13 @@
+uniform mat4 proj_matrix;
+uniform mat4 tex_matrix;
+uniform float scale;
+attribute vec2 position;
+attribute vec2 uv;
+varying vec2 UV;
+
+void main()
+{
+    vec4 transformed_uv = tex_matrix * vec4(uv.x, uv.y, 1.0, 1.0);
+    UV = transformed_uv.st / transformed_uv.q;
+    gl_Position = vec4(scale, scale, 1.0, 1.0) * (proj_matrix * vec4(position.x, position.y, 0.0, 1.0));
+}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 736f1a9d2..f6c0d71 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4926,6 +4926,7 @@
     <declare-styleable name="InsetDrawable">
         <attr name="visible" />
         <attr name="drawable" />
+        <attr name="inset"  format="dimension"/>
         <attr name="insetLeft" format="dimension" />
         <attr name="insetRight" format="dimension" />
         <attr name="insetTop" format="dimension" />
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index bae8e8d..c21dc59 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -68,4 +68,7 @@
     <dimen name="control_padding_material">4dp</dimen>
     <!-- Default rounded corner for controls -->
     <dimen name="control_corner_material">2dp</dimen>
+
+    <!-- Default alpha value for disabled elements. -->
+    <item name="disabled_alpha_material" format="float" type="dimen">0.26</item>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 73aaafd..67352d7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2269,6 +2269,12 @@
   <public type="attr" name="windowReenterTransition" />
   <public type="attr" name="windowSharedElementReturnTransition" />
   <public type="attr" name="windowSharedElementReenterTransition" />
+  <public type="attr" name="contentRatingSystemXml"/>
+  <public type="attr" name="datePickerMode"/>
+  <public type="attr" name="timePickerMode"/>
+  <public type="attr" name="inset" />
+  <public type="attr" name="letterSpacing" />
+  <public type="attr" name="fontFeatureSettings" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2561,8 +2567,22 @@
   <!-- WebView error page for when domain lookup fails. @hide @SystemApi -->
   <public type="raw" name="nodomain"/>
 
-  <public type="attr" name="contentRatingSystemXml"/>
-
-  <public type="attr" name="datePickerMode"/>
-  <public type="attr" name="timePickerMode"/>
+  <!-- Base text appearance for SystemUI elements -->
+  <public type="style" name="TextAppearance.StatusBar.Material" />
+  <!-- Base text appearance for notifications -->
+  <public type="style" name="TextAppearance.StatusBar.Material.EventContent" />
+  <!-- Notification text appearance: title -->
+  <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Title" />
+  <!-- Notification text appearance: additional line of text sandwiched
+       between the title and content -->
+  <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Line2" />
+  <!-- Notification text appearance: an annotation, e.g. the
+       number of messages in your inbox -->
+  <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Info" />
+  <!-- Notification text appearance: timestamp -->
+  <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Time" />
+  <!-- Notification text appearance: a way to highlight a bit of text (for
+       example, to separate the sender from the subject of an email if they
+       are all on the same line) -->
+  <public type="style" name="TextAppearance.StatusBar.Material.EventContent.Emphasis" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f107a4c..dd1d433 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -154,6 +154,10 @@
     <string name="ClipMmi">Incoming Caller ID</string>
     <!-- Displayed as the title for a success/failure report enabling/disabling caller ID. -->
     <string name="ClirMmi">Outgoing Caller ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID. -->
+    <string name="ColpMmi">Connected Line ID</string>
+    <!-- Displayed as the title for a success/failure report enabling/disabling connected line ID restriction. -->
+    <string name="ColrMmi">Connected Line ID Restriction</string>
     <!-- Displayed as the title for a success/failure report enabling/disabling call forwarding. -->
     <string name="CfMmi">Call forwarding</string>
     <!-- Displayed as the title for a success/failure report enabling/disabling call waiting. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3956bdf..250711e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -382,6 +382,8 @@
   <java-symbol type="string" name="CfMmi" />
   <java-symbol type="string" name="ClipMmi" />
   <java-symbol type="string" name="ClirMmi" />
+  <java-symbol type="string" name="ColpMmi" />
+  <java-symbol type="string" name="ColrMmi" />
   <java-symbol type="string" name="CwMmi" />
   <java-symbol type="string" name="Midnight" />
   <java-symbol type="string" name="Noon" />
@@ -1264,6 +1266,8 @@
   <java-symbol type="xml" name="default_zen_mode_config" />
   <java-symbol type="xml" name="tv_content_rating_systems" />
 
+  <java-symbol type="raw" name="color_fade_vert" />
+  <java-symbol type="raw" name="color_fade_frag" />
   <java-symbol type="raw" name="accessibility_gestures" />
   <java-symbol type="raw" name="incognito_mode_start_page" />
   <java-symbol type="raw" name="loaderror" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 6ee9a03..1376dfa 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -46,7 +46,7 @@
         <item name="colorForegroundInverse">@color/bright_foreground_material_light</item>
         <item name="colorBackground">@color/background_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
-        <item name="disabledAlpha">0.5</item>
+        <item name="disabledAlpha">@dimen/disabled_alpha_material</item>
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
@@ -387,7 +387,7 @@
         <item name="colorForegroundInverse">@color/bright_foreground_material_dark</item>
         <item name="colorBackground">@color/background_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
-        <item name="disabledAlpha">0.5</item>
+        <item name="disabledAlpha">@dimen/disabled_alpha_material</item>
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 864e82e..851827c 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=23.0.2
-adt.zip.download=ADT-23.0.2.zip
-adt.zip.bytes=103287135
-adt.zip.checksum=cde1d0a463b5ccce844b63161cfa1cb9
+adt.zip.version=23.0.3
+adt.zip.download=ADT-23.0.3.zip
+adt.zip.bytes=103321934
+adt.zip.checksum=ab2f5e2fbbdddeeb7dfd02cd4046538a
 
 @jd:body
 
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 5d04098..cf33200 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -56,6 +56,42 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 23.0.3</a> <em>(August 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 7 or higher is required if you are targeting the L Developer Preview.</li>
+      <li>Java 1.6 or higher is required if you are targeting other releases.</li>
+      <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r23.0.2</a>.
+        If you haven't already installed SDK Tools r23.0.2 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Fixed an issue where ADT displayed a <code>NullPointerException</code> warning dialog
+          when a valid SDK was not configured. (<a href="http://b.android.com/73313">Issue
+          73313</a>)</li>
+      <li>Fixed a minor issue with RenderScript support.</li>
+      <li>Disabled APK compression.</li>
+    </ul>
+  </dd>
+</dl>
+</div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 23.0.2</a> <em>(July 2014)</em>
   </p>
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index ca8d736..1c76d9c 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1267,7 +1267,6 @@
      * is 0.
      *
      * @return         the paint's letter-spacing for drawing text.
-     * @hide
      */
     public float getLetterSpacing() {
         return native_getLetterSpacing(mNativePaint);
@@ -1279,7 +1278,6 @@
      * expansion will be around 0.05.  Negative values tighten text.
      *
      * @param letterSpacing set the paint's letter-spacing for drawing text.
-     * @hide
      */
     public void setLetterSpacing(float letterSpacing) {
         native_setLetterSpacing(mNativePaint, letterSpacing);
@@ -1289,7 +1287,6 @@
      * Get font feature settings.  Default is null.
      *
      * @return the paint's currently set font feature settings.
-     * @hide
      */
     public String getFontFeatureSettings() {
         return mFontFeatureSettings;
@@ -1302,7 +1299,6 @@
      * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
      *
      * @param settings the font feature settings string to use, may be null.
-     * @hide
      */
     public void setFontFeatureSettings(String settings) {
         if (settings != null && settings.equals("")) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index ee5fe2e..588e776 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -119,20 +119,40 @@
         // Extract the theme attributes, if any.
         state.mThemeAttrs = a.extractThemeAttrs();
 
-        final Drawable dr = a.getDrawable(R.styleable.InsetDrawable_drawable);
-        if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+        final int N = a.getIndexCount();
+        for (int i = 0; i < N; i++) {
+            final int attr = a.getIndex(i);
+            switch (attr) {
+                case R.styleable.InsetDrawable_drawable:
+                    final Drawable dr = a.getDrawable(attr);
+                    if (dr != null) {
+                        state.mDrawable = dr;
+                        dr.setCallback(this);
+                    }
+                    break;
+                case R.styleable.InsetDrawable_inset:
+                    final int inset = a.getDimensionPixelOffset(attr, Integer.MIN_VALUE);
+                    if (inset != Integer.MIN_VALUE) {
+                        state.mInsetLeft = inset;
+                        state.mInsetTop = inset;
+                        state.mInsetRight = inset;
+                        state.mInsetBottom = inset;
+                    }
+                    break;
+                case R.styleable.InsetDrawable_insetLeft:
+                    state.mInsetLeft = a.getDimensionPixelOffset(attr, state.mInsetLeft);
+                    break;
+                case R.styleable.InsetDrawable_insetTop:
+                    state.mInsetTop = a.getDimensionPixelOffset(attr, state.mInsetTop);
+                    break;
+                case R.styleable.InsetDrawable_insetRight:
+                    state.mInsetRight = a.getDimensionPixelOffset(attr, state.mInsetRight);
+                    break;
+                case R.styleable.InsetDrawable_insetBottom:
+                    state.mInsetBottom = a.getDimensionPixelOffset(attr, state.mInsetBottom);
+                    break;
+            }
         }
-
-        state.mInsetLeft = a.getDimensionPixelOffset(
-                R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
-        state.mInsetTop = a.getDimensionPixelOffset(
-                R.styleable.InsetDrawable_insetTop, state.mInsetTop);
-        state.mInsetRight = a.getDimensionPixelOffset(
-                R.styleable.InsetDrawable_insetRight, state.mInsetRight);
-        state.mInsetBottom = a.getDimensionPixelOffset(
-                R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
     }
 
     @Override
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 79a2f61..acfa98e 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -69,7 +69,9 @@
 class PlaybackStateStruct {
 protected:
     PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
-            : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator){}
+            : mRenderer(renderer)
+            , mReplayFlags(replayFlags)
+            , mAllocator(allocator) {}
 
 public:
     OpenGLRenderer& mRenderer;
@@ -78,6 +80,15 @@
     // Allocator with the lifetime of a single frame.
     // replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator
     LinearAllocator * const mAllocator;
+
+    SkPath* allocPathForFrame() {
+        mTempPaths.push_back();
+        return &mTempPaths.back();
+    }
+
+private:
+    // Paths kept alive for the duration of the frame
+    std::vector<SkPath> mTempPaths;
 };
 
 class DeferStateStruct : public PlaybackStateStruct {
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 6883cc5..c6d3db7 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1505,20 +1505,18 @@
 class DrawShadowOp : public DrawOp {
 public:
     DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
-            float casterAlpha, const SkPath* casterOutline, const SkPath* revealClip)
-            : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ),
-            mCasterAlpha(casterAlpha) {
-        mOutline = *casterOutline;
-        if (revealClip) {
-            // intersect the outline with the convex reveal clip
-            Op(mOutline, *revealClip, kIntersect_PathOp, &mOutline);
-        }
+            float casterAlpha, const SkPath* casterOutline)
+        : DrawOp(NULL)
+        , mTransformXY(transformXY)
+        , mTransformZ(transformZ)
+        , mCasterAlpha(casterAlpha)
+        , mCasterOutline(casterOutline) {
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
             const DeferredDisplayState& state) {
         renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix,
-                renderer.getLocalClipBounds(), isCasterOpaque(), &mOutline,
+                renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
                 &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius());
     }
 
@@ -1527,7 +1525,7 @@
         Matrix4 drawTransform;
         renderer.getMatrix(&drawTransform);
         renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform,
-                renderer.getLocalClipBounds(), isCasterOpaque(), &mOutline,
+                renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
                 &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(),
                 buffers);
 
@@ -1546,7 +1544,7 @@
     const mat4 mTransformXY;
     const mat4 mTransformZ;
     const float mCasterAlpha;
-    SkPath mOutline;
+    const SkPath* mCasterOutline;
 };
 
 class DrawLayerOp : public DrawOp {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index f48b774..23940ee 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -534,6 +534,7 @@
     inline void endMark() {}
     inline int level() { return mLevel; }
     inline int replayFlags() { return mDeferStruct.mReplayFlags; }
+    inline SkPath* allocPathForFrame() { return mDeferStruct.allocPathForFrame(); }
 
 private:
     DeferStateStruct& mDeferStruct;
@@ -564,6 +565,7 @@
     }
     inline int level() { return mLevel; }
     inline int replayFlags() { return mReplayStruct.mReplayFlags; }
+    inline SkPath* allocPathForFrame() { return mReplayStruct.allocPathForFrame(); }
 
 private:
     ReplayStateStruct& mReplayStruct;
@@ -612,14 +614,24 @@
     mat4 shadowMatrixZ(transformFromParent);
     applyViewPropertyTransforms(shadowMatrixZ, true);
 
-    const SkPath* outlinePath = properties().getOutline().getPath();
+    const SkPath* casterOutlinePath = properties().getOutline().getPath();
     const SkPath* revealClipPath = properties().getRevealClip().getPath();
     if (revealClipPath && revealClipPath->isEmpty()) return;
 
     float casterAlpha = properties().getAlpha() * properties().getOutline().getAlpha();
+
+    const SkPath* outlinePath = casterOutlinePath;
+    if (revealClipPath) {
+        // if we can't simply use the caster's path directly, create a temporary one
+        SkPath* frameAllocatedPath = handler.allocPathForFrame();
+
+        // intersect the outline with the convex reveal clip
+        Op(*casterOutlinePath, *revealClipPath, kIntersect_PathOp, frameAllocatedPath);
+        outlinePath = frameAllocatedPath;
+    }
+
     DisplayListOp* shadowOp  = new (handler.allocator()) DrawShadowOp(
-            shadowMatrixXY, shadowMatrixZ, casterAlpha,
-            outlinePath, revealClipPath);
+            shadowMatrixXY, shadowMatrixZ, casterAlpha, outlinePath);
     handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
 }
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 40602c5..8bc2498 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -479,7 +479,7 @@
                                  int channelConfig, int audioFormat, int mode) {
         //--------------
         // sample rate, note these values are subject to change
-        if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {
+        if (sampleRateInHz < SAMPLE_RATE_HZ_MIN || sampleRateInHz > SAMPLE_RATE_HZ_MAX) {
             throw new IllegalArgumentException(sampleRateInHz
                     + "Hz is not a supported sample rate.");
         }
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 143d880..74f7a96 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -190,8 +190,8 @@
 
     private static final String[] PREFERRED_DESCRIPTION_ORDER = {
             METADATA_KEY_TITLE,
-            METADATA_KEY_ALBUM,
             METADATA_KEY_ARTIST,
+            METADATA_KEY_ALBUM,
             METADATA_KEY_ALBUM_ARTIST,
             METADATA_KEY_WRITER,
             METADATA_KEY_AUTHOR,
@@ -405,7 +405,6 @@
      * Returns a simple description of this metadata for display purposes.
      *
      * @return A simple description of this metadata.
-     * @hide
      */
     public @NonNull Description getDescription() {
         if (mDescription != null) {
@@ -672,43 +671,86 @@
 
     /**
      * A simple form of the metadata that can be used for display.
-     *
-     * @hide
      */
     public final class Description {
         /**
          * A primary title suitable for display or null.
          */
-        public final CharSequence title;
+        private final CharSequence mTitle;
         /**
          * A subtitle suitable for display or null.
          */
-        public final CharSequence subtitle;
+        private final CharSequence mSubtitle;
         /**
          * A description suitable for display or null.
          */
-        public final CharSequence description;
+        private final CharSequence mDescription;
         /**
          * A bitmap icon suitable for display or null.
          */
-        public final Bitmap icon;
+        private final Bitmap mIcon;
         /**
          * A Uri for an icon suitable for display or null.
          */
-        public final Uri iconUri;
+        private final Uri mIconUri;
+
+        /**
+         * Returns the best available title or null.
+         *
+         * @return A title or null.
+         */
+        public @Nullable CharSequence getTitle() {
+            return mTitle;
+        }
+
+        /**
+         * Returns the best available subtitle or null.
+         *
+         * @return A subtitle or null.
+         */
+        public @Nullable CharSequence getSubtitle() {
+            return mSubtitle;
+        }
+
+        /**
+         * Returns the best available description or null.
+         *
+         * @return A description or null.
+         */
+        public @Nullable CharSequence getDescription() {
+            return mDescription;
+        }
+
+        /**
+         * Returns the best available icon or null.
+         *
+         * @return An icon or null.
+         */
+        public @Nullable Bitmap getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * Returns the best available icon Uri or null.
+         *
+         * @return An icon uri or null.
+         */
+        public @Nullable Uri getIconUri() {
+            return mIconUri;
+        }
 
         private Description(CharSequence title, CharSequence subtitle, CharSequence description,
                 Bitmap icon, Uri iconUri) {
-            this.title = title;
-            this.subtitle = subtitle;
-            this.description = description;
-            this.icon = icon;
-            this.iconUri = iconUri;
+            mTitle = title;
+            mSubtitle = subtitle;
+            mDescription = description;
+            mIcon = icon;
+            mIconUri = iconUri;
         }
 
         @Override
         public String toString() {
-            return title + ", " + subtitle + ", " + description;
+            return mTitle + ", " + mSubtitle + ", " + mDescription;
         }
     }
 
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index ae6f5bc..97a6b83 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -53,13 +53,25 @@
 
     private static final String PATH_CHANNEL = "channel";
     private static final String PATH_PROGRAM = "program";
-    private static final String PATH_INPUT = "input";
     private static final String PATH_PASSTHROUGH = "passthrough";
 
     /**
+     * An optional query, update or delete URI parameter that allows the caller to specify TV input
+     * ID to filter channels.
+     * @hide
+     */
+    public static final String PARAM_INPUT = "input";
+
+    /**
+     * An optional query, update or delete URI parameter that allows the caller to specify channel
+     * ID to filter programs.
+     * @hide
+     */
+    public static final String PARAM_CHANNEL = "channel";
+
+    /**
      * An optional query, update or delete URI parameter that allows the caller to specify start
      * time (in milliseconds since the epoch) to filter programs.
-     *
      * @hide
      */
     public static final String PARAM_START_TIME = "start_time";
@@ -67,7 +79,6 @@
     /**
      * An optional query, update or delete URI parameter that allows the caller to specify end time
      * (in milliseconds since the epoch) to filter programs.
-     *
      * @hide
      */
     public static final String PARAM_END_TIME = "end_time";
@@ -76,7 +87,6 @@
      * A query, update or delete URI parameter that allows the caller to operate on all or
      * browsable-only channels. If set to "true", the rows that contain non-browsable channels are
      * not affected.
-     *
      * @hide
      */
     public static final String PARAM_BROWSABLE_ONLY = "browsable_only";
@@ -84,7 +94,6 @@
     /**
      * A optional query, update or delete URI parameter that allows the caller to specify canonical
      * genre to filter programs.
-     *
      * @hide
      */
     public static final String PARAM_CANONICAL_GENRE = "canonical_genre";
@@ -116,17 +125,7 @@
      */
     public static final Uri buildChannelUriForPassthroughTvInput(String inputId) {
         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
-                .appendPath(PATH_INPUT).appendPath(inputId).appendPath(PATH_CHANNEL)
-                .appendPath(PATH_PASSTHROUGH).build();
-    }
-
-    /**
-     * Returns true, if {@code channelUri} is a channel URI for a passthrough TV input.
-     * @hide
-     */
-    @SystemApi
-    public static final boolean isChannelUriForPassthroughTvInput(Uri channelUri) {
-        return channelUri.toString().endsWith(PATH_PASSTHROUGH);
+                .appendPath(PATH_PASSTHROUGH).appendPath(inputId).build();
     }
 
     /**
@@ -144,7 +143,7 @@
      * @param channelUri The URI of the channel whose logo is pointed to.
      */
     public static final Uri buildChannelLogoUri(Uri channelUri) {
-        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
+        if (!isChannelUriForTunerTvInput(channelUri)) {
             throw new IllegalArgumentException("Not a channel: " + channelUri);
         }
         return Uri.withAppendedPath(channelUri, Channels.Logo.CONTENT_DIRECTORY);
@@ -169,8 +168,8 @@
      * @hide
      */
     public static final Uri buildChannelsUriForInput(String inputId, boolean browsableOnly) {
-        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
-                .appendPath(PATH_INPUT).appendPath(inputId).appendPath(PATH_CHANNEL)
+        return Channels.CONTENT_URI.buildUpon()
+                .appendQueryParameter(PARAM_INPUT, inputId)
                 .appendQueryParameter(PARAM_BROWSABLE_ONLY, String.valueOf(browsableOnly)).build();
     }
 
@@ -194,8 +193,7 @@
 
         Uri uri;
         if (inputId == null) {
-            uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
-                    .appendPath(PATH_CHANNEL).build();
+            uri = Channels.CONTENT_URI;
         } else {
             uri = buildChannelsUriForInput(inputId, browsableOnly);
         }
@@ -217,9 +215,8 @@
      * @param channelId The ID of the channel to return programs for.
      */
     public static final Uri buildProgramsUriForChannel(long channelId) {
-        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
-                .appendPath(PATH_CHANNEL).appendPath(String.valueOf(channelId))
-                .appendPath(PATH_PROGRAM).build();
+        return Programs.CONTENT_URI.buildUpon()
+                .appendQueryParameter(PARAM_CHANNEL, String.valueOf(channelId)).build();
     }
 
     /**
@@ -228,7 +225,7 @@
      * @param channelUri The URI of the channel to return programs for.
      */
     public static final Uri buildProgramsUriForChannel(Uri channelUri) {
-        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
+        if (!isChannelUriForTunerTvInput(channelUri)) {
             throw new IllegalArgumentException("Not a channel: " + channelUri);
         }
         return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
@@ -263,7 +260,7 @@
      */
     public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
             long endTime) {
-        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
+        if (!isChannelUriForTunerTvInput(channelUri)) {
             throw new IllegalArgumentException("Not a channel: " + channelUri);
         }
         return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
@@ -279,41 +276,47 @@
         return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId);
     }
 
-    /**
-     * Extracts the {@link Channels#COLUMN_INPUT_ID} from a given URI.
-     *
-     * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(String)},
-     *            {@link #buildChannelsUriForInput(String, boolean)}, or
-     *            {@link #buildChannelsUriForCanonicalGenre(String, String, boolean)}.
-     * @hide
-     */
-    public static final String getInputId(Uri channelsUri) {
-        final List<String> paths = channelsUri.getPathSegments();
-        if (paths.size() < 3) {
-            throw new IllegalArgumentException("Not channels: " + channelsUri);
-        }
-        if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(2))) {
-            throw new IllegalArgumentException("Not channels: " + channelsUri);
-        }
-        return paths.get(1);
+    private static final boolean isTvUri(Uri uri) {
+        return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
+                && AUTHORITY.equals(uri.getAuthority());
+    }
+
+    private static final boolean isTwoSegmentUriStartingWith(Uri uri, String pathSegment) {
+        List<String> pathSegments = uri.getPathSegments();
+        return pathSegments.size() == 2 && pathSegment.equals(pathSegments.get(0));
     }
 
     /**
-     * Extracts the {@link Channels#_ID} from a given URI.
-     *
-     * @param programsUri A URI constructed by {@link #buildProgramsUriForChannel(Uri)} or
-     *            {@link #buildProgramsUriForChannel(Uri, long, long)}.
+     * Returns true, if {@code uri} is a channel URI.
      * @hide
      */
-    public static final String getChannelId(Uri programsUri) {
-        final List<String> paths = programsUri.getPathSegments();
-        if (paths.size() < 3) {
-            throw new IllegalArgumentException("Not programs: " + programsUri);
-        }
-        if (!PATH_CHANNEL.equals(paths.get(0)) || !PATH_PROGRAM.equals(paths.get(2))) {
-            throw new IllegalArgumentException("Not programs: " + programsUri);
-        }
-        return paths.get(1);
+    public static final boolean isChannelUri(Uri uri) {
+        return isChannelUriForTunerTvInput(uri) || isChannelUriForPassthroughTvInput(uri);
+    }
+
+    /**
+     * Returns true, if {@code uri} is a channel URI for a tuner TV input.
+     * @hide
+     */
+    public static final boolean isChannelUriForTunerTvInput(Uri uri) {
+        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
+    }
+
+    /**
+     * Returns true, if {@code uri} is a channel URI for a passthrough TV input.
+     * @hide
+     */
+    @SystemApi
+    public static final boolean isChannelUriForPassthroughTvInput(Uri uri) {
+        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
+    }
+
+    /**
+     * Returns true, if {@code uri} is a program URI.
+     * @hide
+     */
+    public static final boolean isProgramUri(Uri uri) {
+        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PROGRAM);
     }
 
 
@@ -1104,7 +1107,6 @@
     /**
      * Column definitions for the TV programs that the user watched. Applications do not have access
      * to this table.
-     *
      * @hide
      */
     public static final class WatchedPrograms implements BaseTvColumns {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index d033f76..f1e1099 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -58,12 +58,17 @@
     EVENT_SET_CALLBACK = 2,
 };
 
-struct CryptoErrorCodes {
+static struct CryptoErrorCodes {
     jint cryptoErrorNoKey;
     jint cryptoErrorKeyExpired;
     jint cryptoErrorResourceBusy;
 } gCryptoErrorCodes;
 
+static struct CodecActionCodes {
+    jint codecActionTransient;
+    jint codecActionRecoverable;
+} gCodecActionCodes;
+
 struct fields_t {
     jfieldID context;
     jmethodID postEventFromNativeID;
@@ -101,10 +106,11 @@
             PRIORITY_FOREGROUND);
 
     if (nameIsType) {
-        mCodec = MediaCodec::CreateByType(mLooper, name, encoder);
+        mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
     } else {
-        mCodec = MediaCodec::CreateByComponentName(mLooper, name);
+        mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
     }
+    CHECK((mCodec != NULL) != (mInitStatus != OK));
 }
 
 void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
@@ -147,7 +153,7 @@
 }
 
 status_t JMediaCodec::initCheck() const {
-    return mCodec != NULL ? OK : NO_INIT;
+    return mInitStatus;
 }
 
 void JMediaCodec::registerSelf() {
@@ -158,6 +164,7 @@
     if (mCodec != NULL) {
         mCodec->release();
         mCodec.clear();
+        mInitStatus = NO_INIT;
     }
 
     if (mLooper != NULL) {
@@ -554,6 +561,34 @@
     }
 }
 
+static jthrowable createCodecException(
+        JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
+    ScopedLocalRef<jclass> clazz(
+            env, env->FindClass("android/media/MediaCodec$CodecException"));
+    CHECK(clazz.get() != NULL);
+
+    const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
+    CHECK(ctor != NULL);
+
+    ScopedLocalRef<jstring> msgObj(
+            env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
+
+    // translate action code to Java equivalent
+    switch (actionCode) {
+    case ACTION_CODE_TRANSIENT:
+        actionCode = gCodecActionCodes.codecActionTransient;
+        break;
+    case ACTION_CODE_RECOVERABLE:
+        actionCode = gCodecActionCodes.codecActionRecoverable;
+        break;
+    default:
+        actionCode = 0;  // everything else is fatal
+        break;
+    }
+
+    return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
+}
+
 void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
     int32_t arg1, arg2 = 0;
     jobject obj = NULL;
@@ -605,19 +640,8 @@
             CHECK(msg->findInt32("err", &err));
             CHECK(msg->findInt32("actionCode", &actionCode));
 
-            // use Integer object to pass the action code
-            ScopedLocalRef<jclass> clazz(
-                    env, env->FindClass("android/media/MediaCodec$CodecException"));
-            jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
-
-            AString str;
-            const char *detail = "Unknown error";
-            if (msg->findString("detail", &str)) {
-                detail = str.c_str();
-            }
-            jstring msgObj = env->NewStringUTF(detail);
-
-            obj = env->NewObject(clazz.get(), ctor, err, actionCode, msgObj);
+            // note that DRM errors could conceivably alias into a CodecException
+            obj = (jobject)createCodecException(env, err, actionCode);
 
             if (obj == NULL) {
                 if (env->ExceptionCheck()) {
@@ -705,6 +729,11 @@
     setMediaCodec(env, thiz, NULL);
 }
 
+static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
+    jthrowable exception = createCodecException(env, err, actionCode, msg);
+    env->Throw(exception);
+}
+
 static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
     ScopedLocalRef<jclass> clazz(
             env, env->FindClass("android/media/MediaCodec$CryptoException"));
@@ -716,7 +745,7 @@
 
     jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
 
-    /* translate OS errors to Java API CryptoException errorCodes */
+    /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
     switch (err) {
         case ERROR_DRM_NO_LICENSE:
             err = gCryptoErrorCodes.cryptoErrorNoKey;
@@ -727,7 +756,7 @@
         case ERROR_DRM_RESOURCE_BUSY:
             err = gCryptoErrorCodes.cryptoErrorResourceBusy;
             break;
-        default:
+        default:  /* Other negative DRM error codes go out as is. */
             break;
     }
 
@@ -738,13 +767,8 @@
 }
 
 static jint throwExceptionAsNecessary(
-        JNIEnv *env, status_t err, const char *msg = NULL) {
-    if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
-        // We'll throw our custom MediaCodec.CryptoException
-        throwCryptoException(env, err, msg);
-        return 0;
-    }
-
+        JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
+        const char *msg = NULL) {
     switch (err) {
         case OK:
             return 0;
@@ -758,20 +782,18 @@
         case INFO_OUTPUT_BUFFERS_CHANGED:
             return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
 
-        case ERROR_DRM_NO_LICENSE:
-        case ERROR_DRM_LICENSE_EXPIRED:
-        case ERROR_DRM_RESOURCE_BUSY:
-            throwCryptoException(env, err, msg);
-            break;
+        case INVALID_OPERATION:
+            jniThrowException(env, "java/lang/IllegalStateException", msg);
+            return 0;
 
         default:
-        {
-            jniThrowException(env, "java/lang/IllegalStateException", msg);
-            break;
-        }
+            if (isCryptoError(err)) {
+                throwCryptoException(env, err, msg);
+                return 0;
+            }
+            throwCodecException(env, err, actionCode, msg);
+            return 0;
     }
-
-    return 0;
 }
 
 static void android_media_MediaCodec_native_setCallback(
@@ -781,7 +803,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -800,7 +822,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -842,7 +864,7 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -865,13 +887,13 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", "no codec found");
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
     status_t err = codec->start();
 
-    throwExceptionAsNecessary(env, err, "start failed");
+    throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
 }
 
 static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -880,7 +902,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -895,8 +917,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        // should never be here
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -904,7 +925,10 @@
     if (err != OK) {
         // treat all errors as fatal for now, though resource not available
         // errors could be treated as transient.
-        err = 0x80000000;
+        // we also should avoid sending INVALID_OPERATION here due to
+        // the transitory nature of reset(), it should not inadvertently
+        // trigger an IllegalStateException.
+        err = UNKNOWN_ERROR;
     }
     throwExceptionAsNecessary(env, err);
 }
@@ -915,7 +939,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -937,7 +961,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -947,7 +971,7 @@
             index, offset, size, timestampUs, flags, &errorDetailMsg);
 
     throwExceptionAsNecessary(
-            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
 }
 
 static void android_media_MediaCodec_queueSecureInputBuffer(
@@ -963,7 +987,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -1005,7 +1029,7 @@
         err = -ERANGE;
     // subSamples array may silently overflow if number of samples are too large.  Use
     // INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
-    } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) {
+    } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
         err = -EINVAL;
     } else {
         jboolean isCopy;
@@ -1089,7 +1113,7 @@
     subSamples = NULL;
 
     throwExceptionAsNecessary(
-            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+            env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
 }
 
 static jint android_media_MediaCodec_dequeueInputBuffer(
@@ -1099,7 +1123,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return -1;
     }
 
@@ -1120,7 +1144,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return 0;
     }
 
@@ -1143,7 +1167,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -1158,7 +1182,7 @@
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -1174,7 +1198,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -1197,7 +1221,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -1220,7 +1244,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -1246,7 +1270,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -1272,7 +1296,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -1298,7 +1322,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return NULL;
     }
 
@@ -1321,7 +1345,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -1340,7 +1364,7 @@
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
 
     if (codec == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
         return;
     }
 
@@ -1409,13 +1433,25 @@
     CHECK(field != NULL);
     gCryptoErrorCodes.cryptoErrorResourceBusy =
         env->GetStaticIntField(clazz.get(), field);
+
+    clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
+    CHECK(clazz.get() != NULL);
+    field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
+    CHECK(field != NULL);
+    gCodecActionCodes.codecActionTransient =
+        env->GetStaticIntField(clazz.get(), field);
+
+    field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
+    CHECK(field != NULL);
+    gCodecActionCodes.codecActionRecoverable =
+        env->GetStaticIntField(clazz.get(), field);
 }
 
 static void android_media_MediaCodec_native_setup(
         JNIEnv *env, jobject thiz,
         jstring name, jboolean nameIsType, jboolean encoder) {
     if (name == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        jniThrowException(env, "java/lang/NullPointerException", NULL);
         return;
     }
 
@@ -1427,19 +1463,23 @@
 
     sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
 
-    status_t err = codec->initCheck();
-
-    env->ReleaseStringUTFChars(name, tmp);
-    tmp = NULL;
-
-    if (err != OK) {
-        jniThrowException(
-                env,
-                "java/io/IOException",
-                "Failed to allocate component instance");
+    const status_t err = codec->initCheck();
+    if (err == NAME_NOT_FOUND) {
+        // fail and do not try again.
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                String8::format("Failed to initialize %s, error %#x", tmp, err));
+        env->ReleaseStringUTFChars(name, tmp);
+        return;
+    } else if (err != OK) {
+        // believed possible to try again
+        jniThrowException(env, "java/io/IOException",
+                String8::format("Failed to find matching codec %s, error %#x", tmp, err));
+        env->ReleaseStringUTFChars(name, tmp);
         return;
     }
 
+    env->ReleaseStringUTFChars(name, tmp);
+
     codec->registerSelf();
 
     setMediaCodec(env,thiz, codec);
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index f84a16a..9f2785a 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -135,6 +135,8 @@
 
     sp<AMessage> mCallbackNotification;
 
+    status_t mInitStatus;
+
     status_t createByteBufferFromABuffer(
             JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
             jobject *buf) const;
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index ed1eeb9..ecba02a 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -21,6 +21,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaCodecList.h>
+#include <media/IMediaCodecList.h>
+#include <media/MediaCodecInfo.h>
 
 #include "android_runtime/AndroidRuntime.h"
 #include "jni.h"
@@ -29,20 +31,41 @@
 
 using namespace android;
 
+static sp<IMediaCodecList> getCodecList(JNIEnv *env) {
+    sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+    if (mcl == NULL) {
+        // This should never happen unless something is really wrong
+        jniThrowException(
+                    env, "java/lang/RuntimeException", "cannot get MediaCodecList");
+    }
+    return mcl;
+}
+
 static jint android_media_MediaCodecList_getCodecCount(
         JNIEnv *env, jobject thiz) {
-    return MediaCodecList::getInstance()->countCodecs();
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return 0;
+    }
+    return mcl->countCodecs();
 }
 
 static jstring android_media_MediaCodecList_getCodecName(
         JNIEnv *env, jobject thiz, jint index) {
-    const char *name = MediaCodecList::getInstance()->getCodecName(index);
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
 
-    if (name == NULL) {
+    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    if (info == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return NULL;
     }
 
+    const char *name = info->getCodecName();
     return env->NewStringUTF(name);
 }
 
@@ -54,33 +77,56 @@
     }
 
     const char *nameStr = env->GetStringUTFChars(name, NULL);
-
     if (nameStr == NULL) {
         // Out of memory exception already pending.
         return -ENOENT;
     }
 
-    jint ret = MediaCodecList::getInstance()->findCodecByName(nameStr);
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return -ENOENT;
+    }
+
+    jint ret = mcl->findCodecByName(nameStr);
     env->ReleaseStringUTFChars(name, nameStr);
     return ret;
 }
 
 static jboolean android_media_MediaCodecList_isEncoder(
         JNIEnv *env, jobject thiz, jint index) {
-    return MediaCodecList::getInstance()->isEncoder(index);
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return false;
+    }
+
+    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    if (info == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return false;
+    }
+
+    return info->isEncoder();
 }
 
 static jarray android_media_MediaCodecList_getSupportedTypes(
         JNIEnv *env, jobject thiz, jint index) {
-    Vector<AString> types;
-    status_t err =
-        MediaCodecList::getInstance()->getSupportedTypes(index, &types);
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
 
-    if (err != OK) {
+    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    if (info == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return NULL;
     }
 
+    Vector<AString> types;
+    info->getSupportedMimes(&types);
+
     jclass clazz = env->FindClass("java/lang/String");
     CHECK(clazz != NULL);
 
@@ -103,6 +149,18 @@
         return NULL;
     }
 
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
+
+    const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+    if (info == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return NULL;
+    }
+
     const char *typeStr = env->GetStringUTFChars(type, NULL);
 
     if (typeStr == NULL) {
@@ -110,30 +168,27 @@
         return NULL;
     }
 
-    Vector<MediaCodecList::ProfileLevel> profileLevels;
+    Vector<MediaCodecInfo::ProfileLevel> profileLevels;
     Vector<uint32_t> colorFormats;
-    uint32_t flags;
-    sp<AMessage> capabilities;
 
     sp<AMessage> defaultFormat = new AMessage();
     defaultFormat->setString("mime", typeStr);
 
     // TODO query default-format also from codec/codec list
-
-    status_t err =
-        MediaCodecList::getInstance()->getCodecCapabilities(
-                index, typeStr, &profileLevels, &colorFormats, &flags,
-                &capabilities);
-
-    bool isEncoder = MediaCodecList::getInstance()->isEncoder(index);
-
-    env->ReleaseStringUTFChars(type, typeStr);
-    typeStr = NULL;
-
-    if (err != OK) {
+    const sp<MediaCodecInfo::Capabilities> &capabilities =
+        info->getCapabilitiesFor(typeStr);
+    if (capabilities == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return NULL;
     }
+    env->ReleaseStringUTFChars(type, typeStr);
+    typeStr = NULL;
+
+    capabilities->getSupportedColorFormats(&colorFormats);
+    capabilities->getSupportedProfileLevels(&profileLevels);
+    uint32_t flags = capabilities->getFlags();
+    sp<AMessage> details = capabilities->getDetails();
+    bool isEncoder = info->isEncoder();
 
     jobject defaultFormatObj = NULL;
     if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
@@ -141,7 +196,7 @@
     }
 
     jobject infoObj = NULL;
-    if (ConvertMessageToMap(env, capabilities, &infoObj)) {
+    if (ConvertMessageToMap(env, details, &infoObj)) {
         env->DeleteLocalRef(defaultFormatObj);
         return NULL;
     }
@@ -164,7 +219,7 @@
         env->GetFieldID(profileLevelClazz, "level", "I");
 
     for (size_t i = 0; i < profileLevels.size(); ++i) {
-        const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
+        const MediaCodecInfo::ProfileLevel &src = profileLevels.itemAt(i);
 
         jobject profileLevelObj = env->AllocObject(profileLevelClazz);
 
@@ -192,26 +247,6 @@
             profileLevelArray, colorFormatsArray, isEncoder, flags,
             defaultFormatObj, infoObj);
 
-#if 0
-    jfieldID profileLevelsField = env->GetFieldID(
-            capsClazz,
-            "profileLevels",
-            "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
-
-    env->SetObjectField(caps, profileLevelsField, profileLevelArray);
-
-    jfieldID flagsField =
-        env->GetFieldID(capsClazz, "mFlagsVerified", "I");
-
-    env->SetIntField(caps, flagsField, flags);
-
-    jfieldID colorFormatsField = env->GetFieldID(
-            capsClazz, "colorFormats", "[I");
-
-    env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
-
-#endif
-
     env->DeleteLocalRef(profileLevelArray);
     profileLevelArray = NULL;
 
diff --git a/packages/SystemUI/res/layout/data_usage.xml b/packages/SystemUI/res/layout/data_usage.xml
index 63d22b2..8831a05 100644
--- a/packages/SystemUI/res/layout/data_usage.xml
+++ b/packages/SystemUI/res/layout/data_usage.xml
@@ -17,6 +17,9 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingTop="16dp"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
     android:orientation="vertical" >
 
     <TextView
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index c6a7368..5869bf3 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -14,39 +14,43 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@drawable/qs_detail_background"
-    android:padding="16dp" >
-
-    <TextView
-        android:id="@android:id/button1"
-        style="@style/QSBorderlessButton"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:minWidth="88dp"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentEnd="true"
-        android:text="@string/quick_settings_done"
-        android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
-    <TextView
-        android:id="@android:id/button2"
-        style="@style/QSBorderlessButton"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:layout_marginEnd="8dp"
-        android:minWidth="132dp"
-        android:layout_toStartOf="@android:id/button1"
-        android:text="@string/quick_settings_more_settings"
-        android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
-    <FrameLayout
-        android:id="@android:id/content"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_above="@android:id/button1" />
+        android:background="@drawable/qs_detail_background"
+        android:paddingBottom="16dp"
+        android:orientation="vertical">
 
-</RelativeLayout>
\ No newline at end of file
+    <FrameLayout
+            android:id="@android:id/content"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1" />
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingEnd="16dp"
+            android:gravity="end">
+
+        <TextView
+                android:id="@android:id/button2"
+                style="@style/QSBorderlessButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="8dp"
+                android:minWidth="132dp"
+                android:text="@string/quick_settings_more_settings"
+                android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+        <TextView
+                android:id="@android:id/button1"
+                style="@style/QSBorderlessButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minWidth="88dp"
+                android:text="@string/quick_settings_done"
+                android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail_items.xml b/packages/SystemUI/res/layout/qs_detail_items.xml
index b64005f..f61a43c 100644
--- a/packages/SystemUI/res/layout/qs_detail_items.xml
+++ b/packages/SystemUI/res/layout/qs_detail_items.xml
@@ -17,7 +17,10 @@
 <!-- extends FrameLayout -->
 <com.android.systemui.qs.QSDetailItems xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+    android:layout_height="match_parent"
+    android:paddingTop="16dp"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp">
 
     <LinearLayout
         android:id="@android:id/list"
diff --git a/packages/SystemUI/res/layout/qs_user_detail.xml b/packages/SystemUI/res/layout/qs_user_detail.xml
index 1d6df61..91d3a53 100644
--- a/packages/SystemUI/res/layout/qs_user_detail.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail.xml
@@ -16,14 +16,12 @@
   ~ limitations under the License
   -->
 
-<!-- GridView -->
+<!-- PseudoGridView -->
 <com.android.systemui.qs.tiles.UserDetailView
         xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:sysui="http://schemas.android.com/apk/res-auto"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:verticalSpacing="4dp"
-        android:horizontalSpacing="4dp"
-        android:numColumns="3"
-        android:listSelector="@drawable/ripple_drawable">
-
-</com.android.systemui.qs.tiles.UserDetailView>
\ No newline at end of file
+        sysui:verticalSpacing="4dp"
+        sysui:horizontalSpacing="4dp"
+        style="@style/UserDetailView" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 5ceed84..2322f16 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -25,16 +25,17 @@
         android:orientation="vertical"
         android:gravity="top|center_horizontal"
         android:paddingTop="16dp"
-        android:paddingBottom="20dp"
+        android:minHeight="112dp"
         android:clipChildren="false"
         android:clipToPadding="false"
+        android:background="@drawable/ripple_drawable"
         systemui:activatedFontFamily="sans-serif-medium">
 
     <com.android.systemui.statusbar.phone.UserAvatarView
             android:id="@+id/user_picture"
             android:layout_width="@dimen/max_avatar_size"
             android:layout_height="@dimen/max_avatar_size"
-            android:layout_marginBottom="12dp"
+            android:layout_marginBottom="10dp"
             systemui:frameWidth="2dp"
             systemui:framePadding="6dp"
             systemui:activeFrameColor="@color/current_user_border_color"/>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 5daf08e..9e5b1d6 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -34,4 +34,8 @@
         <item name="android:layout_height">@dimen/search_panel_scrim_height</item>
         <item name="android:layout_gravity">bottom</item>
     </style>
+
+    <style name="UserDetailView">
+        <item name="numColumns">4</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 8bd3c39..6ecdca3 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -67,5 +67,10 @@
     <declare-styleable name="DateView">
         <attr name="datePattern" format="string" />
     </declare-styleable>
+    <declare-styleable name="PseudoGridView">
+        <attr name="numColumns" format="integer" />
+        <attr name="verticalSpacing" format="dimension" />
+        <attr name="horizontalSpacing" format="dimension" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 5db6912..baaa379 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -289,4 +289,8 @@
         <item name="android:layout_height">@dimen/search_panel_scrim_height</item>
         <item name="android:layout_gravity">bottom</item>
     </style>
+
+    <style name="UserDetailView">
+        <item name="numColumns">3</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
new file mode 100644
index 0000000..cb6708e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 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.qs;
+
+import com.android.systemui.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A view that arranges it's children in a grid with a fixed number of evenly spaced columns.
+ *
+ * {@see android.widget.GridView}
+ */
+public class PseudoGridView extends ViewGroup {
+
+    private int mNumColumns = 3;
+    private int mVerticalSpacing;
+    private int mHorizontalSpacing;
+
+    public PseudoGridView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PseudoGridView);
+
+        final int N = a.getIndexCount();
+        for (int i = 0; i < N; i++) {
+            int attr = a.getIndex(i);
+            switch (attr) {
+                case R.styleable.PseudoGridView_numColumns:
+                    mNumColumns = a.getInt(attr, 3);
+                    break;
+                case R.styleable.PseudoGridView_verticalSpacing:
+                    mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
+                    break;
+                case R.styleable.PseudoGridView_horizontalSpacing:
+                    mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
+                    break;
+            }
+        }
+
+        a.recycle();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+            throw new UnsupportedOperationException("Needs a maximum width");
+        }
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+
+        int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
+        int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
+        int childHeightSpec = MeasureSpec.UNSPECIFIED;
+        int totalHeight = 0;
+        int children = getChildCount();
+        int rows = (children + mNumColumns - 1) / mNumColumns;
+        for (int row = 0; row < rows; row++) {
+            int startOfRow = row * mNumColumns;
+            int endOfRow = Math.min(startOfRow + mNumColumns, children);
+            int maxHeight = 0;
+            for (int i = startOfRow; i < endOfRow; i++) {
+                View child = getChildAt(i);
+                child.measure(childWidthSpec, childHeightSpec);
+                maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+            }
+            int maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
+            for (int i = startOfRow; i < endOfRow; i++) {
+                View child = getChildAt(i);
+                if (child.getMeasuredHeight() != maxHeight) {
+                    child.measure(childWidthSpec, maxHeightSpec);
+                }
+            }
+            totalHeight += maxHeight;
+            if (row > 0) {
+                totalHeight += mVerticalSpacing;
+            }
+        }
+
+        setMeasuredDimension(width, getDefaultSize(totalHeight, heightMeasureSpec));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        boolean isRtl = isLayoutRtl();
+        int children = getChildCount();
+        int rows = (children + mNumColumns - 1) / mNumColumns;
+        int y = 0;
+        for (int row = 0; row < rows; row++) {
+            int x = isRtl ? getWidth() : 0;
+            int maxHeight = 0;
+            int startOfRow = row * mNumColumns;
+            int endOfRow = Math.min(startOfRow + mNumColumns, children);
+            for (int i = startOfRow; i < endOfRow; i++) {
+                View child = getChildAt(i);
+                int width = child.getMeasuredWidth();
+                int height = child.getMeasuredHeight();
+                if (isRtl) {
+                    x -= width;
+                }
+                child.layout(x, y, x + width, y + height);
+                maxHeight = Math.max(maxHeight, height);
+                if (isRtl) {
+                    x -= mHorizontalSpacing;
+                } else {
+                    x += width + mHorizontalSpacing;
+                }
+            }
+            y += maxHeight;
+            if (row > 0) {
+                y += mVerticalSpacing;
+            }
+        }
+    }
+
+    /**
+     * Bridges between a ViewGroup and a BaseAdapter.
+     * <p>
+     * Usage: {@code ViewGroupAdapterBridge.link(viewGroup, adapter)}
+     * <br />
+     * After this call, the ViewGroup's children will be provided by the adapter.
+     */
+    public static class ViewGroupAdapterBridge extends DataSetObserver {
+
+        private final WeakReference<ViewGroup> mViewGroup;
+        private final BaseAdapter mAdapter;
+        private boolean mReleased;
+
+        public static void link(ViewGroup viewGroup, BaseAdapter adapter) {
+            new ViewGroupAdapterBridge(viewGroup, adapter);
+        }
+
+        private ViewGroupAdapterBridge(ViewGroup viewGroup, BaseAdapter adapter) {
+            mViewGroup = new WeakReference<>(viewGroup);
+            mAdapter = adapter;
+            mReleased = false;
+            mAdapter.registerDataSetObserver(this);
+            refresh();
+        }
+
+        private void refresh() {
+            if (mReleased) {
+                return;
+            }
+            ViewGroup viewGroup = mViewGroup.get();
+            if (viewGroup == null) {
+                release();
+                return;
+            }
+            final int childCount = viewGroup.getChildCount();
+            final int adapterCount = mAdapter.getCount();
+            final int N = Math.max(childCount, adapterCount);
+            for (int i = 0; i < N; i++) {
+                if (i < adapterCount) {
+                    View oldView = null;
+                    if (i < childCount) {
+                        oldView = viewGroup.getChildAt(i);
+                    }
+                    View newView = mAdapter.getView(i, oldView, viewGroup);
+                    if (oldView == null) {
+                        // We ran out of existing views. Add it at the end.
+                        viewGroup.addView(newView);
+                    } else if (oldView != newView) {
+                        // We couldn't rebind the view. Replace it.
+                        viewGroup.removeViewAt(i);
+                        viewGroup.addView(newView, i);
+                    }
+                } else {
+                    int lastIndex = viewGroup.getChildCount() - 1;
+                    viewGroup.removeViewAt(lastIndex);
+                }
+            }
+        }
+
+        @Override
+        public void onChanged() {
+            refresh();
+        }
+
+        @Override
+        public void onInvalidated() {
+            release();
+        }
+
+        private void release() {
+            if (!mReleased) {
+                mReleased = true;
+                mAdapter.unregisterDataSetObserver(this);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 59f3b3d..3679b4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -326,8 +326,11 @@
         if (mFooter.hasFooter()) {
             h += mFooter.getView().getHeight();
         }
-        mDetail.measure(exactly(width), exactly(h));
-        setMeasuredDimension(width, h);
+        mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+        if (mDetail.getMeasuredHeight() < h) {
+            mDetail.measure(exactly(width), exactly(h));
+        }
+        setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
     }
 
     private static int exactly(int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 8cff81a..c524edc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -17,45 +17,24 @@
 package com.android.systemui.qs.tiles;
 
 import com.android.systemui.R;
+import com.android.systemui.qs.PseudoGridView;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 import android.content.Context;
-import android.content.Intent;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.GridView;
 
 /**
  * Quick settings detail view for user switching.
  */
-public class UserDetailView extends GridView {
+public class UserDetailView extends PseudoGridView {
 
-    public UserDetailView(Context context) {
-        this(context, null);
-    }
+    private Adapter mAdapter;
 
     public UserDetailView(Context context, AttributeSet attrs) {
-        this(context, attrs, android.R.attr.gridViewStyle);
-    }
-
-    public UserDetailView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public UserDetailView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-
-        setOnItemClickListener(new OnItemClickListener() {
-            @Override
-            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-                UserSwitcherController.UserRecord tag =
-                        (UserSwitcherController.UserRecord) view.getTag();
-                ((Adapter)getAdapter()).switchTo(tag);
-            }
-        });
+        super(context, attrs);
     }
 
     public static UserDetailView inflate(Context context, ViewGroup parent, boolean attach) {
@@ -64,10 +43,12 @@
     }
 
     public void createAndSetAdapter(UserSwitcherController controller) {
-        setAdapter(new Adapter(mContext, controller));
+        mAdapter = new Adapter(mContext, controller);
+        ViewGroupAdapterBridge.link(this, mAdapter);
     }
 
-    public static class Adapter extends UserSwitcherController.BaseUserAdapter {
+    public static class Adapter extends UserSwitcherController.BaseUserAdapter
+            implements OnClickListener {
 
         private Context mContext;
 
@@ -81,6 +62,9 @@
             UserSwitcherController.UserRecord item = getItem(position);
             UserDetailItemView v = UserDetailItemView.convertOrInflate(
                     mContext, convertView, parent);
+            if (v != convertView) {
+                v.setOnClickListener(this);
+            }
             String name = getName(mContext, item);
             if (item.picture == null) {
                 v.bind(name, getDrawable(mContext, item));
@@ -91,5 +75,12 @@
             v.setTag(item);
             return v;
         }
+
+        @Override
+        public void onClick(View view) {
+            UserSwitcherController.UserRecord tag =
+                    (UserSwitcherController.UserRecord) view.getTag();
+            switchTo(tag);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index c48f3f5..a1993f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -465,12 +465,12 @@
 
         @Override
         public View createDetailView(Context context, View convertView, ViewGroup parent) {
+            UserDetailView v;
             if (!(convertView instanceof UserDetailView)) {
-                convertView = UserDetailView.inflate(context, parent, false);
-            }
-            UserDetailView v = (UserDetailView) convertView;
-            if (v.getAdapter() == null) {
+                v = UserDetailView.inflate(context, parent, false);
                 v.createAndSetAdapter(UserSwitcherController.this);
+            } else {
+                v = (UserDetailView) convertView;
             }
             return v;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 2e97d18..6c4fb7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -29,11 +29,13 @@
     Uri getExitConditionId();
     long getNextAlarm();
     void setUserId(int userId);
+    boolean isZenAvailable();
 
     public static class Callback {
         public void onZenChanged(int zen) {}
         public void onExitConditionChanged(Uri exitConditionId) {}
         public void onConditionsChanged(Condition[] conditions) {}
         public void onNextAlarmChanged() {}
+        public void onZenAvailableChanged(boolean available) {}
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index a3cdd41..9d3dec8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -20,15 +20,18 @@
 import android.app.AlarmManager;
 import android.app.INotificationManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
 import android.service.notification.Condition;
 import android.service.notification.IConditionListener;
 import android.service.notification.ZenModeConfig;
@@ -52,6 +55,7 @@
     private final INotificationManager mNoMan;
     private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
     private final AlarmManager mAlarmManager;
+    private final SetupObserver mSetupObserver;
 
     private int mUserId;
     private boolean mRequesting;
@@ -76,6 +80,8 @@
         mNoMan = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        mSetupObserver = new SetupObserver(handler);
+        mSetupObserver.register();
     }
 
     @Override
@@ -99,6 +105,11 @@
     }
 
     @Override
+    public boolean isZenAvailable() {
+        return mSetupObserver.isDeviceProvisioned() && mSetupObserver.isUserSetup();
+    }
+
+    @Override
     public void requestConditions(boolean request) {
         mRequesting = request;
         try {
@@ -148,6 +159,7 @@
         mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId),
                 new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED), null, null);
         mRegistered = true;
+        mSetupObserver.register();
     }
 
     private void fireNextAlarmChanged() {
@@ -162,6 +174,12 @@
         }
     }
 
+    private void fireZenAvailableChanged(boolean available) {
+        for (Callback cb : mCallbacks) {
+            cb.onZenAvailableChanged(available);
+        }
+    }
+
     private void fireConditionsChanged(Condition[] conditions) {
         for (Callback cb : mCallbacks) {
             cb.onConditionsChanged(conditions);
@@ -204,4 +222,42 @@
             }
         }
     };
+
+    private final class SetupObserver extends ContentObserver {
+        private final ContentResolver mResolver;
+
+        private boolean mRegistered;
+
+        public SetupObserver(Handler handler) {
+            super(handler);
+            mResolver = mContext.getContentResolver();
+        }
+
+        public boolean isUserSetup() {
+            return Secure.getIntForUser(mResolver, Secure.USER_SETUP_COMPLETE, 0, mUserId) != 0;
+        }
+
+        public boolean isDeviceProvisioned() {
+            return Global.getInt(mResolver, Global.DEVICE_PROVISIONED, 0) != 0;
+        }
+
+        public void register() {
+            if (mRegistered) {
+                mResolver.unregisterContentObserver(this);
+            }
+            mResolver.registerContentObserver(
+                    Global.getUriFor(Global.DEVICE_PROVISIONED), false, this);
+            mResolver.registerContentObserver(
+                    Secure.getUriFor(Secure.USER_SETUP_COMPLETE), false, this, mUserId);
+            fireZenAvailableChanged(isZenAvailable());
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (Global.getUriFor(Global.DEVICE_PROVISIONED).equals(uri)
+                    || Secure.getUriFor(Secure.USER_SETUP_COMPLETE).equals(uri)) {
+                fireZenAvailableChanged(isZenAvailable());
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 3a63a79..5233da2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -107,7 +107,7 @@
     private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
     private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
     private static final int MSG_LAYOUT_DIRECTION = 12;
-    private static final int MSG_ZEN_MODE_CHANGED = 13;
+    private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13;
     private static final int MSG_USER_ACTIVITY = 14;
 
     // Pseudo stream type for master volume
@@ -125,7 +125,7 @@
     private final ZenModeController mZenController;
     private boolean mRingIsSilent;
     private boolean mVoiceCapable;
-    private boolean mZenModeCapable;
+    private boolean mZenModeAvailable;
     private boolean mZenPanelExpanded;
     private int mTimeoutDelay = TIMEOUT_DELAY;
     private float mDisabledAlpha;
@@ -405,9 +405,10 @@
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
 
-        mZenModeCapable = !useMasterVolume && mZenController != null;
-        updateZenMode(mZenController != null ? mZenController.getZen() : Global.ZEN_MODE_OFF);
-        mZenController.addCallback(mZenCallback);
+        if (mZenController != null && !useMasterVolume) {
+            mZenModeAvailable = mZenController.isZenAvailable();
+            mZenController.addCallback(mZenCallback);
+        }
 
         final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
         final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
@@ -434,7 +435,7 @@
         pw.print("  mTag="); pw.println(mTag);
         pw.print("  mRingIsSilent="); pw.println(mRingIsSilent);
         pw.print("  mVoiceCapable="); pw.println(mVoiceCapable);
-        pw.print("  mZenModeCapable="); pw.println(mZenModeCapable);
+        pw.print("  mZenModeAvailable="); pw.println(mZenModeAvailable);
         pw.print("  mZenPanelExpanded="); pw.println(mZenPanelExpanded);
         pw.print("  mTimeoutDelay="); pw.println(mTimeoutDelay);
         pw.print("  mDisabledAlpha="); pw.println(mDisabledAlpha);
@@ -645,7 +646,7 @@
             active.group.setVisibility(View.VISIBLE);
             updateSlider(active);
             updateTimeoutDelay();
-            setZenPanelVisible(isNotificationOrRing(mActiveStreamType));
+            updateZenPanelVisible();
         }
     }
 
@@ -776,14 +777,8 @@
         }
     }
 
-    private void updateZenMode(int zen) {
-        final boolean show = mZenModeCapable && isNotificationOrRing(mActiveStreamType);
-        setZenPanelVisible(show);
-    }
-
-    public void postZenModeChanged(int zen) {
-        removeMessages(MSG_ZEN_MODE_CHANGED);
-        obtainMessage(MSG_ZEN_MODE_CHANGED, zen).sendToTarget();
+    private void updateZenPanelVisible() {
+        setZenPanelVisible(mZenModeAvailable && isNotificationOrRing(mActiveStreamType));
     }
 
     public void postVolumeChanged(int streamType, int flags) {
@@ -1307,8 +1302,9 @@
                 setLayoutDirection(msg.arg1);
                 break;
 
-            case MSG_ZEN_MODE_CHANGED:
-                updateZenMode(msg.arg1);
+            case MSG_ZEN_MODE_AVAILABLE_CHANGED:
+                mZenModeAvailable = msg.arg1 != 0;
+                updateZenPanelVisible();
                 break;
 
             case MSG_USER_ACTIVITY:
@@ -1359,8 +1355,8 @@
     };
 
     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
-        public void onZenChanged(int zen) {
-            postZenModeChanged(zen);
+        public void onZenAvailableChanged(boolean available) {
+            obtainMessage(MSG_ZEN_MODE_AVAILABLE_CHANGED, available ? 1 : 0, 0).sendToTarget();
         }
     };
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c5bc7d3..4653742 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1099,6 +1099,51 @@
         }
     }
 
+    // Find the first visible activity above the passed activity and if it is translucent return it
+    // otherwise return null;
+    ActivityRecord findNextTranslucentActivity(ActivityRecord r) {
+        TaskRecord task = r.task;
+        if (task == null) {
+            return null;
+        }
+
+        ActivityStack stack = task.stack;
+        if (stack == null) {
+            return null;
+        }
+
+        int stackNdx = mStacks.indexOf(stack);
+
+        ArrayList<TaskRecord> tasks = stack.mTaskHistory;
+        int taskNdx = tasks.indexOf(task);
+
+        ArrayList<ActivityRecord> activities = task.mActivities;
+        int activityNdx = activities.indexOf(r) + 1;
+
+        final int numStacks = mStacks.size();
+        while (stackNdx < numStacks) {
+            tasks = mStacks.get(stackNdx).mTaskHistory;
+            final int numTasks = tasks.size();
+            while (taskNdx < numTasks) {
+                activities = tasks.get(taskNdx).mActivities;
+                final int numActivities = activities.size();
+                while (activityNdx < numActivities) {
+                    final ActivityRecord activity = activities.get(activityNdx);
+                    if (!activity.finishing) {
+                        return activity.fullscreen ? null : activity;
+                    }
+                    ++activityNdx;
+                }
+                activityNdx = 0;
+                ++taskNdx;
+            }
+            taskNdx = 0;
+            ++stackNdx;
+        }
+
+        return null;
+    }
+
     // Checks if any of the stacks above this one has a fullscreen activity behind it.
     // If so, this stack is hidden, otherwise it is visible.
     private boolean isStackVisible() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index b4e66c1..4a99ef3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2680,6 +2680,13 @@
         }
 
         stack.setMediaPlayer(playing ? r : null);
+        if (!playing) {
+            // Make the activity immediately above r opaque.
+            final ActivityRecord next = stack.findNextTranslucentActivity(r);
+            if (next != null) {
+                mService.convertFromTranslucent(next.appToken);
+            }
+        }
         try {
             top.app.thread.scheduleBackgroundMediaPlayingChanged(top.appToken, playing);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ColorFade.java
similarity index 65%
rename from services/core/java/com/android/server/display/ElectronBeam.java
rename to services/core/java/com/android/server/display/ColorFade.java
index 18e4049..920fdfb 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -16,11 +16,16 @@
 
 package com.android.server.display;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
 
+import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManagerInternal;
@@ -30,9 +35,8 @@
 import android.opengl.EGLContext;
 import android.opengl.EGLDisplay;
 import android.opengl.EGLSurface;
-import android.opengl.GLES10;
+import android.opengl.GLES20;
 import android.opengl.GLES11Ext;
-import android.os.Looper;
 import android.util.FloatMath;
 import android.util.Slog;
 import android.view.DisplayInfo;
@@ -41,10 +45,12 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
+import libcore.io.Streams;
+
 import com.android.server.LocalServices;
+import com.android.internal.R;
 
 /**
- * Bzzzoooop!  *crackle*
  * <p>
  * Animates a screen transition from on to off or off to on by applying
  * some GL transformations to a screenshot.
@@ -53,20 +59,14 @@
  * that belongs to the {@link DisplayPowerController}.
  * </p>
  */
-final class ElectronBeam {
-    private static final String TAG = "ElectronBeam";
+final class ColorFade {
+    private static final String TAG = "ColorFade";
 
     private static final boolean DEBUG = false;
 
     // The layer for the electron beam surface.
     // This is currently hardcoded to be one layer above the boot animation.
-    private static final int ELECTRON_BEAM_LAYER = 0x40000001;
-
-    // The relative proportion of the animation to spend performing
-    // the horizontal stretch effect.  The remainder is spent performing
-    // the vertical stretch effect.
-    private static final float HSTRETCH_DURATION = 0.5f;
-    private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
+    private static final int COLOR_FADE_LAYER = 0x40000001;
 
     // The number of frames to draw when preparing the animation so that it will
     // be ready to run smoothly.  We use 3 frames because we are triple-buffered.
@@ -98,6 +98,11 @@
     private final int[] mTexNames = new int[1];
     private boolean mTexNamesGenerated;
     private final float mTexMatrix[] = new float[16];
+    private final float mProjMatrix[] = new float[16];
+    private final int[] mGLBuffers = new int[2];
+    private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
+    private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc;
+    private int mProgram;
 
     // Vertex and corresponding texture coordinates.
     // We have 4 2D vertices, so 8 elements.  The vertices form a quad.
@@ -105,12 +110,12 @@
     private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
 
     /**
-     * Animates an electron beam warming up.
+     * Animates an color fade warming up.
      */
     public static final int MODE_WARM_UP = 0;
 
     /**
-     * Animates an electron beam shutting off.
+     * Animates an color fade shutting off.
      */
     public static final int MODE_COOL_DOWN = 1;
 
@@ -119,19 +124,19 @@
      */
     public static final int MODE_FADE = 2;
 
-    public ElectronBeam(int displayId) {
+    public ColorFade(int displayId) {
         mDisplayId = displayId;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
     /**
-     * Warms up the electron beam in preparation for turning on or off.
+     * Warms up the color fade in preparation for turning on or off.
      * This method prepares a GL context, and captures a screen shot.
      *
      * @param mode The desired mode for the upcoming animation.
-     * @return True if the electron beam is ready, false if it is uncontrollable.
+     * @return True if the color fade is ready, false if it is uncontrollable.
      */
-    public boolean prepare(int mode) {
+    public boolean prepare(Context context, int mode) {
         if (DEBUG) {
             Slog.d(TAG, "prepare: mode=" + mode);
         }
@@ -139,18 +144,33 @@
         mMode = mode;
 
         // Get the display size and layer stack.
-        // This is not expected to change while the electron beam surface is showing.
+        // This is not expected to change while the color fade surface is showing.
         DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
 
         // Prepare the surface for drawing.
-        if (!tryPrepare()) {
+        if (!(createSurface() && createEglContext() && createEglSurface() &&
+              captureScreenshotTextureAndSetViewport())) {
             dismiss();
             return false;
         }
 
+        // Init GL
+        if (!attachEglContext()) {
+            return false;
+        }
+        try {
+            if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
+                detachEglContext();
+                dismiss();
+                return false;
+            }
+        } finally {
+            detachEglContext();
+        }
+
         // Done.
         mPrepared = true;
 
@@ -169,24 +189,125 @@
         return true;
     }
 
-    private boolean tryPrepare() {
-        if (createSurface()) {
-            if (mMode == MODE_FADE) {
-                return true;
-            }
-            return createEglContext()
-                    && createEglSurface()
-                    && captureScreenshotTextureAndSetViewport();
+    private String readFile(Context context, int resourceId) {
+        try{
+            InputStream stream = context.getResources().openRawResource(resourceId);
+            return new String(Streams.readFully(new InputStreamReader(stream)));
         }
-        return false;
+        catch (IOException e) {
+            Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
+            throw new RuntimeException(e);
+        }
+    }
+
+    private int loadShader(Context context, int resourceId, int type) {
+        String source = readFile(context, resourceId);
+
+        int shader = GLES20.glCreateShader(type);
+
+        GLES20.glShaderSource(shader, source);
+        GLES20.glCompileShader(shader);
+
+        int[] compiled = new int[1];
+        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+        if (compiled[0] == 0) {
+            Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
+            Slog.e(TAG, GLES20.glGetShaderSource(shader));
+            Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
+            GLES20.glDeleteShader(shader);
+            shader = 0;
+        }
+
+        return shader;
+    }
+
+    private boolean initGLShaders(Context context) {
+        int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
+                GLES20.GL_VERTEX_SHADER);
+        int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
+                GLES20.GL_FRAGMENT_SHADER);
+        if (vshader == 0 || fshader == 0) return false;
+
+        mProgram = GLES20.glCreateProgram();
+
+        GLES20.glAttachShader(mProgram, vshader);
+        GLES20.glAttachShader(mProgram, fshader);
+
+        GLES20.glLinkProgram(mProgram);
+
+        mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
+        mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
+
+        mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
+        mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
+
+        mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
+        mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
+        mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
+        mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale");
+        mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
+
+        GLES20.glUseProgram(mProgram);
+        GLES20.glUniform1i(mTexUnitLoc, 0);
+        GLES20.glUseProgram(0);
+
+        return true;
+    }
+
+    private boolean initGLBuffers() {
+        //Fill vertices
+        setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
+
+        // Setup GL Textures
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+                GLES20.GL_NEAREST);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+                GLES20.GL_NEAREST);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
+                GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
+                GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+
+        // Setup GL Buffers
+        GLES20.glGenBuffers(2, mGLBuffers, 0);
+
+        // fill vertex buffer
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
+        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
+                            mVertexBuffer, GLES20.GL_STATIC_DRAW);
+
+        // fill tex buffer
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
+        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
+                            mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
+
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+        return true;
+    }
+
+    private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
+        if (DEBUG) {
+            Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
+        }
+        vtx.put(0, x);
+        vtx.put(1, y);
+        vtx.put(2, x);
+        vtx.put(3, y + h);
+        vtx.put(4, x + w);
+        vtx.put(5, y + h);
+        vtx.put(6, x + w);
+        vtx.put(7, y);
     }
 
     /**
-     * Dismisses the electron beam animation surface and cleans up.
+     * Dismisses the color fade animation surface and cleans up.
      *
-     * To prevent stray photons from leaking out after the electron beam has been
+     * To prevent stray photons from leaking out after the color fade has been
      * turned off, it is a good idea to defer dismissing the animation until the
-     * electron beam has been turned back on fully.
+     * color fade has been turned back on fully.
      */
     public void dismiss() {
         if (DEBUG) {
@@ -200,10 +321,10 @@
     }
 
     /**
-     * Draws an animation frame showing the electron beam activated at the
+     * Draws an animation frame showing the color fade activated at the
      * specified level.
      *
-     * @param level The electron beam level.
+     * @param level The color fade level.
      * @return True if successful.
      */
     public boolean draw(float level) {
@@ -224,15 +345,18 @@
         }
         try {
             // Clear frame to solid black.
-            GLES10.glClearColor(0f, 0f, 0f, 1f);
-            GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
+            GLES20.glClearColor(0f, 0f, 0f, 1f);
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
 
             // Draw the frame.
-            if (level < HSTRETCH_DURATION) {
-                drawHStretch(1.0f - (level / HSTRETCH_DURATION));
-            } else {
-                drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION));
-            }
+            float one_minus_level = 1 - level;
+            float cos = FloatMath.cos((float)Math.PI * one_minus_level);
+            float sign = cos < 0 ? -1 : 1;
+            float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
+            float saturation = FloatMath.pow(level, 4);
+            float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
+            float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
+            drawFaded(opacity, 1.f / gamma, saturation, scale);
             if (checkGlErrors("drawFrame")) {
                 return false;
             }
@@ -244,139 +368,59 @@
         return showSurface(1.0f);
     }
 
-    /**
-     * Draws a frame where the content of the electron beam is collapsing inwards upon
-     * itself vertically with red / green / blue channels dispersing and eventually
-     * merging down to a single horizontal line.
-     *
-     * @param stretch The stretch factor.  0.0 is no collapse, 1.0 is full collapse.
-     */
-    private void drawVStretch(float stretch) {
-        // compute interpolation scale factors for each color channel
-        final float ar = scurve(stretch, 7.5f);
-        final float ag = scurve(stretch, 8.0f);
-        final float ab = scurve(stretch, 8.5f);
+    private void drawFaded(float opacity, float gamma, float saturation, float scale) {
         if (DEBUG) {
-            Slog.d(TAG, "drawVStretch: stretch=" + stretch
-                    + ", ar=" + ar + ", ag=" + ag + ", ab=" + ab);
+            Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
+                        ", saturation=" + saturation + ", scale=" + scale);
         }
+        // Use shaders
+        GLES20.glUseProgram(mProgram);
 
-        // set blending
-        GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE);
-        GLES10.glEnable(GLES10.GL_BLEND);
+        // Set Uniforms
+        GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
+        GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
+        GLES20.glUniform1f(mOpacityLoc, opacity);
+        GLES20.glUniform1f(mGammaLoc, gamma);
+        GLES20.glUniform1f(mSaturationLoc, saturation);
+        GLES20.glUniform1f(mScaleLoc, scale);
 
-        // bind vertex buffer
-        GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
-        GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
+        // Use textures
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
 
-        // set-up texturing
-        GLES10.glDisable(GLES10.GL_TEXTURE_2D);
-        GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
+        // draw the plane
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
+        GLES20.glEnableVertexAttribArray(mVertexLoc);
+        GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
 
-        // bind texture and set blending for drawing planes
-        GLES10.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
-        GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
-                mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE);
-        GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
-                GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE);
-        GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
-        GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer);
-        GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
+        GLES20.glEnableVertexAttribArray(mTexCoordLoc);
+        GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
 
-        // draw the red plane
-        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar);
-        GLES10.glColorMask(true, false, false, true);
-        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-        // draw the green plane
-        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
-        GLES10.glColorMask(false, true, false, true);
-        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-        // draw the blue plane
-        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab);
-        GLES10.glColorMask(false, false, true, true);
-        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-        // clean up after drawing planes
-        GLES10.glDisable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
-        GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
-        GLES10.glColorMask(true, true, true, true);
-
-        // draw the white highlight (we use the last vertices)
-        if (mMode == MODE_COOL_DOWN) {
-            GLES10.glColor4f(ag, ag, ag, 1.0f);
-            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-        }
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
 
         // clean up
-        GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
-        GLES10.glDisable(GLES10.GL_BLEND);
+        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
     }
 
-    /**
-     * Draws a frame where the electron beam has been stretched out into
-     * a thin white horizontal line that fades as it collapses inwards.
-     *
-     * @param stretch The stretch factor.  0.0 is maximum stretch / no fade,
-     * 1.0 is collapsed / maximum fade.
-     */
-    private void drawHStretch(float stretch) {
-        // compute interpolation scale factor
-        final float ag = scurve(stretch, 8.0f);
-        if (DEBUG) {
-            Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag);
-        }
-
-        if (stretch < 1.0f) {
-            // bind vertex buffer
-            GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
-            GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
-
-            // draw narrow fading white line
-            setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
-            GLES10.glColor4f(1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f);
-            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
-            // clean up
-            GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
-        }
-    }
-
-    private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
-        final float w = dw + (dw * a);
-        final float h = dh - (dh * a);
-        final float x = (dw - w) * 0.5f;
-        final float y = (dh - h) * 0.5f;
-        setQuad(vtx, x, y, w, h);
-    }
-
-    private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
-        final float w = 2 * dw * (1.0f - a);
-        final float h = 1.0f;
-        final float x = (dw - w) * 0.5f;
-        final float y = (dh - h) * 0.5f;
-        setQuad(vtx, x, y, w, h);
-    }
-
-    private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
-        if (DEBUG) {
-            Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
-        }
-        vtx.put(0, x);
-        vtx.put(1, y);
-        vtx.put(2, x);
-        vtx.put(3, y + h);
-        vtx.put(4, x + w);
-        vtx.put(5, y + h);
-        vtx.put(6, x + w);
-        vtx.put(7, y);
+    private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
+        mProjMatrix[0] = 2f / (right - left);
+        mProjMatrix[1] = 0;
+        mProjMatrix[2] = 0;
+        mProjMatrix[3] = 0;
+        mProjMatrix[4] = 0;
+        mProjMatrix[5] = 2f / (top - bottom);
+        mProjMatrix[6] = 0;
+        mProjMatrix[7] = 0;
+        mProjMatrix[8] = 0;
+        mProjMatrix[9] = 0;
+        mProjMatrix[10] = -2f / (zfar - znear);
+        mProjMatrix[11] = 0;
+        mProjMatrix[12] = -(right + left) / (right - left);
+        mProjMatrix[13] = -(top + bottom) / (top - bottom);
+        mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
+        mProjMatrix[15] = 1f;
     }
 
     private boolean captureScreenshotTextureAndSetViewport() {
@@ -385,7 +429,7 @@
         }
         try {
             if (!mTexNamesGenerated) {
-                GLES10.glGenTextures(1, mTexNames, 0);
+                GLES20.glGenTextures(1, mTexNames, 0);
                 if (checkGlErrors("glGenTextures")) {
                     return false;
                 }
@@ -413,15 +457,8 @@
             mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
 
             // Set up our viewport.
-            GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
-            GLES10.glMatrixMode(GLES10.GL_PROJECTION);
-            GLES10.glLoadIdentity();
-            GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1);
-            GLES10.glMatrixMode(GLES10.GL_MODELVIEW);
-            GLES10.glLoadIdentity();
-            GLES10.glMatrixMode(GLES10.GL_TEXTURE);
-            GLES10.glLoadIdentity();
-            GLES10.glLoadMatrixf(mTexMatrix, 0);
+            GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
+            ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
         } finally {
             detachEglContext();
         }
@@ -433,7 +470,7 @@
             mTexNamesGenerated = false;
             if (attachEglContext()) {
                 try {
-                    GLES10.glDeleteTextures(1, mTexNames, 0);
+                    GLES20.glDeleteTextures(1, mTexNames, 0);
                     checkGlErrors("glDeleteTextures");
                 } finally {
                     detachEglContext();
@@ -460,6 +497,8 @@
 
         if (mEglConfig == null) {
             int[] eglConfigAttribList = new int[] {
+                    EGL14.EGL_RENDERABLE_TYPE,
+                    EGL14.EGL_OPENGL_ES2_BIT,
                     EGL14.EGL_RED_SIZE, 8,
                     EGL14.EGL_GREEN_SIZE, 8,
                     EGL14.EGL_BLUE_SIZE, 8,
@@ -478,6 +517,7 @@
 
         if (mEglContext == null) {
             int[] eglContextAttribList = new int[] {
+                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                     EGL14.EGL_NONE
             };
             mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
@@ -490,16 +530,6 @@
         return true;
     }
 
-    /* not used because it is too expensive to create / destroy contexts all of the time
-    private void destroyEglContext() {
-        if (mEglContext != null) {
-            if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) {
-                logEglError("eglDestroyContext");
-            }
-            mEglContext = null;
-        }
-    }*/
-
     private boolean createSurface() {
         if (mSurfaceSession == null) {
             mSurfaceSession = new SurfaceSession();
@@ -516,7 +546,7 @@
                         flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
                     }
                     mSurfaceControl = new SurfaceControl(mSurfaceSession,
-                            "ElectronBeam", mDisplayWidth, mDisplayHeight,
+                            "ColorFade", mDisplayWidth, mDisplayHeight,
                             PixelFormat.OPAQUE, flags);
                 } catch (OutOfResourcesException ex) {
                     Slog.e(TAG, "Unable to create surface.", ex);
@@ -584,7 +614,7 @@
         if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
             SurfaceControl.openTransaction();
             try {
-                mSurfaceControl.setLayer(ELECTRON_BEAM_LAYER);
+                mSurfaceControl.setLayer(COLOR_FADE_LAYER);
                 mSurfaceControl.setAlpha(alpha);
                 mSurfaceControl.show();
             } finally {
@@ -614,34 +644,6 @@
         }
     }
 
-    /**
-     * Interpolates a value in the range 0 .. 1 along a sigmoid curve
-     * yielding a result in the range 0 .. 1 scaled such that:
-     * scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1.
-     */
-    private static float scurve(float value, float s) {
-        // A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s).
-        // Here we take the input datum and shift it by 0.5 so that the
-        // domain spans the range -0.5 .. 0.5 instead of 0 .. 1.
-        final float x = value - 0.5f;
-
-        // Next apply the sigmoid function to the scaled value
-        // which produces a value in the range 0 .. 1 so we subtract
-        // 0.5 to get a value in the range -0.5 .. 0.5 instead.
-        final float y = sigmoid(x, s) - 0.5f;
-
-        // To obtain the desired boundary conditions we need to scale
-        // the result so that it fills a range of -1 .. 1.
-        final float v = sigmoid(0.5f, s) - 0.5f;
-
-        // And finally remap the value back to a range of 0 .. 1.
-        return y / v * 0.5f + 0.5f;
-    }
-
-    private static float sigmoid(float x, float s) {
-        return 1.0f / (1.0f + FloatMath.exp(-x * s));
-    }
-
     private static FloatBuffer createNativeFloatBuffer(int size) {
         ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
         bb.order(ByteOrder.nativeOrder());
@@ -659,7 +661,7 @@
     private static boolean checkGlErrors(String func, boolean log) {
         boolean hadError = false;
         int error;
-        while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) {
+        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
             if (log) {
                 Slog.e(TAG, func + " failed: error " + error, new Throwable());
             }
@@ -670,7 +672,7 @@
 
     public void dump(PrintWriter pw) {
         pw.println();
-        pw.println("Electron Beam State:");
+        pw.println("Color Fade State:");
         pw.println("  mPrepared=" + mPrepared);
         pw.println("  mMode=" + mMode);
         pw.println("  mDisplayLayerStack=" + mDisplayLayerStack);
@@ -685,7 +687,7 @@
      * Updates the position and transformation of the matrix whenever the display
      * is rotated.  This is a little tricky because the display transaction
      * callback can be invoked on any thread, not necessarily the thread that
-     * owns the electron beam.
+     * owns the color fade.
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
         private final DisplayManagerInternal mDisplayManagerInternal;
@@ -725,7 +727,8 @@
                         mSurfaceControl.setMatrix(0, -1, 1, 0);
                         break;
                     case Surface.ROTATION_180:
-                        mSurfaceControl.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
+                        mSurfaceControl.setPosition(displayInfo.logicalWidth,
+                                displayInfo.logicalHeight);
                         mSurfaceControl.setMatrix(-1, 0, 0, -1);
                         break;
                     case Surface.ROTATION_270:
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d0e4b33..9a67321 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -64,7 +64,7 @@
  * blocker as long as the display is not ready.  So most of the work done here
  * does not need to worry about holding a suspend blocker unless it happens
  * independently of the display ready signal.
- *
+   *
  * For debugging, you can make the electron beam and brightness animations run
  * slower by changing the "animator duration scale" option in Development Settings.
  */
@@ -78,14 +78,14 @@
     // We might want to turn this off if we cannot get a guarantee that the screen
     // actually turns on and starts showing new content after the call to set the
     // screen state returns.  Playing the animation can also be somewhat slow.
-    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
+    private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
 
 
     // The minimum reduction in brightness when dimmed.
     private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
 
-    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
-    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
+    private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
+    private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 600;
 
     private static final int MSG_UPDATE_POWER_STATE = 1;
     private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
@@ -107,6 +107,8 @@
 
     private final Object mLock = new Object();
 
+    private final Context mContext;
+
     // Our handler.
     private final DisplayControllerHandler mHandler;
 
@@ -146,7 +148,7 @@
 
     // True if we should fade the screen while turning it off, false if we should play
     // a stylish electron beam animation instead.
-    private boolean mElectronBeamFadesConfig;
+    private boolean mColorFadeFadesConfig;
 
     // The pending power request.
     // Initially null until the first call to requestPowerState.
@@ -223,8 +225,8 @@
     private AutomaticBrightnessController mAutomaticBrightnessController;
 
     // Animators.
-    private ObjectAnimator mElectronBeamOnAnimator;
-    private ObjectAnimator mElectronBeamOffAnimator;
+    private ObjectAnimator mColorFadeOnAnimator;
+    private ObjectAnimator mColorFadeOffAnimator;
     private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
 
     /**
@@ -240,6 +242,7 @@
         mLights = LocalServices.getService(LightsManager.class);
         mSensorManager = sensorManager;
         mBlanker = blanker;
+        mContext = context;
 
         final Resources resources = context.getResources();
 
@@ -287,7 +290,7 @@
 
         mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
 
-        mElectronBeamFadesConfig = resources.getBoolean(
+        mColorFadeFadesConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_animateScreenLights);
 
         if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
@@ -378,17 +381,17 @@
         // In the future, we might manage multiple displays independently.
         mPowerState = new DisplayPowerState(mBlanker,
                 mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
-                new ElectronBeam(Display.DEFAULT_DISPLAY));
+                new ColorFade(Display.DEFAULT_DISPLAY));
 
-        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
-                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
-        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
-        mElectronBeamOnAnimator.addListener(mAnimatorListener);
+        mColorFadeOnAnimator = ObjectAnimator.ofFloat(
+                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
+        mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
+        mColorFadeOnAnimator.addListener(mAnimatorListener);
 
-        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
-                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
-        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
-        mElectronBeamOffAnimator.addListener(mAnimatorListener);
+        mColorFadeOffAnimator = ObjectAnimator.ofFloat(
+                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
+        mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
+        mColorFadeOffAnimator.addListener(mAnimatorListener);
 
         mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
                 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
@@ -600,34 +603,34 @@
             // Wait for previous off animation to complete beforehand.
             // It is relatively short but if we cancel it and switch to the
             // on animation immediately then the results are pretty ugly.
-            if (!mElectronBeamOffAnimator.isStarted()) {
+            if (!mColorFadeOffAnimator.isStarted()) {
                 // Turn the screen on.  The contents of the screen may not yet
                 // be visible if the electron beam has not been dismissed because
                 // its last frame of animation is solid black.
                 setScreenState(Display.STATE_ON);
                 if (mPowerRequest.blockScreenOn
-                        && mPowerState.getElectronBeamLevel() == 0.0f) {
+                        && mPowerState.getColorFadeLevel() == 0.0f) {
                     blockScreenOn();
                 } else {
                     unblockScreenOn();
-                    if (USE_ELECTRON_BEAM_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
+                    if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
                         // Perform screen on animation.
-                        if (!mElectronBeamOnAnimator.isStarted()) {
-                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
-                                mPowerState.dismissElectronBeam();
-                            } else if (mPowerState.prepareElectronBeam(
-                                    mElectronBeamFadesConfig ?
-                                            ElectronBeam.MODE_FADE :
-                                                    ElectronBeam.MODE_WARM_UP)) {
-                                mElectronBeamOnAnimator.start();
+                        if (!mColorFadeOnAnimator.isStarted()) {
+                            if (mPowerState.getColorFadeLevel() == 1.0f) {
+                                mPowerState.dismissColorFade();
+                            } else if (mPowerState.prepareColorFade(mContext,
+                                    mColorFadeFadesConfig ?
+                                            ColorFade.MODE_FADE :
+                                                    ColorFade.MODE_WARM_UP)) {
+                                mColorFadeOnAnimator.start();
                             } else {
-                                mElectronBeamOnAnimator.end();
+                                mColorFadeOnAnimator.end();
                             }
                         }
                     } else {
                         // Skip screen on animation.
-                        mPowerState.setElectronBeamLevel(1.0f);
-                        mPowerState.dismissElectronBeam();
+                        mPowerState.setColorFadeLevel(1.0f);
+                        mPowerState.dismissColorFade();
                     }
                 }
             }
@@ -640,8 +643,8 @@
                     || mPowerState.getScreenState() != Display.STATE_ON) {
                 // Set screen state and dismiss the black surface without fanfare.
                 setScreenState(state);
-                mPowerState.setElectronBeamLevel(1.0f);
-                mPowerState.dismissElectronBeam();
+                mPowerState.setColorFadeLevel(1.0f);
+                mPowerState.dismissColorFade();
             }
         } else if (state == Display.STATE_DOZE_SUSPEND) {
             // Want screen dozing and suspended.
@@ -652,27 +655,27 @@
                     || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
                 // Set screen state and dismiss the black surface without fanfare.
                 setScreenState(state);
-                mPowerState.setElectronBeamLevel(1.0f);
-                mPowerState.dismissElectronBeam();
+                mPowerState.setColorFadeLevel(1.0f);
+                mPowerState.dismissColorFade();
             }
         } else {
             // Want screen off.
             // Wait for previous on animation to complete beforehand.
             unblockScreenOn();
-            if (!mElectronBeamOnAnimator.isStarted()) {
+            if (!mColorFadeOnAnimator.isStarted()) {
                 if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
                     // Perform screen off animation.
-                    if (!mElectronBeamOffAnimator.isStarted()) {
-                        if (mPowerState.getElectronBeamLevel() == 0.0f) {
+                    if (!mColorFadeOffAnimator.isStarted()) {
+                        if (mPowerState.getColorFadeLevel() == 0.0f) {
                             setScreenState(Display.STATE_OFF);
-                        } else if (mPowerState.prepareElectronBeam(
-                                mElectronBeamFadesConfig ?
-                                        ElectronBeam.MODE_FADE :
-                                                ElectronBeam.MODE_COOL_DOWN)
+                        } else if (mPowerState.prepareColorFade(mContext,
+                                mColorFadeFadesConfig ?
+                                        ColorFade.MODE_FADE :
+                                                ColorFade.MODE_COOL_DOWN)
                                 && mPowerState.getScreenState() != Display.STATE_OFF) {
-                            mElectronBeamOffAnimator.start();
+                            mColorFadeOffAnimator.start();
                         } else {
-                            mElectronBeamOffAnimator.end();
+                            mColorFadeOffAnimator.end();
                         }
                     }
                 } else {
@@ -687,8 +690,8 @@
         // which will be handled asynchronously.
         if (mustNotify
                 && !mScreenOnWasBlocked
-                && !mElectronBeamOnAnimator.isStarted()
-                && !mElectronBeamOffAnimator.isStarted()
+                && !mColorFadeOnAnimator.isStarted()
+                && !mColorFadeOffAnimator.isStarted()
                 && !mScreenBrightnessRampAnimator.isAnimating()
                 && mPowerState.waitUntilClean(mCleanListener)) {
             synchronized (mLock) {
@@ -936,13 +939,13 @@
         pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
                 mScreenBrightnessRampAnimator.isAnimating());
 
-        if (mElectronBeamOnAnimator != null) {
-            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
-                    mElectronBeamOnAnimator.isStarted());
+        if (mColorFadeOnAnimator != null) {
+            pw.println("  mColorFadeOnAnimator.isStarted()=" +
+                    mColorFadeOnAnimator.isStarted());
         }
-        if (mElectronBeamOffAnimator != null) {
-            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
-                    mElectronBeamOffAnimator.isStarted());
+        if (mColorFadeOffAnimator != null) {
+            pw.println("  mColorFadeOffAnimator.isStarted()=" +
+                    mColorFadeOffAnimator.isStarted());
         }
 
         if (mPowerState != null) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 4821e74..6522b89 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,6 +18,7 @@
 
 import com.android.server.lights.Light;
 
+import android.content.Context;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
@@ -56,7 +57,7 @@
     private final Choreographer mChoreographer;
     private final DisplayBlanker mBlanker;
     private final Light mBacklight;
-    private final ElectronBeam mElectronBeam;
+    private final ColorFade mColorFade;
     private final PhotonicModulator mPhotonicModulator;
 
     private int mScreenState;
@@ -64,19 +65,19 @@
     private boolean mScreenReady;
     private boolean mScreenUpdatePending;
 
-    private boolean mElectronBeamPrepared;
-    private float mElectronBeamLevel;
-    private boolean mElectronBeamReady;
-    private boolean mElectronBeamDrawPending;
+    private boolean mColorFadePrepared;
+    private float mColorFadeLevel;
+    private boolean mColorFadeReady;
+    private boolean mColorFadeDrawPending;
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
+    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
         mBlanker = blanker;
         mBacklight = backlight;
-        mElectronBeam = electronBeam;
+        mColorFade = electronBeam;
         mPhotonicModulator = new PhotonicModulator();
 
         // At boot time, we know that the screen is on and the electron beam
@@ -89,21 +90,21 @@
         mScreenBrightness = PowerManager.BRIGHTNESS_ON;
         scheduleScreenUpdate();
 
-        mElectronBeamPrepared = false;
-        mElectronBeamLevel = 1.0f;
-        mElectronBeamReady = true;
+        mColorFadePrepared = false;
+        mColorFadeLevel = 1.0f;
+        mColorFadeReady = true;
     }
 
-    public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
+    public static final FloatProperty<DisplayPowerState> COLOR_FADE_LEVEL =
             new FloatProperty<DisplayPowerState>("electronBeamLevel") {
         @Override
         public void setValue(DisplayPowerState object, float value) {
-            object.setElectronBeamLevel(value);
+            object.setColorFadeLevel(value);
         }
 
         @Override
         public Float get(DisplayPowerState object) {
-            return object.getElectronBeamLevel();
+            return object.getColorFadeLevel();
         }
     };
 
@@ -176,26 +177,26 @@
      * @param mode The electron beam animation mode to prepare.
      * @return True if the electron beam was prepared.
      */
-    public boolean prepareElectronBeam(int mode) {
-        if (!mElectronBeam.prepare(mode)) {
-            mElectronBeamPrepared = false;
-            mElectronBeamReady = true;
+    public boolean prepareColorFade(Context context, int mode) {
+        if (!mColorFade.prepare(context, mode)) {
+            mColorFadePrepared = false;
+            mColorFadeReady = true;
             return false;
         }
 
-        mElectronBeamPrepared = true;
-        mElectronBeamReady = false;
-        scheduleElectronBeamDraw();
+        mColorFadePrepared = true;
+        mColorFadeReady = false;
+        scheduleColorFadeDraw();
         return true;
     }
 
     /**
      * Dismisses the electron beam surface.
      */
-    public void dismissElectronBeam() {
-        mElectronBeam.dismiss();
-        mElectronBeamPrepared = false;
-        mElectronBeamReady = true;
+    public void dismissColorFade() {
+        mColorFade.dismiss();
+        mColorFadePrepared = false;
+        mColorFadeReady = true;
     }
 
     /**
@@ -211,20 +212,20 @@
      *
      * @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
      */
-    public void setElectronBeamLevel(float level) {
-        if (mElectronBeamLevel != level) {
+    public void setColorFadeLevel(float level) {
+        if (mColorFadeLevel != level) {
             if (DEBUG) {
-                Slog.d(TAG, "setElectronBeamLevel: level=" + level);
+                Slog.d(TAG, "setColorFadeLevel: level=" + level);
             }
 
-            mElectronBeamLevel = level;
+            mColorFadeLevel = level;
             if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate(); // update backlight brightness
             }
-            if (mElectronBeamPrepared) {
-                mElectronBeamReady = false;
-                scheduleElectronBeamDraw();
+            if (mColorFadePrepared) {
+                mColorFadeReady = false;
+                scheduleColorFadeDraw();
             }
         }
     }
@@ -232,8 +233,8 @@
     /**
      * Gets the level of the electron beam steering current.
      */
-    public float getElectronBeamLevel() {
-        return mElectronBeamLevel;
+    public float getColorFadeLevel() {
+        return mColorFadeLevel;
     }
 
     /**
@@ -243,7 +244,7 @@
      * The listener always overrides any previously set listener.
      */
     public boolean waitUntilClean(Runnable listener) {
-        if (!mScreenReady || !mElectronBeamReady) {
+        if (!mScreenReady || !mColorFadeReady) {
             mCleanListener = listener;
             return false;
         } else {
@@ -259,13 +260,13 @@
         pw.println("  mScreenBrightness=" + mScreenBrightness);
         pw.println("  mScreenReady=" + mScreenReady);
         pw.println("  mScreenUpdatePending=" + mScreenUpdatePending);
-        pw.println("  mElectronBeamPrepared=" + mElectronBeamPrepared);
-        pw.println("  mElectronBeamLevel=" + mElectronBeamLevel);
-        pw.println("  mElectronBeamReady=" + mElectronBeamReady);
-        pw.println("  mElectronBeamDrawPending=" + mElectronBeamDrawPending);
+        pw.println("  mColorFadePrepared=" + mColorFadePrepared);
+        pw.println("  mColorFadeLevel=" + mColorFadeLevel);
+        pw.println("  mColorFadeReady=" + mColorFadeReady);
+        pw.println("  mColorFadeDrawPending=" + mColorFadeDrawPending);
 
         mPhotonicModulator.dump(pw);
-        mElectronBeam.dump(pw);
+        mColorFade.dump(pw);
     }
 
     private void scheduleScreenUpdate() {
@@ -280,17 +281,17 @@
         mHandler.post(mScreenUpdateRunnable);
     }
 
-    private void scheduleElectronBeamDraw() {
-        if (!mElectronBeamDrawPending) {
-            mElectronBeamDrawPending = true;
+    private void scheduleColorFadeDraw() {
+        if (!mColorFadeDrawPending) {
+            mColorFadeDrawPending = true;
             mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
-                    mElectronBeamDrawRunnable, null);
+                    mColorFadeDrawRunnable, null);
         }
     }
 
     private void invokeCleanListenerIfNeeded() {
         final Runnable listener = mCleanListener;
-        if (listener != null && mScreenReady && mElectronBeamReady) {
+        if (listener != null && mScreenReady && mColorFadeReady) {
             mCleanListener = null;
             listener.run();
         }
@@ -302,7 +303,7 @@
             mScreenUpdatePending = false;
 
             int brightness = mScreenState != Display.STATE_OFF
-                    && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+                    && mColorFadeLevel > 0f ? mScreenBrightness : 0;
             if (mPhotonicModulator.setState(mScreenState, brightness)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Screen ready");
@@ -317,16 +318,16 @@
         }
     };
 
-    private final Runnable mElectronBeamDrawRunnable = new Runnable() {
+    private final Runnable mColorFadeDrawRunnable = new Runnable() {
         @Override
         public void run() {
-            mElectronBeamDrawPending = false;
+            mColorFadeDrawPending = false;
 
-            if (mElectronBeamPrepared) {
-                mElectronBeam.draw(mElectronBeamLevel);
+            if (mColorFadePrepared) {
+                mColorFade.draw(mColorFadeLevel);
             }
 
-            mElectronBeamReady = true;
+            mColorFadeReady = true;
             invokeCleanListenerIfNeeded();
         }
     };
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index fb4fa7f..ad5b2ba 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -617,6 +617,7 @@
                         }
 
                         addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this));
+                        addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this));
 
                         // If there is AVR, initiate System Audio Auto initiation action,
                         // which turns on and off system audio according to last system
@@ -1300,6 +1301,7 @@
         //     LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery().
         removeAction(DeviceDiscoveryAction.class);
         removeAction(HotplugDetectionAction.class);
+        removeAction(PowerStatusMonitorAction.class);
         // Remove recording actions.
         removeAction(OneTouchRecordAction.class);
         removeAction(TimerRecordingAction.class);
@@ -1521,4 +1523,22 @@
             }
         });
     }
+
+    void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) {
+        HdmiDeviceInfo info = getDeviceInfo(logicalAddress);
+        if (info == null) {
+            Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress);
+            return;
+        }
+
+        if (info.getDevicePowerStatus() == newPowerStatus) {
+            return;
+        }
+
+        HdmiDeviceInfo newInfo = HdmiUtils.cloneHdmiDeviceInfo(info, newPowerStatus);
+        // addDeviceInfo replaces old device info with new one if exists.
+        addDeviceInfo(newInfo);
+
+        // TODO: notify this update to others.
+    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index cccc44c..81b99f0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -317,7 +317,10 @@
                     if (logicalAddress == Constants.ADDR_UNREGISTERED) {
                         Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]");
                     } else {
-                        HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType);
+                        // Set POWER_STATUS_ON to all local devices because they share lifetime
+                        // with system.
+                        HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType,
+                                HdmiControlManager.POWER_STATUS_ON);
                         localDevice.setDeviceInfo(deviceInfo);
                         mCecController.addLocalDevice(deviceType, localDevice);
                         mCecController.addLogicalAddress(logicalAddress);
@@ -653,7 +656,7 @@
         }
     }
 
-    private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) {
+    private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) {
         // TODO: find better name instead of model name.
         String displayName = Build.MODEL;
         return new HdmiDeviceInfo(logicalAddress,
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index a52e0d2..23f19ff 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -266,4 +266,14 @@
         }
         return true;
     }
+
+    /**
+     * Clone {@link HdmiDeviceInfo} with new power status.
+     */
+    static HdmiDeviceInfo cloneHdmiDeviceInfo(HdmiDeviceInfo info, int newPowerStatus) {
+        return new HdmiDeviceInfo(info.getLogicalAddress(),
+                info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
+                info.getVendorId(), info.getDisplayName(), newPowerStatus);
+    }
+
 }
diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
new file mode 100644
index 0000000..03fbb95
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 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.server.hdmi;
+
+import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN;
+
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.util.SparseIntArray;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+import java.util.List;
+
+/**
+ * Action that check each device's power status.
+ */
+public class PowerStatusMonitorAction extends HdmiCecFeatureAction {
+    private static final String TAG = "PowerStatusMonitorAction";
+
+    // State that waits for <Report Power Status> once sending <Give Device Power Status>
+    // to all external devices.
+    private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
+    // State that waits for next monitoring
+    private static final int STATE_WAIT_FOR_NEXT_MONITORING = 2;
+
+    private static final int INVALID_POWER_STATUS = POWER_STATUS_UNKNOWN - 1;
+
+    // Monitoring interval (60s)
+    private static final int MONITIROING_INTERNAL_MS = 60000;
+
+    // Timeout once sending <Give Device Power Status>
+    private static final int REPORT_POWER_STATUS_TIMEOUT_MS = 5000;
+
+    // Container for current power status of all external devices.
+    // The key is a logical address a device and the value is current power status of it
+    // Whenever the action receives <Report Power Status> from a device,
+    // it removes an entry of the given device.
+    // If this is non-empty when timeout for STATE_WAIT_FOR_REPORT_POWER_STATUS happens,
+    // updates power status of all remaining devices into POWER_STATUS_UNKNOWN.
+    private final SparseIntArray mPowerStatus = new SparseIntArray();
+
+    PowerStatusMonitorAction(HdmiCecLocalDevice source) {
+        super(source);
+    }
+
+    @Override
+    boolean start() {
+        queryPowerStatus();
+        return true;
+    }
+
+    @Override
+    boolean processCommand(HdmiCecMessage cmd) {
+        if (mState != STATE_WAIT_FOR_REPORT_POWER_STATUS) {
+            return false;
+        }
+        return handleReportPowerStatus(cmd);
+    }
+
+    private boolean handleReportPowerStatus(HdmiCecMessage cmd) {
+        int sourceAddress = cmd.getSource();
+        int oldStatus = mPowerStatus.get(sourceAddress, INVALID_POWER_STATUS);
+        if (oldStatus == INVALID_POWER_STATUS) {
+            // if no device exists for incoming message, hands it over to other actions.
+            return false;
+        }
+        int newStatus = cmd.getParams()[0];
+        updatePowerStatus(sourceAddress, newStatus, true);
+        return true;
+    }
+
+    @Override
+    void handleTimerEvent(int state) {
+        switch (mState) {
+            case STATE_WAIT_FOR_NEXT_MONITORING:
+                queryPowerStatus();
+                break;
+            case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+                handleTimeout();
+                break;
+        }
+    }
+
+    private void handleTimeout() {
+        for (int i = 0; i < mPowerStatus.size(); ++i) {
+            int logicalAddress = mPowerStatus.keyAt(i);
+            updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, false);
+        }
+        mPowerStatus.clear();
+        mState = STATE_WAIT_FOR_NEXT_MONITORING;
+    }
+
+    private void resetPowerStatus(List<HdmiDeviceInfo> deviceInfos) {
+        mPowerStatus.clear();
+        for (HdmiDeviceInfo info : deviceInfos) {
+            mPowerStatus.append(info.getLogicalAddress(), info.getDevicePowerStatus());
+        }
+    }
+
+    private void queryPowerStatus() {
+        List<HdmiDeviceInfo> deviceInfos = tv().getDeviceInfoList(false);
+        resetPowerStatus(deviceInfos);
+        for (HdmiDeviceInfo info : deviceInfos) {
+            final int logicalAddress = info.getLogicalAddress();
+            sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(),
+                    logicalAddress),
+                    new SendMessageCallback() {
+                        @Override
+                        public void onSendCompleted(int error) {
+                            // If fails to send <Give Device Power Status>,
+                            // update power status into UNKNOWN.
+                            if (error != Constants.SEND_RESULT_SUCCESS) {
+                               updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true);
+                            }
+                        }
+                    });
+        }
+
+        mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+
+        // Add both timers, monitoring and timeout.
+        addTimer(STATE_WAIT_FOR_NEXT_MONITORING, MONITIROING_INTERNAL_MS);
+        addTimer(STATE_WAIT_FOR_REPORT_POWER_STATUS, REPORT_POWER_STATUS_TIMEOUT_MS);
+    }
+
+    private void updatePowerStatus(int logicalAddress, int newStatus, boolean remove) {
+        tv().updateDevicePowerStatus(logicalAddress, newStatus);
+
+        if (remove) {
+            mPowerStatus.delete(logicalAddress);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 5c77014..c7e3fb7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -37,14 +37,17 @@
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.InstallSessionInfo;
 import android.content.pm.InstallSessionParams;
+import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -548,8 +551,21 @@
             int userId) {
         mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
 
-        // TODO: enforce installer of record or permission
-        mPm.deletePackage(packageName, observer, userId, flags);
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
+                == PackageManager.PERMISSION_GRANTED) {
+            // Sweet, call straight through!
+            mPm.deletePackage(packageName, observer, userId, flags);
+
+        } else {
+            // Take a short detour to confirm with user
+            final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+            intent.setData(Uri.fromParts("package", packageName, null));
+            intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
+            try {
+                observer.onUserActionRequired(intent);
+            } catch (RemoteException ignored) {
+            }
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 92bb44b..a3184f0 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -16,11 +16,11 @@
 
 package com.android.server.pm;
 
+import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_REJECTED;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
@@ -577,7 +577,7 @@
             mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
         } else {
             destroyInternal();
-            dispatchSessionFinished(INSTALL_FAILED_REJECTED, "User rejected permissions", null);
+            dispatchSessionFinished(INSTALL_FAILED_ABORTED, "User rejected permissions", null);
         }
     }
 
@@ -591,7 +591,7 @@
     @Override
     public void abandon() {
         destroyInternal();
-        dispatchSessionFinished(INSTALL_FAILED_INTERNAL_ERROR, "Session was abandoned", null);
+        dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
     }
 
     private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6802fac..44b7f01 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -85,7 +85,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
-import android.app.PackageDeleteObserver;
 import android.app.admin.IDevicePolicyManager;
 import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
@@ -115,6 +114,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
 import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
@@ -1402,7 +1402,9 @@
 
             boolean didDexOptLibraryOrTool = false;
 
-            final List<String> instructionSets = getAllInstructionSets();
+            final List<String> allInstructionSets = getAllInstructionSets();
+            final String[] dexCodeInstructionSets =
+                getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
 
             /**
              * Ensure all external libraries have had dexopt run on them.
@@ -1412,7 +1414,7 @@
                 // (and framework jars) into all available architectures. It's possible
                 // to compile them only when we come across an app that uses them (there's
                 // already logic for that in scanPackageLI) but that adds some complexity.
-                for (String instructionSet : instructionSets) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                     for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
                         final String lib = libEntry.path;
                         if (lib == null) {
@@ -1421,16 +1423,16 @@
 
                         try {
                             byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
-                                                                                 instructionSet,
+                                                                                 dexCodeInstructionSet,
                                                                                  false);
                             if (dexoptRequired != DexFile.UP_TO_DATE) {
                                 alreadyDexOpted.add(lib);
 
                                 // The list of "shared libraries" we have at this point is
                                 if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
-                                    mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+                                    mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 } else {
-                                    mInstaller.patchoat(lib, Process.SYSTEM_UID, true, instructionSet);
+                                    mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 }
                                 didDexOptLibraryOrTool = true;
                             }
@@ -1465,7 +1467,7 @@
                 // TODO: We could compile these only for the most preferred ABI. We should
                 // first double check that the dex files for these commands are not referenced
                 // by other system apps.
-                for (String instructionSet : instructionSets) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                     for (int i=0; i<frameworkFiles.length; i++) {
                         File libPath = new File(frameworkDir, frameworkFiles[i]);
                         String path = libPath.getPath();
@@ -1479,13 +1481,13 @@
                         }
                         try {
                             byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
-                                                                                 instructionSet,
+                                                                                 dexCodeInstructionSet,
                                                                                  false);
                             if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
-                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
+                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 didDexOptLibraryOrTool = true;
                             } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
-                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, instructionSet);
+                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
                                 didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
@@ -1509,8 +1511,8 @@
                 // small maintenance release update that the library and tool
                 // jars may be unchanged but APK could be removed resulting in
                 // unused dalvik-cache files.
-                for (String instructionSet : instructionSets) {
-                    mInstaller.pruneDexCache(instructionSet);
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                    mInstaller.pruneDexCache(dexCodeInstructionSet);
                 }
 
                 // Additionally, delete all dex files from the root directory
@@ -4632,9 +4634,10 @@
         // 1.) we need to dexopt, either because we are forced or it is needed
         // 2.) we are defering a needed dexopt
         // 3.) we are skipping an unneeded dexopt
+        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         for (String path : paths) {
-            for (String instructionSet : instructionSets) {
-                if (!forceDex && pkg.mDexOptPerformed.contains(instructionSet)) {
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
                     continue;
                 }
 
@@ -4645,13 +4648,13 @@
                     // odex file and it matches the checksum of the image but not its base address,
                     // meaning we need to move it.
                     final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
-                            pkg.packageName, instructionSet, defer);
+                            pkg.packageName, dexCodeInstructionSet, defer);
                     if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
                         Log.i(TAG, "Running dexopt on: " + path + " pkg="
-                                + pkg.applicationInfo.packageName + " isa=" + instructionSet);
+                                + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                         final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, instructionSet);
+                                pkg.packageName, dexCodeInstructionSet);
 
                         if (ret < 0) {
                             // Don't bother running dexopt again if we failed, it will probably
@@ -4660,13 +4663,13 @@
                             return DEX_OPT_FAILED;
                         } else {
                             performedDexOpt = true;
-                            pkg.mDexOptPerformed.add(instructionSet);
+                            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
                         }
                     } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
                         Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                         final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, instructionSet);
+                                pkg.packageName, dexCodeInstructionSet);
 
                         if (ret < 0) {
                             // Don't bother running patchoat again if we failed, it will probably
@@ -4675,7 +4678,7 @@
                             return DEX_OPT_FAILED;
                         } else {
                             performedDexOpt = true;
-                            pkg.mDexOptPerformed.add(instructionSet);
+                            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
                         }
                     }
 
@@ -4764,6 +4767,23 @@
         return allInstructionSets;
     }
 
+    /**
+     * Returns the instruction set that should be used to compile dex code. In the presence of
+     * a native bridge this might be different than the one shared libraries use.
+     */
+    private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+        String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+        return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
+    }
+
+    private static String[] getDexCodeInstructionSets(String[] instructionSets) {
+        HashSet<String> dexCodeInstructionSets = new HashSet<String>(instructionSets.length);
+        for (String instructionSet : instructionSets) {
+            dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+        }
+        return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+    }
+
     @Override
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
@@ -6183,7 +6203,8 @@
                             ps.pkg.applicationInfo.primaryCpuAbi = null;
                             return;
                         } else {
-                            mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
+                            mInstaller.rmdex(ps.codePathString,
+                                             getDexCodeInstructionSet(getPreferredInstructionSet()));
                         }
                     }
                 }
@@ -9412,10 +9433,10 @@
                 if (instructionSets == null) {
                     throw new IllegalStateException("instructionSet == null");
                 }
-
+                String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
                 for (String codePath : allCodePaths) {
-                    for (String instructionSet : instructionSets) {
-                        int retCode = mInstaller.rmdex(codePath, instructionSet);
+                    for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                        int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
                         if (retCode < 0) {
                             Slog.w(TAG, "Couldn't remove dex file for package: "
                                     + " at location " + codePath + ", retcode=" + retCode);
@@ -9695,8 +9716,9 @@
             if (instructionSets == null) {
                 throw new IllegalStateException("instructionSet == null");
             }
-            for (String instructionSet : instructionSets) {
-                int retCode = mInstaller.rmdex(sourceFile, instructionSet);
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                int retCode = mInstaller.rmdex(sourceFile, dexCodeInstructionSet);
                 if (retCode < 0) {
                     Slog.w(TAG, "Couldn't remove dex file for package: "
                             + " at location "
@@ -10199,9 +10221,10 @@
         // TODO: extend to move split APK dex files
         if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             final String[] instructionSets = getAppDexInstructionSets(newPackage.applicationInfo);
-            for (String instructionSet : instructionSets) {
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath,
-                        instructionSet);
+                        dexCodeInstructionSet);
                 if (retCode != 0) {
                 /*
                  * Programs may be lazily run through dexopt, so the
@@ -10212,8 +10235,8 @@
                  * file from a previous version of the package.
                  */
                     newPackage.mDexOptPerformed.clear();
-                    mInstaller.rmdex(oldCodePath, instructionSet);
-                    mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
+                    mInstaller.rmdex(oldCodePath, dexCodeInstructionSet);
+                    mInstaller.rmdex(newPackage.baseCodePath, dexCodeInstructionSet);
                 }
             }
         }
@@ -11360,9 +11383,9 @@
         // not just the first level.
         // TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not
         // just the primary.
+        String[] dexCodeInstructionSets = getDexCodeInstructionSets(getAppDexInstructionSets(ps));
         int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirRoot,
-                publicSrcDir, asecPath, getAppDexInstructionSets(ps),
-                pStats);
+                publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
         if (res < 0) {
             return false;
         }
@@ -13451,20 +13474,4 @@
             return false;
         }
     }
-
-    private static class LegacyPackageDeleteObserver extends PackageDeleteObserver {
-        private final IPackageDeleteObserver mLegacy;
-
-        public LegacyPackageDeleteObserver(IPackageDeleteObserver legacy) {
-            mLegacy = legacy;
-        }
-
-        @Override
-        public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
-            try {
-                mLegacy.packageDeleted(basePackageName, returnCode);
-            } catch (RemoteException ignored) {
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 304d2d4..4e711ba 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2347,6 +2347,7 @@
             origId = Binder.clearCallingIdentity();
 
             if (addToken) {
+                Slog.w("BadTokenDebug", "addWindow: Adding token=" + token + " attrs.token=" + attrs.token);
                 mTokenMap.put(attrs.token, token);
             }
             win.attach();
@@ -2429,7 +2430,7 @@
             // relayout to be displayed, so we'll do it there.
 
             if (focusChanged) {
-                finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/);
+                mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
             }
             mInputMonitor.updateInputWindowsLw(false /*force*/);
 
@@ -2546,12 +2547,15 @@
                 if (displayContent != null) {
                     displayContent.layoutNeeded = true;
                 }
-                updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                        false /*updateInputWindows*/);
+                final boolean focusChanged = updateFocusedWindowLocked(
+                        UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
                 performLayoutAndPlaceSurfacesLocked();
                 if (win.mAppToken != null) {
                     win.mAppToken.updateReportedVisibilityLocked();
                 }
+                if (focusChanged) {
+                    mInputMonitor.updateInputWindowsLw(false /*force*/);
+                }
                 //dump();
                 Binder.restoreCallingIdentity(origId);
                 return;
@@ -2625,7 +2629,9 @@
                 + token.windows.size());
         if (token.windows.size() == 0) {
             if (!token.explicit) {
-                mTokenMap.remove(token.token);
+                WindowToken wtoken = mTokenMap.remove(token.token);
+                Slog.w("BadTokenDebug", "removeWindowInnerLocked: Removing token=" + token + " removed=" +
+                        wtoken + " Callers=" + Debug.getCallers(4));
             } else if (atoken != null) {
                 atoken.firstWindowDrawn = false;
             }
@@ -3411,6 +3417,7 @@
                 return;
             }
             wtoken = new WindowToken(this, token, type, true);
+            Slog.w("BadTokenDebug", "addWindowToken: Adding token=" + token + " wtoken=" + wtoken);
             mTokenMap.put(token, wtoken);
             if (type == TYPE_WALLPAPER) {
                 mWallpaperTokens.add(wtoken);
@@ -3429,6 +3436,8 @@
         synchronized(mWindowMap) {
             DisplayContent displayContent = null;
             WindowToken wtoken = mTokenMap.remove(token);
+            Slog.w("BadTokenDebug", "removeWindowToken: Removing token=" + token + " removed=" + wtoken
+                    + " Callers=" + Debug.getCallers(3));
             if (wtoken != null) {
                 boolean delayed = false;
                 if (!wtoken.hidden) {
@@ -3545,6 +3554,7 @@
                 task.addAppToken(addPos, atoken);
             }
 
+            Slog.w("BadTokenDebug", "addAppToken: Adding token=" + token.asBinder() + " atoken=" + atoken);
             mTokenMap.put(token.asBinder(), atoken);
 
             // Application tokens start out hidden.
@@ -3910,7 +3920,7 @@
             final boolean changed = mFocusedApp != newFocus;
             if (changed) {
                 mFocusedApp = newFocus;
-                mInputMonitor.setFocusedAppLw(null);
+                mInputMonitor.setFocusedAppLw(newFocus);
             }
 
             if (moveFocusNow && changed) {
@@ -4633,6 +4643,7 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
             WindowToken basewtoken = mTokenMap.remove(token);
+            Slog.w("BadTokenDebug", "removeAppToke: Removing token=" + token + " removed=" + basewtoken);
             if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
                 delayed = setTokenVisibilityLocked(wtoken, null, false,
@@ -8917,7 +8928,7 @@
                     && !moveInputMethodWindowsIfNeededLocked(true)) {
                 assignLayersLocked(windows);
             }
-            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
+            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
             mFocusMayChange = false;
         }
 
@@ -9152,10 +9163,11 @@
         final long currentTime = SystemClock.uptimeMillis();
 
         int i;
+        boolean updateInputWindowsNeeded = false;
 
         if (mFocusMayChange) {
             mFocusMayChange = false;
-            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+            updateInputWindowsNeeded = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                     false /*updateInputWindows*/);
         }
 
@@ -9517,6 +9529,7 @@
             mFocusMayChange = false;
             if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                     false /*updateInputWindows*/)) {
+                updateInputWindowsNeeded = true;
                 defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
             }
         }
@@ -9697,6 +9710,9 @@
             mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
         }
 
+        if (updateInputWindowsNeeded) {
+            mInputMonitor.updateInputWindowsLw(false /*force*/);
+        }
         setFocusedStackFrame();
 
         // Check to see if we are now in a state where the screen should
@@ -10012,7 +10028,7 @@
             if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
                 // If we defer assigning layers, then the caller is responsible for
                 // doing this part.
-                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
+                mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
             }
 
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -10021,10 +10037,6 @@
         return false;
     }
 
-    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
-        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
-    }
-
     private WindowState computeFocusedWindowLocked() {
         if (mAnimator.mUniverseBackground != null
                 && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
diff --git a/telecomm/java/android/telecomm/Call.java b/telecomm/java/android/telecomm/Call.java
index 3374d51..55cb8b1 100644
--- a/telecomm/java/android/telecomm/Call.java
+++ b/telecomm/java/android/telecomm/Call.java
@@ -69,6 +69,11 @@
      */
     public static final int STATE_PRE_DIAL_WAIT = 8;
 
+    /**
+     * The state of an outgoing {@code Call}, before Telecomm broadcast intent has returned.
+     */
+    public static final int STATE_CONNECTING = 9;
+
     public static class Details {
         private final Uri mHandle;
         private final int mHandlePresentation;
@@ -771,6 +776,8 @@
         switch (parcelableCallState) {
             case NEW:
                 return STATE_NEW;
+            case CONNECTING:
+                return STATE_CONNECTING;
             case PRE_DIAL_WAIT:
                 return STATE_PRE_DIAL_WAIT;
             case DIALING:
diff --git a/telecomm/java/android/telecomm/CallState.java b/telecomm/java/android/telecomm/CallState.java
index 9cb05db..cfa78d4 100644
--- a/telecomm/java/android/telecomm/CallState.java
+++ b/telecomm/java/android/telecomm/CallState.java
@@ -32,6 +32,12 @@
     NEW,
 
     /**
+     * Indicates an outgoing call has been initiated and is waiting for the broadcast intent to
+     * return and provide call details before proceeding.
+     */
+    CONNECTING,
+
+    /**
      * Indicates that the call is about to go into the outgoing and dialing state but is waiting for
      * user input before it proceeds. For example, where no default {@link PhoneAccount} is set,
      * this is the state where the InCallUI is waiting for the user to select a
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index f5c4c34..5bf59c7 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -97,11 +97,11 @@
         String packageName = mArgs.getString(PACKAGE_TO_LAUNCH);
         if (packageName != null) {
             Log.d(TAG, "Launching app " + packageName);
-            Collection<ProcessErrorStateInfo> err = launchActivity(packageName);
+            ProcessErrorStateInfo err = launchActivity(packageName);
             // Make sure there are no errors when launching the application,
             // otherwise raise an
             // exception with the first error encountered.
-            assertNull(getFirstError(err), err);
+            assertNull(getStackTrace(err), err);
             assertTrue("App crashed after launch.", processStillUp(packageName));
         } else {
             Log.d(TAG, "Missing argument, use " + PACKAGE_TO_LAUNCH +
@@ -110,20 +110,32 @@
     }
 
     /**
-     * Gets the first error in collection and return the long message for it.
+     * Gets the stack trace for the error.
      *
-     * @param in {@link Collection} of {@link ProcessErrorStateInfo} to parse.
+     * @param in {@link ProcessErrorStateInfo} to parse.
      * @return {@link String} the long message of the error.
      */
-    private String getFirstError(Collection<ProcessErrorStateInfo> in) {
+    private String getStackTrace(ProcessErrorStateInfo in) {
         if (in == null) {
             return null;
+        } else {
+            return in.stackTrace;
         }
-        ProcessErrorStateInfo err = in.iterator().next();
-        if (err != null) {
-            return err.stackTrace;
+    }
+
+    /**
+     * Returns the process name that the package is going to use.
+     *
+     * @param packageName name of the package
+     * @return process name of the package
+     */
+    private String getProcessName(String packageName) {
+        try {
+            PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
+            return pi.applicationInfo.processName;
+        } catch (NameNotFoundException e) {
+            return packageName;
         }
-        return null;
     }
 
     /**
@@ -134,7 +146,7 @@
      * @return {@link Collection} of {@link ProcessErrorStateInfo} detected
      *         during the app launch.
      */
-    private Collection<ProcessErrorStateInfo> launchActivity(String packageName) {
+    private ProcessErrorStateInfo launchActivity(String packageName) {
         Intent homeIntent = new Intent(Intent.ACTION_MAIN);
         homeIntent.addCategory(Intent.CATEGORY_HOME);
         homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -146,16 +158,7 @@
             return null;
         }
 
-        // We check for any Crash or ANR dialogs that are already up, and we
-        // ignore them. This is
-        // so that we don't report crashes that were caused by prior apps (which
-        // those particular
-        // tests should have caught and reported already). Otherwise, test
-        // failures would cascade
-        // from the initial broken app to many/all of the tests following that
-        // app's launch.
-        final Collection<ProcessErrorStateInfo> preErr =
-                mActivityManager.getProcessesInErrorState();
+        String processName = getProcessName(packageName);
 
         // Launch Activity
         mContext.startActivity(intent);
@@ -179,13 +182,16 @@
         // possible to occur.
         final Collection<ProcessErrorStateInfo> postErr =
                 mActivityManager.getProcessesInErrorState();
-        // Take the difference between the error processes we see now, and the
-        // ones that were
-        // present when we started
-        if (preErr != null && postErr != null) {
-            postErr.removeAll(preErr);
+
+        if (postErr == null) {
+            return null;
         }
-        return postErr;
+        for (ProcessErrorStateInfo error : postErr) {
+            if (error.processName.equals(processName)) {
+                return error;
+            }
+        }
+        return null;
     }
 
     /**
@@ -195,22 +201,16 @@
      * @return True if package is running, false otherwise.
      */
     private boolean processStillUp(String packageName) {
-        try {
-            PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0);
-            String processName = packageInfo.applicationInfo.processName;
-            List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses();
-            for (RunningAppProcessInfo app : runningApps) {
-                if (app.processName.equalsIgnoreCase(processName)) {
-                    Log.d(TAG, "Found process " + app.processName);
-                    return true;
-                }
+        String processName = getProcessName(packageName);
+        List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses();
+        for (RunningAppProcessInfo app : runningApps) {
+            if (app.processName.equalsIgnoreCase(processName)) {
+                Log.d(TAG, "Found process " + app.processName);
+                return true;
             }
-            Log.d(TAG, "Failed to find process " + processName + " with package name "
-                    + packageName);
-        } catch (NameNotFoundException e) {
-            Log.w(TAG, "Failed to find package " + packageName);
-            return false;
         }
+        Log.d(TAG, "Failed to find process " + processName + " with package name "
+                + packageName);
         return false;
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index dfed174..1ca54bc 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -343,6 +343,7 @@
      * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
      * @hide
      */
+    @SystemApi
     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
     /**
@@ -351,6 +352,7 @@
      * broadcast is sent.
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
     /**
      * Multiple network configurations have changed.
@@ -358,6 +360,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
     /**
      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
@@ -365,23 +368,27 @@
      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_CHANGE_REASON = "changeReason";
     /**
      * The configuration is new and was added.
      * @hide
      */
+    @SystemApi
     public static final int CHANGE_REASON_ADDED = 0;
     /**
      * The configuration was removed and is no longer present in the system's list of
      * configured networks.
      * @hide
      */
+    @SystemApi
     public static final int CHANGE_REASON_REMOVED = 1;
     /**
      * The configuration has changed as a result of explicit action or because the system
      * took an automated action such as disabling a malfunctioning configuration.
      * @hide
      */
+    @SystemApi
     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
     /**
      * An access point scan has completed, and results are available from the supplicant.
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index c5c44b5..e7bcb23 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -100,7 +100,7 @@
      */
     public static class ChannelSpec {
         /**
-         * channel frequency in KHz; for example channel 1 is specified as 2412
+         * channel frequency in MHz; for example channel 1 is specified as 2412
          */
         public int frequency;
         /**
@@ -158,6 +158,7 @@
             dest.writeInt(band);
             dest.writeInt(periodInMs);
             dest.writeInt(reportEvents);
+            dest.writeInt(numBssidsPerScan);
 
             if (channels != null) {
                 dest.writeInt(channels.length);
@@ -181,6 +182,7 @@
                         settings.band = in.readInt();
                         settings.periodInMs = in.readInt();
                         settings.reportEvents = in.readInt();
+                        settings.numBssidsPerScan = in.readInt();
                         int num_channels = in.readInt();
                         settings.channels = new ChannelSpec[num_channels];
                         for (int i = 0; i < num_channels; i++) {