Merge "Fix ObservableScrollView's cancel dispatch" into mnc-dev
diff --git a/Android.mk b/Android.mk
index 146afe0..59c1878 100644
--- a/Android.mk
+++ b/Android.mk
@@ -146,6 +146,7 @@
 	core/java/android/database/IContentObserver.aidl \
 	core/java/android/hardware/ICameraService.aidl \
 	core/java/android/hardware/ICameraServiceListener.aidl \
+	core/java/android/hardware/ICameraServiceProxy.aidl \
 	core/java/android/hardware/ICamera.aidl \
 	core/java/android/hardware/ICameraClient.aidl \
 	core/java/android/hardware/IConsumerIrService.aidl \
@@ -155,6 +156,8 @@
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index d3b8724..bbdb878 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5773,7 +5773,7 @@
     method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
-    method public boolean setPermissionGranted(android.content.ComponentName, java.lang.String, java.lang.String, boolean);
+    method public boolean setPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String, int);
     method public void setPermissionPolicy(android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
@@ -5862,6 +5862,9 @@
     field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000
     field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000
     field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0
+    field public static final int PERMISSION_GRANT_STATE_DEFAULT = 0; // 0x0
+    field public static final int PERMISSION_GRANT_STATE_DENIED = 2; // 0x2
+    field public static final int PERMISSION_GRANT_STATE_GRANTED = 1; // 0x1
     field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
     field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
     field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
@@ -7160,6 +7163,7 @@
   public static final class ScanSettings.Builder {
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
+    method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
     method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
@@ -14797,8 +14801,8 @@
     ctor public AudioFormat.Builder();
     ctor public AudioFormat.Builder(android.media.AudioFormat);
     method public android.media.AudioFormat build();
-    method public android.media.AudioFormat.Builder setChannelIndexMask(int) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioFormat.Builder setChannelMask(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioFormat.Builder setChannelIndexMask(int);
+    method public android.media.AudioFormat.Builder setChannelMask(int);
     method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException;
   }
@@ -14960,11 +14964,11 @@
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
+    method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
     method public android.media.AudioFormat getFormat();
     method public static int getMinBufferSize(int, int, int);
-    method public int getNativeFrameCount() throws java.lang.IllegalStateException;
     method public int getNotificationMarkerPosition();
     method public int getPositionNotificationPeriod();
     method public android.media.AudioDeviceInfo getPreferredDevice();
@@ -15033,13 +15037,14 @@
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
+    method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
     method public android.media.AudioFormat getFormat();
     method public static float getMaxVolume();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
-    method public int getNativeFrameCount() throws java.lang.IllegalStateException;
+    method protected deprecated int getNativeFrameCount();
     method public static int getNativeOutputSampleRate(int);
     method public int getNotificationMarkerPosition();
     method public int getPlayState();
@@ -18396,7 +18401,7 @@
     field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
-  public deprecated class ProxyInfo implements android.os.Parcelable {
+  public class ProxyInfo implements android.os.Parcelable {
     method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
     method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
     method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
@@ -25175,13 +25180,6 @@
     field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1
   }
 
-  public static final class ContactsContract.Authorization {
-    ctor public ContactsContract.Authorization();
-    field public static final java.lang.String AUTHORIZATION_METHOD = "authorize";
-    field public static final java.lang.String KEY_AUTHORIZED_URI = "authorized_uri";
-    field public static final java.lang.String KEY_URI_TO_AUTHORIZE = "uri_to_authorize";
-  }
-
   protected static abstract interface ContactsContract.BaseSyncColumns {
     field public static final java.lang.String SYNC1 = "sync1";
     field public static final java.lang.String SYNC2 = "sync2";
@@ -25588,6 +25586,8 @@
   }
 
   protected static abstract interface ContactsContract.DataColumns {
+    field public static final java.lang.String CARRIER_PRESENCE = "carrier_presence";
+    field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
     field public static final java.lang.String DATA1 = "data1";
     field public static final java.lang.String DATA10 = "data10";
     field public static final java.lang.String DATA11 = "data11";
@@ -25826,16 +25826,6 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  public static final class ContactsContract.ProviderStatus {
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
-    field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String STATUS = "status";
-    field public static final int STATUS_CHANGING_LOCALE = 3; // 0x3
-    field public static final int STATUS_NORMAL = 0; // 0x0
-    field public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; // 0x4
-    field public static final int STATUS_UPGRADING = 1; // 0x1
-  }
-
   public static final class ContactsContract.QuickContact {
     ctor public ContactsContract.QuickContact();
     method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
@@ -30323,6 +30313,7 @@
     method public android.net.Uri getSubscriptionAddress();
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
+    method public boolean isEnabled();
     method public boolean supportsUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1dc5325..1a3673d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5882,7 +5882,7 @@
     method public void setPasswordMinimumSymbols(android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(android.content.ComponentName, int);
     method public void setPasswordQuality(android.content.ComponentName, int);
-    method public boolean setPermissionGranted(android.content.ComponentName, java.lang.String, java.lang.String, boolean);
+    method public boolean setPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String, int);
     method public void setPermissionPolicy(android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedInputMethods(android.content.ComponentName, java.util.List<java.lang.String>);
@@ -5976,6 +5976,9 @@
     field public static final int PASSWORD_QUALITY_NUMERIC_COMPLEX = 196608; // 0x30000
     field public static final int PASSWORD_QUALITY_SOMETHING = 65536; // 0x10000
     field public static final int PASSWORD_QUALITY_UNSPECIFIED = 0; // 0x0
+    field public static final int PERMISSION_GRANT_STATE_DEFAULT = 0; // 0x0
+    field public static final int PERMISSION_GRANT_STATE_DENIED = 2; // 0x2
+    field public static final int PERMISSION_GRANT_STATE_GRANTED = 1; // 0x1
     field public static final int PERMISSION_POLICY_AUTO_DENY = 2; // 0x2
     field public static final int PERMISSION_POLICY_AUTO_GRANT = 1; // 0x1
     field public static final int PERMISSION_POLICY_PROMPT = 0; // 0x0
@@ -16024,8 +16027,8 @@
     ctor public AudioFormat.Builder();
     ctor public AudioFormat.Builder(android.media.AudioFormat);
     method public android.media.AudioFormat build();
-    method public android.media.AudioFormat.Builder setChannelIndexMask(int) throws java.lang.IllegalArgumentException;
-    method public android.media.AudioFormat.Builder setChannelMask(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioFormat.Builder setChannelIndexMask(int);
+    method public android.media.AudioFormat.Builder setChannelMask(int);
     method public android.media.AudioFormat.Builder setEncoding(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioFormat.Builder setSampleRate(int) throws java.lang.IllegalArgumentException;
   }
@@ -16197,11 +16200,11 @@
     method public int getAudioFormat();
     method public int getAudioSessionId();
     method public int getAudioSource();
+    method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
     method public android.media.AudioFormat getFormat();
     method public static int getMinBufferSize(int, int, int);
-    method public int getNativeFrameCount() throws java.lang.IllegalStateException;
     method public int getNotificationMarkerPosition();
     method public int getPositionNotificationPeriod();
     method public android.media.AudioDeviceInfo getPreferredDevice();
@@ -16272,13 +16275,14 @@
     method public void flush();
     method public int getAudioFormat();
     method public int getAudioSessionId();
+    method public int getBufferSizeInFrames();
     method public int getChannelConfiguration();
     method public int getChannelCount();
     method public android.media.AudioFormat getFormat();
     method public static float getMaxVolume();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
-    method public int getNativeFrameCount() throws java.lang.IllegalStateException;
+    method protected deprecated int getNativeFrameCount();
     method public static int getNativeOutputSampleRate(int);
     method public int getNotificationMarkerPosition();
     method public int getPlayState();
@@ -19905,7 +19909,7 @@
     field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
-  public deprecated class ProxyInfo implements android.os.Parcelable {
+  public class ProxyInfo implements android.os.Parcelable {
     method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
     method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
     method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
@@ -27102,13 +27106,6 @@
     field public static final int TYPE_KEEP_TOGETHER = 1; // 0x1
   }
 
-  public static final class ContactsContract.Authorization {
-    ctor public ContactsContract.Authorization();
-    field public static final java.lang.String AUTHORIZATION_METHOD = "authorize";
-    field public static final java.lang.String KEY_AUTHORIZED_URI = "authorized_uri";
-    field public static final java.lang.String KEY_URI_TO_AUTHORIZE = "uri_to_authorize";
-  }
-
   protected static abstract interface ContactsContract.BaseSyncColumns {
     field public static final java.lang.String SYNC1 = "sync1";
     field public static final java.lang.String SYNC2 = "sync2";
@@ -27515,6 +27512,8 @@
   }
 
   protected static abstract interface ContactsContract.DataColumns {
+    field public static final java.lang.String CARRIER_PRESENCE = "carrier_presence";
+    field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
     field public static final java.lang.String DATA1 = "data1";
     field public static final java.lang.String DATA10 = "data10";
     field public static final java.lang.String DATA11 = "data11";
@@ -27753,16 +27752,6 @@
     field public static final android.net.Uri CONTENT_URI;
   }
 
-  public static final class ContactsContract.ProviderStatus {
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
-    field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String STATUS = "status";
-    field public static final int STATUS_CHANGING_LOCALE = 3; // 0x3
-    field public static final int STATUS_NORMAL = 0; // 0x0
-    field public static final int STATUS_NO_ACCOUNTS_NO_CONTACTS = 4; // 0x4
-    field public static final int STATUS_UPGRADING = 1; // 0x1
-  }
-
   public static final class ContactsContract.QuickContact {
     ctor public ContactsContract.QuickContact();
     method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
@@ -32509,6 +32498,7 @@
     method public android.net.Uri getSubscriptionAddress();
     method public java.util.List<java.lang.String> getSupportedUriSchemes();
     method public boolean hasCapabilities(int);
+    method public boolean isEnabled();
     method public boolean supportsUriScheme(java.lang.String);
     method public android.telecom.PhoneAccount.Builder toBuilder();
     method public void writeToParcel(android.os.Parcel, int);
@@ -32650,6 +32640,7 @@
     method public void cancelMissedCallsNotification();
     method public deprecated void clearAccounts();
     method public void clearPhoneAccounts();
+    method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
     method public boolean endCall();
     method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
@@ -32665,7 +32656,6 @@
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
-    method public java.util.List<android.telecom.PhoneAccountHandle> getRegisteredConnectionManagers();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
     method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
     method public boolean handleMmi(java.lang.String);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3309443..96c6878 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1366,7 +1366,9 @@
         int version = parcel.readInt();
 
         when = parcel.readLong();
-        mSmallIcon = Icon.CREATOR.createFromParcel(parcel);
+        if (parcel.readInt() != 0) {
+            mSmallIcon = Icon.CREATOR.createFromParcel(parcel);
+        }
         number = parcel.readInt();
         if (parcel.readInt() != 0) {
             contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
@@ -1590,7 +1592,12 @@
         parcel.writeInt(1);
 
         parcel.writeLong(when);
-        mSmallIcon.writeToParcel(parcel, 0);
+        if (mSmallIcon != null) {
+            parcel.writeInt(1);
+            mSmallIcon.writeToParcel(parcel, 0);
+        } else {
+            parcel.writeInt(0);
+        }
         parcel.writeInt(number);
         if (contentIntent != null) {
             parcel.writeInt(1);
@@ -3241,7 +3248,7 @@
             Notification n = new Notification();
             n.when = mWhen;
             n.mSmallIcon = mSmallIcon;
-            if (mSmallIcon.getType() == Icon.TYPE_RESOURCE) {
+            if (mSmallIcon != null && mSmallIcon.getType() == Icon.TYPE_RESOURCE) {
                 n.icon = mSmallIcon.getResId();
             }
             n.iconLevel = mSmallIconLevel;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 55ff85a..a8f2311 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -825,6 +825,23 @@
      */
     public static final int PERMISSION_POLICY_AUTO_DENY = 2;
 
+    /**
+     * Runtime permission state: The user can manage the permission
+     * through the UI.
+     */
+    public static final int PERMISSION_GRANT_STATE_DEFAULT = 0;
+
+    /**
+     * Runtime permission state: The permission is granted to the app
+     * and the user cannot manage the permission through the UI.
+     */
+    public static final int PERMISSION_GRANT_STATE_GRANTED = 1;
+
+    /**
+     * Runtime permission state: The permission is denied to the app
+     * and the user cannot manage the permission through the UI.
+     */
+    public static final int PERMISSION_GRANT_STATE_DENIED = 2;
 
     /**
      * Return true if the given administrator component is currently
@@ -4401,21 +4418,31 @@
     }
 
     /**
-     * Grants or revokes a runtime permission to a specific application so that the user
-     * does not have to be prompted. This might affect all permissions in a group that the
-     * runtime permission belongs to. This method can only be called by a profile or device
-     * owner.
+     * Sets the grant state of a runtime permission for a specific application. The state
+     * can be {@link #PERMISSION_GRANT_STATE_DEFAULT default} in which a user can manage it
+     * through the UI, {@link #PERMISSION_GRANT_STATE_DENIED denied}, in which the permission
+     * is denied and the user cannot manage it through the UI, and {@link
+     * #PERMISSION_GRANT_STATE_GRANTED granted} in which the permission is granted and the
+     * user cannot manage it through the UI. This might affect all permissions in a
+     * group that the runtime permission belongs to. This method can only be called
+     * by a profile or device owner.
+     *
      * @param admin Which profile or device owner this request is associated with.
      * @param packageName The application to grant or revoke a permission to.
      * @param permission The permission to grant or revoke.
-     * @param granted Whether or not to grant the permission. If false, all permissions in the
-     * associated permission group will be denied.
-     * @return whether the permission was successfully granted or revoked
+     * @param grantState The permission grant state which is one of {@link
+     *         #PERMISSION_GRANT_STATE_DENIED}, {@link #PERMISSION_GRANT_STATE_DEFAULT},
+     *         {@link #PERMISSION_GRANT_STATE_GRANTED},
+     * @return whether the permission was successfully granted or revoked.
+     *
+     * @see #PERMISSION_GRANT_STATE_DENIED
+     * @see #PERMISSION_GRANT_STATE_DEFAULT
+     * @see #PERMISSION_GRANT_STATE_GRANTED
      */
-    public boolean setPermissionGranted(ComponentName admin, String packageName,
-            String permission, boolean granted) {
+    public boolean setPermissionGrantState(ComponentName admin, String packageName,
+            String permission, int grantState) {
         try {
-            return mService.setPermissionGranted(admin, packageName, permission, granted);
+            return mService.setPermissionGrantState(admin, packageName, permission, grantState);
         } catch (RemoteException re) {
             Log.w(TAG, "Failed talking with device policy service", re);
             return false;
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 24ef604..10b0941 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -234,6 +234,6 @@
 
     void setPermissionPolicy(in ComponentName admin, int policy);
     int  getPermissionPolicy(in ComponentName admin);
-    boolean setPermissionGranted(in ComponentName admin, String packageName, String permission,
-            boolean granted);
+    boolean setPermissionGrantState(in ComponentName admin, String packageName,
+            String permission, int grantState);
 }
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 4eeb577..d616624 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -249,9 +249,7 @@
          *
          * @param callbackType The callback type flags for the scan.
          * @throws IllegalArgumentException If the {@code callbackType} is invalid.
-         * @hide
          */
-        @SystemApi
         public Builder setCallbackType(int callbackType) {
 
             if (!isValidCallbackType(callbackType)) {
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index 9201b614..c933f92 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -25,7 +25,11 @@
 import android.hardware.ICameraServiceListener;
 import android.hardware.CameraInfo;
 
-/** @hide */
+/**
+ * Binder interface for the native camera service running in mediaserver.
+ *
+ * @hide
+ */
 interface ICameraService
 {
     /**
diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl
new file mode 100644
index 0000000..0bb24bc
--- /dev/null
+++ b/core/java/android/hardware/ICameraServiceProxy.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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.hardware;
+
+/**
+ * Binder interface for the camera service proxy running in system_server.
+ *
+ * @hide
+ */
+interface ICameraServiceProxy
+{
+    /**
+     * Ping the service proxy to update the valid users for the camera service.
+     */
+    oneway void pingForUserUpdate();
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 9046e81..7f4a76c 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -67,8 +67,6 @@
     private final TaskSingleDrainer mIdleDrainer;
     /** Drain state transitions from BUSY -> IDLE */
     private final TaskSingleDrainer mAbortDrainer;
-    /** Drain the UNCONFIGURED state transition */
-    private final TaskSingleDrainer mUnconfigureDrainer;
 
     /** This session is closed; all further calls will throw ISE */
     private boolean mClosed = false;
@@ -121,8 +119,6 @@
                 /*name*/"idle");
         mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
                 /*name*/"abort");
-        mUnconfigureDrainer = new TaskSingleDrainer(mDeviceHandler, new UnconfigureDrainListener(),
-                /*name*/"unconf");
 
         // CameraDevice should call configureOutputs and have it finish before constructing us
 
@@ -572,26 +568,6 @@
             @Override
             public void onUnconfigured(CameraDevice camera) {
                 if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigured");
-                synchronized (session) {
-                    // Ignore #onUnconfigured before #close is called.
-                    //
-                    // Normally, this is reached when this session is closed and no immediate other
-                    // activity happens for the camera, in which case the camera is configured to
-                    // null streams by this session and the UnconfigureDrainer task is started.
-                    // However, we can also end up here if
-                    //
-                    // 1) Session is closed
-                    // 2) New session is created before this session finishes closing, setting
-                    //    mSkipUnconfigure and therefore this session does not configure null or
-                    //    start the UnconfigureDrainer task.
-                    // 3) And then the new session fails to be created, so onUnconfigured fires
-                    //    _anyway_.
-                    // In this second case, need to not finish a task that was never started, so
-                    // guard with mSkipUnconfigure
-                    if (mClosed && mConfigureSuccess && !mSkipUnconfigure) {
-                        mUnconfigureDrainer.taskFinished();
-                    }
-                }
             }
 
             @Override
@@ -656,6 +632,19 @@
              * then the drain immediately finishes.
              */
             if (VERBOSE) Log.v(TAG, mIdString + "onSequenceDrained");
+
+
+            // Fire session close as soon as all sequences are complete.
+            // We may still need to unconfigure the device, but a new session might be created
+            // past this point, and notifications would then stop to this instance.
+            mStateCallback.onClosed(CameraCaptureSessionImpl.this);
+
+            // Fast path: A new capture session has replaced this one; don't wait for abort/idle
+            // as we won't get state updates any more anyway.
+            if (mSkipUnconfigure) {
+                return;
+            }
+
             mAbortDrainer.beginDrain();
         }
     }
@@ -673,6 +662,12 @@
                  *
                  * If the camera is already "IDLE", then the drain immediately finishes.
                  */
+
+                // Fast path: A new capture session has replaced this one; don't wait for idle
+                // as we won't get state updates any more anyway.
+                if (mSkipUnconfigure) {
+                    return;
+                }
                 mIdleDrainer.beginDrain();
             }
         }
@@ -691,7 +686,7 @@
                  * The device is now IDLE, and has settled. It will not transition to
                  * ACTIVE or BUSY again by itself.
                  *
-                 * It's now safe to unconfigure the outputs and after it's done invoke #onClosed.
+                 * It's now safe to unconfigure the outputs.
                  *
                  * This operation is idempotent; a session will not be closed twice.
                  */
@@ -699,45 +694,31 @@
                         Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
                                 mSkipUnconfigure);
 
-                    // Fast path: A new capture session has replaced this one; don't unconfigure.
+                    // Fast path: A new capture session has replaced this one; don't wait for idle
+                    // as we won't get state updates any more anyway.
                     if (mSkipUnconfigure) {
-                        mStateCallback.onClosed(CameraCaptureSessionImpl.this);
                         return;
                     }
 
-                    // Slow path: #close was called explicitly on this session; unconfigure first
-                    mUnconfigureDrainer.taskStarted();
-
+                    // Final slow path: unconfigure the camera, no session has replaced us and
+                    // everything is idle.
                     try {
                         // begin transition to unconfigured
                         mDeviceImpl.configureStreamsChecked(null, null);
                     } catch (CameraAccessException e) {
                         // OK: do not throw checked exceptions.
-                        Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
+                        Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e);
 
                         // TODO: call onError instead of onClosed if this happens
                     } catch (IllegalStateException e) {
-                        // Camera is already closed, so go straight to the close callback
+                        // Camera is already closed, so nothing left to do
                         if (VERBOSE) Log.v(TAG, mIdString +
                                 "Camera was already closed or busy, skipping unconfigure");
-                        mUnconfigureDrainer.taskFinished();
                     }
 
-                    mUnconfigureDrainer.beginDrain();
                 }
             }
         }
     }
 
-    private class UnconfigureDrainListener implements TaskDrainer.DrainListener {
-        @Override
-
-        public void onDrained() {
-            if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigureDrained");
-            synchronized (CameraCaptureSessionImpl.this) {
-                // The device has finished unconfiguring. It's now fully closed.
-                mStateCallback.onClosed(CameraCaptureSessionImpl.this);
-            }
-        }
-    }
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 338bd76..caf21d5 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -729,12 +729,6 @@
         }
     }
 
-    private void clearCallbacks() {
-        mAuthenticationCallback = null;
-        mEnrollmentCallback = null;
-        mRemovalCallback = null;
-    }
-
     private void cancelEnrollment() {
         if (mService != null) try {
             mService.cancelEnrollment(mToken);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
new file mode 100644
index 0000000..186d36e
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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.hardware.fingerprint;
+
+import android.hardware.fingerprint.IFingerprintDaemonCallback;
+
+/**
+ * Communication channel from FingerprintService to FingerprintDaemon (fingerprintd)
+ * @hide
+ */
+ 
+interface IFingerprintDaemon {
+    int authenticate(long sessionId, int groupId);
+    int cancelAuthentication();
+    int enroll(in byte [] token, int groupId, int timeout);
+    int cancelEnrollment();
+    long preEnroll();
+    int remove(int fingerId, int groupId);
+    long getAuthenticatorId();
+    int setActiveGroup(int groupId, in byte[] path);
+    long openHal();
+    int closeHal();
+    void init(IFingerprintDaemonCallback callback);
+}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl
new file mode 100644
index 0000000..bd8ad6e
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.hardware.fingerprint;
+
+/**
+ * Communication channel from the fingerprintd back to FingerprintService.
+ * @hide
+ */
+ interface IFingerprintDaemonCallback {
+    void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
+    void onAcquired(long deviceId, int acquiredInfo);
+    void onAuthenticated(long deviceId, int fingerId, int groupId);
+    void onError(long deviceId, int error);
+    void onRemoved(long deviceId, int fingerId, int groupId);
+    void onEnumerate(long deviceId, in int [] fingerIds, in int [] groupIds);
+}
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java
index add8774..b0f2003 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/core/java/android/net/IpReachabilityMonitor.java
@@ -73,7 +73,62 @@
     private final Set<InetAddress> mIpWatchList;
     private int mIpWatchListVersion;
     private boolean mRunning;
-    final private Thread mObserverThread;
+    private final NetlinkSocketObserver mNetlinkSocketObserver;
+    private final Thread mObserverThread;
+
+    /**
+     * Make the kernel to perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+     * for the given IP address on the specified interface index.
+     *
+     * @return true, if the request was successfully passed to the kernel; false otherwise.
+     */
+    public static boolean probeNeighbor(int ifIndex, InetAddress ip) {
+        final long IO_TIMEOUT = 300L;
+        // This currently does not cause neighbor probing if the target |ip|
+        // has been confirmed reachable within the past "delay_probe_time"
+        // seconds, i.e. within the past 5 seconds.
+        //
+        // TODO: replace with a transition directly to NUD_PROBE state once
+        // kernels are updated to do so correctly.
+        if (DBG) { Log.d(TAG, "Probing ip=" + ip.getHostAddress()); }
+
+        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+                1, ip, StructNdMsg.NUD_DELAY, ifIndex, null);
+        NetlinkSocket nlSocket = null;
+        boolean returnValue = false;
+
+        try {
+            nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
+            nlSocket.connectToKernel();
+            nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
+            final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+            final NetlinkMessage response = NetlinkMessage.parse(bytes);
+            if (response != null && response instanceof NetlinkErrorMessage &&
+                    (((NetlinkErrorMessage) response).getNlMsgError() != null) &&
+                    (((NetlinkErrorMessage) response).getNlMsgError().error == 0)) {
+                returnValue = true;
+            } else {
+                String errmsg;
+                if (bytes == null) {
+                    errmsg = "null recvMessage";
+                } else if (response == null) {
+                    bytes.position(0);
+                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
+                } else {
+                    errmsg = response.toString();
+                }
+                Log.e(TAG, "Error probing ip=" + ip.getHostAddress() +
+                        ", errmsg=" + errmsg);
+            }
+        } catch (ErrnoException | InterruptedIOException | SocketException e) {
+            Log.d(TAG, "Error probing ip=" + ip.getHostAddress(), e);
+        }
+
+        if (nlSocket != null) {
+            nlSocket.close();
+        }
+        return returnValue;
+    }
 
     public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
         mInterfaceName = ifName;
@@ -88,15 +143,15 @@
         mIpWatchList = new HashSet<InetAddress>();
         mIpWatchListVersion = 0;
         mRunning = false;
-        mObserverThread = new Thread(new NetlinkSocketObserver());
+        mNetlinkSocketObserver = new NetlinkSocketObserver();
+        mObserverThread = new Thread(mNetlinkSocketObserver);
         mObserverThread.start();
     }
 
     public void stop() {
-        synchronized (mLock) {
-            mRunning = false;
-            mIpWatchList.clear();
-        }
+        synchronized (mLock) { mRunning = false; }
+        clearLinkProperties();
+        mNetlinkSocketObserver.clearNetlinkSocket();
     }
 
     // TODO: add a public dump() method that can be called during a bug report.
@@ -215,42 +270,15 @@
             ipProbeList.addAll(mIpWatchList);
         }
         for (InetAddress target : ipProbeList) {
-            if (!stillRunning()) { break; }
-            probeIp(target);
-        }
-    }
-
-    private void probeIp(InetAddress ip) {
-        // This currently does not cause neighbor probing if the target |ip|
-        // has been confirmed reachable within the past "delay_probe_time"
-        // seconds, i.e. within the past 5 seconds.
-        //
-        // TODO: replace with a transition directly to NUD_PROBE state once
-        // kernels are updated to do so correctly.
-        if (DBG) { Log.d(TAG, "Probing ip=" + ip.getHostAddress()); }
-
-        final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
-                1, ip, StructNdMsg.NUD_DELAY, mInterfaceIndex, null);
-        NetlinkSocket nlSocket = null;
-
-        try {
-            nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
-            nlSocket.connectToKernel();
-            nlSocket.sendMessage(msg, 0, msg.length, 300);
-            final NetlinkMessage response = NetlinkMessage.parse(nlSocket.recvMessage(300));
-            if (response != null && response instanceof NetlinkErrorMessage) {
-                Log.e(TAG, "Error probing ip=" + response.toString());
+            if (!stillRunning()) {
+                break;
             }
-        } catch (ErrnoException | InterruptedIOException | SocketException e) {
-            Log.d(TAG, "Error probing ip=" + ip.getHostAddress(), e);
-        }
-
-        if (nlSocket != null) {
-            nlSocket.close();
+            probeNeighbor(mInterfaceIndex, target);
         }
     }
 
 
+    // TODO: simply the number of objects by making this extend Thread.
     private final class NetlinkSocketObserver implements Runnable {
         private static final String TAG = "NetlinkSocketObserver";
         private NetlinkSocket mSocket;
@@ -292,7 +320,6 @@
             if (mSocket != null) {
                 mSocket.close();
             }
-            mSocket = null;
         }
 
             // TODO: Refactor the main loop to recreate the socket upon recoverable errors.
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 9c3a623..e6fc1ea 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -27,6 +27,7 @@
 import com.android.internal.util.Protocol;
 
 import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * A Utility class for handling for communicating between bearer-specific
@@ -51,6 +52,8 @@
     private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
     private volatile long mLastBwRefreshTime = 0;
     private static final long BW_REFRESH_MIN_WIN_MS = 500;
+    private boolean mPollLceScheduled = false;
+    private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
 
     private static final int BASE = Protocol.BASE_NETWORK_AGENT;
 
@@ -207,11 +210,23 @@
                 break;
             }
             case CMD_REQUEST_BANDWIDTH_UPDATE: {
+                long currentTimeMs = System.currentTimeMillis();
                 if (VDBG) {
                     log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
                 }
-                if (System.currentTimeMillis() > (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
-                    pollLceData();
+                if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
+                    mPollLceScheduled = false;
+                    if (mPollLcePending.getAndSet(true) == false) {
+                        pollLceData();
+                    }
+                } else {
+                    // deliver the request at a later time rather than discard it completely.
+                    if (!mPollLceScheduled) {
+                        long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS -
+                                currentTimeMs + 1;
+                        mPollLceScheduled = sendEmptyMessageDelayed(
+                                CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
+                    }
                 }
                 break;
             }
@@ -260,6 +275,7 @@
      * Called by the bearer code when it has new NetworkCapabilities data.
      */
     public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
+        mPollLcePending.set(false);
         mLastBwRefreshTime = System.currentTimeMillis();
         queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED,
                 new NetworkCapabilities(networkCapabilities));
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 7838b47..e61594c 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -115,6 +115,18 @@
         }
 
         /**
+         * Completely clears all the {@code NetworkCapabilities} from this builder instance,
+         * removing even the capabilities that are set by default when the object is constructed.
+         *
+         * @return The builder to facilitate chaining.
+         * @hide
+         */
+        public Builder clearCapabilities() {
+            mNetworkCapabilities.clearAll();
+            return this;
+        }
+
+        /**
          * Adds the given transport requirement to this builder.  These represent
          * the set of allowed transports for the request.  Only networks using one
          * of these transports will satisfy the request.  If no particular transports
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index 2c90909..5f5e623 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -35,13 +35,7 @@
  *
  * Other HTTP stacks will need to obtain the proxy info from
  * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
- *
- * @deprecated Please use {@link java.net.URL#openConnection}, {@link java.net.Proxy} and
- *     friends. The Apache HTTP client is no longer maintained and may be removed in a future
- *     release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- *     for further details.
  */
-@Deprecated
 public class ProxyInfo implements Parcelable {
 
     private String mHost;
diff --git a/core/java/android/net/netlink/NetlinkErrorMessage.java b/core/java/android/net/netlink/NetlinkErrorMessage.java
index dbc10d6..e275574 100644
--- a/core/java/android/net/netlink/NetlinkErrorMessage.java
+++ b/core/java/android/net/netlink/NetlinkErrorMessage.java
@@ -18,7 +18,6 @@
 
 import android.net.netlink.StructNlMsgHdr;
 import android.net.netlink.NetlinkMessage;
-import android.util.Log;
 
 import java.nio.ByteBuffer;
 
diff --git a/core/java/android/net/netlink/NetlinkMessage.java b/core/java/android/net/netlink/NetlinkMessage.java
index bc04a16..3bf75ca 100644
--- a/core/java/android/net/netlink/NetlinkMessage.java
+++ b/core/java/android/net/netlink/NetlinkMessage.java
@@ -60,7 +60,7 @@
         switch (nlmsghdr.nlmsg_type) {
             //case NetlinkConstants.NLMSG_NOOP:
             case NetlinkConstants.NLMSG_ERROR:
-                return (NetlinkMessage) NetlinkErrorMessage.parse(byteBuffer);
+                return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer);
             case NetlinkConstants.NLMSG_DONE:
                 byteBuffer.position(byteBuffer.position() + payloadLength);
                 return new NetlinkMessage(nlmsghdr);
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
index b5f5817..02df131 100644
--- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
+++ b/core/java/android/net/netlink/RtNetlinkNeighborMessage.java
@@ -16,6 +16,11 @@
 
 package android.net.netlink;
 
+import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+
 import android.net.netlink.StructNdaCacheInfo;
 import android.net.netlink.StructNdMsg;
 import android.net.netlink.StructNlAttr;
@@ -123,7 +128,7 @@
         final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
         nlmsghdr.nlmsg_len = length;
         nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH;
-        nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST|StructNlMsgHdr.NLM_F_DUMP;
+        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
         nlmsghdr.nlmsg_seq = seqNo;
         nlmsghdr.pack(byteBuffer);
 
@@ -141,7 +146,7 @@
             int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) {
         final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
         nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH;
-        nlmsghdr.nlmsg_flags = StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_REPLACE;
+        nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
         nlmsghdr.nlmsg_seq = seqNo;
 
         final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr);
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/core/java/android/net/netlink/StructNlMsgErr.java
index 6b02650..f095af4 100644
--- a/core/java/android/net/netlink/StructNlMsgErr.java
+++ b/core/java/android/net/netlink/StructNlMsgErr.java
@@ -52,11 +52,6 @@
     public int error;
     public StructNlMsgHdr msg;
 
-    public StructNlMsgErr() {
-        error = 0;
-        msg = null;
-    }
-
     public void pack(ByteBuffer byteBuffer) {
         // The ByteOrder must have already been set by the caller.  In most
         // cases ByteOrder.nativeOrder() is correct, with the possible
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 9623695..04e54aa 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
     public final int flags;
     public long size;
     public String label;
+    /** Hacky; don't rely on this count */
+    public int volumeCount;
 
     public DiskInfo(String id, int flags) {
         this.id = Preconditions.checkNotNull(id);
@@ -61,6 +63,7 @@
         flags = parcel.readInt();
         size = parcel.readLong();
         label = parcel.readString();
+        volumeCount = parcel.readInt();
     }
 
     public @NonNull String getId() {
@@ -181,5 +184,6 @@
         parcel.writeInt(this.flags);
         parcel.writeLong(size);
         parcel.writeString(label);
+        parcel.writeInt(volumeCount);
     }
 }
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index e07e846..76a5f967 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -230,6 +230,8 @@
      * }
      * </pre>
      * </p>
+     *
+     * @hide
      */
     public static final class Authorization {
         /**
@@ -4067,6 +4069,21 @@
         public static final String SYNC3 = "data_sync3";
         /** Generic column for use by sync adapters. */
         public static final String SYNC4 = "data_sync4";
+
+        /**
+         * Carrier presence information.
+         * <P>
+         * Type: INTEGER (A bitmask of CARRIER_PRESENCE_* fields)
+         * </P>
+         */
+        public static final String CARRIER_PRESENCE = "carrier_presence";
+
+        /**
+         * Bitmask flags for CARRIER_PRESENCE column. Each value represents
+         * a bit (or a set of bits) which may be set independently of each
+         * other.
+         */
+        public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01;
     }
 
     /**
@@ -7913,6 +7930,8 @@
 
     /**
      * API for inquiring about the general status of the provider.
+     *
+     * @hide
      */
     public static final class ProviderStatus {
 
@@ -8261,7 +8280,7 @@
         /**
          * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager
          * to strip off anything not necessary.
-         * 
+         *
          * @hide
          */
         public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId,
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index d70712a..cdc196e 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -30,21 +30,21 @@
  * <p>A TextureView can be used to display a content stream. Such a content
  * stream can for instance be a video or an OpenGL scene. The content stream
  * can come from the application's process as well as a remote process.</p>
- * 
+ *
  * <p>TextureView can only be used in a hardware accelerated window. When
  * rendered in software, TextureView will draw nothing.</p>
- * 
+ *
  * <p>Unlike {@link SurfaceView}, TextureView does not create a separate
  * window but behaves as a regular View. This key difference allows a
  * TextureView to be moved, transformed, animated, etc. For instance, you
  * can make a TextureView semi-translucent by calling
  * <code>myView.setAlpha(0.5f)</code>.</p>
- * 
+ *
  * <p>Using a TextureView is simple: all you need to do is get its
  * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
- * render content. The following example demonstrates how to render the 
+ * render content. The following example demonstrates how to render the
  * camera preview into a TextureView:</p>
- * 
+ *
  * <pre>
  *  public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
  *      private Camera mCamera;
@@ -85,19 +85,19 @@
  *      }
  *  }
  * </pre>
- * 
+ *
  * <p>A TextureView's SurfaceTexture can be obtained either by invoking
  * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
  * It is important to know that a SurfaceTexture is available only after the
  * TextureView is attached to a window (and {@link #onAttachedToWindow()} has
  * been invoked.) It is therefore highly recommended you use a listener to
  * be notified when the SurfaceTexture becomes available.</p>
- * 
+ *
  * <p>It is important to note that only one producer can use the TextureView.
  * For instance, if you use a TextureView to display the camera preview, you
  * cannot use {@link #lockCanvas()} to draw onto the TextureView at the same
  * time.</p>
- * 
+ *
  * @see SurfaceView
  * @see SurfaceTexture
  */
@@ -127,7 +127,7 @@
 
     /**
      * Creates a new TextureView.
-     * 
+     *
      * @param context The context to associate this view with.
      */
     public TextureView(Context context) {
@@ -137,7 +137,7 @@
 
     /**
      * Creates a new TextureView.
-     * 
+     *
      * @param context The context to associate this view with.
      * @param attrs The attributes of the XML tag that is inflating the view.
      */
@@ -148,7 +148,7 @@
 
     /**
      * Creates a new TextureView.
-     * 
+     *
      * @param context The context to associate this view with.
      * @param attrs The attributes of the XML tag that is inflating the view.
      * @param defStyleAttr An attribute in the current theme that contains a
@@ -193,7 +193,7 @@
     /**
      * Indicates whether the content of this TextureView is opaque. The
      * content is assumed to be opaque by default.
-     * 
+     *
      * @param opaque True if the content of this TextureView is opaque,
      *               false otherwise
      */
@@ -258,7 +258,7 @@
      * considered to act as a hardware layer. The optional paint supplied to this
      * method will however be taken into account when rendering the content of
      * this TextureView.
-     * 
+     *
      * @param layerType The ype of layer to use with this view, must be one of
      *        {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
      *        {@link #LAYER_TYPE_HARDWARE}
@@ -297,7 +297,7 @@
     /**
      * Subclasses of TextureView cannot do their own rendering
      * with the {@link Canvas} object.
-     * 
+     *
      * @param canvas The Canvas to which the View is rendered.
      */
     @Override
@@ -312,7 +312,7 @@
     /**
      * Subclasses of TextureView cannot do their own rendering
      * with the {@link Canvas} object.
-     * 
+     *
      * @param canvas The Canvas to which the View is rendered.
      */
     @Override
@@ -435,7 +435,7 @@
                 return;
             }
         }
-        
+
         mLayer.prepare(getWidth(), getHeight(), mOpaque);
         mLayer.updateSurfaceTexture();
 
@@ -449,17 +449,17 @@
      * The specified transform applies to the underlying surface
      * texture and does not affect the size or position of the view
      * itself, only of its content.</p>
-     * 
+     *
      * <p>Some transforms might prevent the content from drawing
      * all the pixels contained within this view's bounds. In such
      * situations, make sure this texture view is not marked opaque.</p>
-     * 
+     *
      * @param transform The transform to apply to the content of
      *        this view.
-     * 
-     * @see #getTransform(android.graphics.Matrix) 
-     * @see #isOpaque() 
-     * @see #setOpaque(boolean) 
+     *
+     * @see #getTransform(android.graphics.Matrix)
+     * @see #isOpaque()
+     * @see #setOpaque(boolean)
      */
     public void setTransform(Matrix transform) {
         mMatrix.set(transform);
@@ -469,14 +469,14 @@
 
     /**
      * Returns the transform associated with this texture view.
-     * 
+     *
      * @param transform The {@link Matrix} in which to copy the current
      *        transform. Can be null.
-     * 
+     *
      * @return The specified matrix if not null or a new {@link Matrix}
      *         instance otherwise.
-     *         
-     * @see #setTransform(android.graphics.Matrix) 
+     *
+     * @see #setTransform(android.graphics.Matrix)
      */
     public Matrix getTransform(Matrix transform) {
         if (transform == null) {
@@ -499,21 +499,21 @@
      * <p>Returns a {@link android.graphics.Bitmap} representation of the content
      * of the associated surface texture. If the surface texture is not available,
      * this method returns null.</p>
-     * 
+     *
      * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888}
      * pixel format and its dimensions are the same as this view's.</p>
-     * 
+     *
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
-     * 
+     *
      * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
-     * 
+     *
      * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
      *         texture is not available or the width &lt;= 0 or the height &lt;= 0
-     * 
-     * @see #isAvailable() 
-     * @see #getBitmap(android.graphics.Bitmap) 
-     * @see #getBitmap(int, int) 
+     *
+     * @see #isAvailable()
+     * @see #getBitmap(android.graphics.Bitmap)
+     * @see #getBitmap(int, int)
      */
     public Bitmap getBitmap() {
         return getBitmap(getWidth(), getHeight());
@@ -523,24 +523,24 @@
      * <p>Returns a {@link android.graphics.Bitmap} representation of the content
      * of the associated surface texture. If the surface texture is not available,
      * this method returns null.</p>
-     * 
+     *
      * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888}
      * pixel format.</p>
-     * 
+     *
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
-     * 
+     *
      * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
-     * 
+     *
      * @param width The width of the bitmap to create
      * @param height The height of the bitmap to create
-     * 
+     *
      * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
      *         texture is not available or width is &lt;= 0 or height is &lt;= 0
-     * 
-     * @see #isAvailable() 
-     * @see #getBitmap(android.graphics.Bitmap) 
-     * @see #getBitmap() 
+     *
+     * @see #isAvailable()
+     * @see #getBitmap(android.graphics.Bitmap)
+     * @see #getBitmap()
      */
     public Bitmap getBitmap(int width, int height) {
         if (isAvailable() && width > 0 && height > 0) {
@@ -555,21 +555,21 @@
      * bitmap. If the surface texture is not available, the copy is not executed.
      * The content of the surface texture will be scaled to fit exactly inside
      * the specified bitmap.</p>
-     * 
+     *
      * <p><strong>Do not</strong> invoke this method from a drawing method
      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
-     * 
+     *
      * <p>If an error occurs, the bitmap is left unchanged.</p>
-     * 
+     *
      * @param bitmap The bitmap to copy the content of the surface texture into,
      *               cannot be null, all configurations are supported
-     * 
+     *
      * @return The bitmap specified as a parameter
-     * 
-     * @see #isAvailable() 
-     * @see #getBitmap(int, int)  
-     * @see #getBitmap() 
-     * 
+     *
+     * @see #isAvailable()
+     * @see #getBitmap(int, int)
+     * @see #getBitmap()
+     *
      * @throws IllegalStateException if the hardware rendering context cannot be
      *         acquired to capture the bitmap
      */
@@ -609,21 +609,21 @@
      * to implement
      * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)}
      * to find out when the Surface is available for use.</p>
-     * 
+     *
      * <p>The content of the Surface is never preserved between unlockCanvas()
      * and lockCanvas(), for this reason, every pixel within the Surface area
      * must be written. The only exception to this rule is when a dirty
      * rectangle is specified, in which case, non-dirty pixels will be
      * preserved.</p>
-     * 
+     *
      * <p>This method can only be used if the underlying surface is not already
      * owned by another producer. For instance, if the TextureView is being used
      * to render the camera's preview you cannot invoke this method.</p>
-     * 
+     *
      * @return A Canvas used to draw into the surface.
-     * 
-     * @see #lockCanvas(android.graphics.Rect) 
-     * @see #unlockCanvasAndPost(android.graphics.Canvas) 
+     *
+     * @see #lockCanvas(android.graphics.Rect)
+     * @see #unlockCanvasAndPost(android.graphics.Canvas)
      */
     public Canvas lockCanvas() {
         return lockCanvas(null);
@@ -639,12 +639,12 @@
      * available (see {@link #isAvailable()} or if the surface texture is
      * already connected to an image producer (for instance: the camera,
      * OpenGL, a media player, etc.)
-     * 
+     *
      * @param dirty Area of the surface that will be modified.
 
      * @return A Canvas used to draw into the surface.
-     * 
-     * @see #lockCanvas() 
+     *
+     * @see #lockCanvas()
      * @see #unlockCanvasAndPost(android.graphics.Canvas)
      * @see #isAvailable()
      */
@@ -670,11 +670,11 @@
      * current pixels will be shown on the screen, but its content is lost,
      * in particular there is no guarantee that the content of the Surface
      * will remain unchanged when lockCanvas() is called again.
-     * 
+     *
      * @param canvas The Canvas previously returned by lockCanvas()
-     * 
+     *
      * @see #lockCanvas()
-     * @see #lockCanvas(android.graphics.Rect) 
+     * @see #lockCanvas(android.graphics.Rect)
      */
     public void unlockCanvasAndPost(Canvas canvas) {
         if (mCanvas != null && canvas == mCanvas) {
@@ -691,8 +691,8 @@
      * Returns the {@link SurfaceTexture} used by this view. This method
      * may return null if the view is not attached to a window or if the surface
      * texture has not been initialized yet.
-     * 
-     * @see #isAvailable() 
+     *
+     * @see #isAvailable()
      */
     public SurfaceTexture getSurfaceTexture() {
         return mSurface;
@@ -730,9 +730,13 @@
         }
         mSurface = surfaceTexture;
 
-        // If the view is visible, update the listener in the new surface to use
-        // the existing listener in the view.
-        if (((mViewFlags & VISIBILITY_MASK) == VISIBLE)) {
+        /*
+         * If the view is visible and we already made a layer, update the
+         * listener in the new surface to use the existing listener in the view.
+         * Otherwise this will be called when the view becomes visible or the
+         * layer is created
+         */
+        if (((mViewFlags & VISIBILITY_MASK) == VISIBLE) && mLayer != null) {
             mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
         }
         mUpdateSurface = true;
@@ -742,8 +746,8 @@
     /**
      * Returns the {@link SurfaceTextureListener} currently associated with this
      * texture view.
-     * 
-     * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener) 
+     *
+     * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
      * @see SurfaceTextureListener
      */
     public SurfaceTextureListener getSurfaceTextureListener() {
@@ -753,8 +757,8 @@
     /**
      * Sets the {@link SurfaceTextureListener} used to listen to surface
      * texture events.
-     * 
-     * @see #getSurfaceTextureListener() 
+     *
+     * @see #getSurfaceTextureListener()
      * @see SurfaceTextureListener
      */
     public void setSurfaceTextureListener(SurfaceTextureListener listener) {
@@ -777,7 +781,7 @@
     public static interface SurfaceTextureListener {
         /**
          * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
-         * 
+         *
          * @param surface The surface returned by
          *                {@link android.view.TextureView#getSurfaceTexture()}
          * @param width The width of the surface
@@ -787,7 +791,7 @@
 
         /**
          * Invoked when the {@link SurfaceTexture}'s buffers size changed.
-         * 
+         *
          * @param surface The surface returned by
          *                {@link android.view.TextureView#getSurfaceTexture()}
          * @param width The new width of the surface
@@ -800,7 +804,7 @@
          * If returns true, no rendering should happen inside the surface texture after this method
          * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
          * Most applications should return true.
-         * 
+         *
          * @param surface The surface about to be destroyed
          */
         public boolean onSurfaceTextureDestroyed(SurfaceTexture surface);
@@ -808,7 +812,7 @@
         /**
          * Invoked when the specified {@link SurfaceTexture} is updated through
          * {@link SurfaceTexture#updateTexImage()}.
-         * 
+         *
          * @param surface The surface just updated
          */
         public void onSurfaceTextureUpdated(SurfaceTexture surface);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7f243d3..e044f1e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -148,7 +148,6 @@
         mInitialized = true;
         updateEnabledState(surface);
         boolean status = nInitialize(mNativeProxy, surface);
-        surface.allocateBuffers();
         return status;
     }
 
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index bd45007..f18b7ac 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -80,12 +80,18 @@
 
     /**
      * The interpolator of the underlying Animator object. By default, we don't set the interpolator
-     * on the Animator and just use its default interpolator. If the interpolator is set to a
-     * non-null value on this Animator, then we use the interpolator that it was set to.
+     * on the Animator and just use its default interpolator. If the interpolator is ever set on
+     * this Animator, then we use the interpolator that it was set to.
      */
     private TimeInterpolator mInterpolator;
 
     /**
+     * A flag indicating whether the interpolator has been set on this object. If not, we don't set
+     * the interpolator on the underlying Animator, but instead just use its default interpolator.
+     */
+    private boolean mInterpolatorSet = false;
+
+    /**
      * Listener for the lifecycle events of the underlying ValueAnimator object.
      */
     private Animator.AnimatorListener mListener = null;
@@ -332,6 +338,7 @@
      * @return This object, allowing calls to methods in this class to be chained.
      */
     public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
+        mInterpolatorSet = true;
         mInterpolator = interpolator;
         return this;
     }
@@ -342,7 +349,7 @@
      * @return The timing interpolator for this animation.
      */
     public TimeInterpolator getInterpolator() {
-        if (mInterpolator != null) {
+        if (mInterpolatorSet) {
             return mInterpolator;
         } else {
             // Just return the default from ValueAnimator, since that's what we'd get if
@@ -890,7 +897,7 @@
         if (mDurationSet) {
             animator.setDuration(mDuration);
         }
-        if (mInterpolator != null) {
+        if (mInterpolatorSet) {
             animator.setInterpolator(mInterpolator);
         }
         animator.start();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c4f9209..41f906a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1705,10 +1705,19 @@
                         mFullRedrawNeeded = true;
                         mPreviousTransparentRegion.setEmpty();
 
+                        // Only initialize up-front if transparent regions are not
+                        // requested, otherwise defer to see if the entire window
+                        // will be transparent
                         if (mAttachInfo.mHardwareRenderer != null) {
                             try {
                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
                                         mSurface);
+                                if (hwInitialized && (host.mPrivateFlags
+                                        & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
+                                    // Don't pre-allocate if transparent regions
+                                    // are requested as they may not be needed
+                                    mSurface.allocateBuffers();
+                                }
                             } catch (OutOfResourcesException e) {
                                 handleOutOfResourcesException(e);
                                 return;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 7976ca4..f0c86e5 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -218,7 +218,7 @@
             @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR, to = "TYPE_NAVIGATION_BAR"),
             @ViewDebug.IntToString(from = TYPE_VOLUME_OVERLAY, to = "TYPE_VOLUME_OVERLAY"),
             @ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS"),
-            @ViewDebug.IntToString(from = TYPE_HIDDEN_NAV_CONSUMER, to = "TYPE_HIDDEN_NAV_CONSUMER"),
+            @ViewDebug.IntToString(from = TYPE_INPUT_CONSUMER, to = "TYPE_INPUT_CONSUMER"),
             @ViewDebug.IntToString(from = TYPE_DREAM, to = "TYPE_DREAM"),
             @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"),
             @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY"),
@@ -490,12 +490,11 @@
         public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
 
         /**
-         * Window type: Fake window to consume touch events when the navigation
-         * bar is hidden.
+         * Window type to consume input events when the systemUI bars are hidden.
          * In multiuser systems shows on all users' windows.
          * @hide
          */
-        public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
+        public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;
 
         /**
          * Window type: Dreams (screen saver) window, just above keyguard.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 9199af1..1b759a3 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -373,12 +373,12 @@
     }
 
     /**
-     * Representation of a "fake window" that the policy has added to the
-     * window manager to consume events.
+     * Representation of a input consumer that the policy has added to the
+     * window manager to consume input events going to windows below it.
      */
-    public interface FakeWindow {
+    public interface InputConsumer {
         /**
-         * Remove the fake window from the window manager.
+         * Remove the input consumer from the window manager.
          */
         void dismiss();
     }
@@ -402,13 +402,10 @@
         public void reevaluateStatusBarVisibility();
 
         /**
-         * Add a fake window to the window manager.  This window sits
-         * at the top of the other windows and consumes events.
+         * Add a input consumer which will consume all input events going to any window below it.
          */
-        public FakeWindow addFakeWindow(Looper looper,
-                InputEventReceiver.Factory inputEventReceiverFactory,
-                String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags,
-                boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen);
+        public InputConsumer addInputConsumer(Looper looper,
+                InputEventReceiver.Factory inputEventReceiverFactory);
 
         /**
          * Returns a code that describes the current state of the lid switch.
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d558c7b..19184d6 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1699,6 +1699,15 @@
      * @return true if the selection mode was actually started.
      */
     private boolean startSelectionActionModeWithoutSelection() {
+        if (extractedTextModeWillBeStarted()) {
+            // Cancel the single tap delayed runnable.
+            if (mSelectionModeWithoutSelectionRunnable != null) {
+                mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
+            }
+
+            return false;
+        }
+
         if (mSelectionActionMode != null) {
             // Selection action mode is already started
             // TODO: revisit invocations to minimize this case.
@@ -1740,6 +1749,15 @@
     }
 
     private boolean startSelectionActionModeWithSelectionInternal() {
+        if (extractedTextModeWillBeStarted()) {
+            // Cancel the single tap delayed runnable.
+            if (mSelectionModeWithoutSelectionRunnable != null) {
+                mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
+            }
+
+            return false;
+        }
+
         if (mSelectionActionMode != null) {
             // Selection action mode is already started
             mSelectionActionMode.invalidate();
@@ -3477,6 +3495,10 @@
             mIdealVerticalOffset = 0.7f * handleHeight;
         }
 
+        public float getIdealVerticalOffset() {
+            return mIdealVerticalOffset;
+        }
+
         protected void updateDrawable() {
             final int offset = getCurrentCursorOffset();
             final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset);
@@ -3948,7 +3970,11 @@
 
         @Override
         protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
-            return isRtlRun ? 0 : drawable.getIntrinsicWidth();
+            if (isRtlRun) {
+                return drawable.getIntrinsicWidth() / 4;
+            } else {
+                return (drawable.getIntrinsicWidth() * 3) / 4;
+            }
         }
 
         @Override
@@ -4066,7 +4092,11 @@
 
         @Override
         protected int getHotspotX(Drawable drawable, boolean isRtlRun) {
-            return isRtlRun ? drawable.getIntrinsicWidth() : 0;
+            if (isRtlRun) {
+                return (drawable.getIntrinsicWidth() * 3) / 4;
+            } else {
+                return drawable.getIntrinsicWidth() / 4;
+            }
         }
 
         @Override
@@ -4253,6 +4283,7 @@
         private int mStartOffset = -1;
         // Indicates whether the user is selecting text and using the drag accelerator.
         private boolean mDragAcceleratorActive;
+        private boolean mHaventMovedEnoughToStartDrag;
 
         SelectionModifierCursorController() {
             resetTouchOffsets();
@@ -4317,19 +4348,20 @@
         public void onTouchEvent(MotionEvent event) {
             // This is done even when the View does not have focus, so that long presses can start
             // selection and tap can move cursor from this tap position.
+            final float eventX = event.getX();
+            final float eventY = event.getY();
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
-                    final float x = event.getX();
-                    final float y = event.getY();
 
                     // Remember finger down position, to be able to start selection from there.
-                    mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(x, y);
+                    mMinTouchOffset = mMaxTouchOffset = mTextView.getOffsetForPosition(
+                            eventX, eventY);
 
                     // Double tap detection
                     if (mGestureStayedInTapRegion) {
                         if (mDoubleTap) {
-                            final float deltaX = x - mDownPositionX;
-                            final float deltaY = y - mDownPositionY;
+                            final float deltaX = eventX - mDownPositionX;
+                            final float deltaY = eventY - mDownPositionY;
                             final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
 
                             ViewConfiguration viewConfiguration = ViewConfiguration.get(
@@ -4337,16 +4369,17 @@
                             int doubleTapSlop = viewConfiguration.getScaledDoubleTapSlop();
                             boolean stayedInArea = distanceSquared < doubleTapSlop * doubleTapSlop;
 
-                            if (stayedInArea && isPositionOnText(x, y)) {
+                            if (stayedInArea && isPositionOnText(eventX, eventY)) {
                                 startSelectionActionModeWithSelectionAndStartDrag();
                                 mDiscardNextActionUp = true;
                             }
                         }
                     }
 
-                    mDownPositionX = x;
-                    mDownPositionY = y;
+                    mDownPositionX = eventX;
+                    mDownPositionY = eventY;
                     mGestureStayedInTapRegion = true;
+                    mHaventMovedEnoughToStartDrag = true;
                     break;
 
                 case MotionEvent.ACTION_POINTER_DOWN:
@@ -4360,18 +4393,24 @@
                     break;
 
                 case MotionEvent.ACTION_MOVE:
-                    final ViewConfiguration viewConfiguration = ViewConfiguration.get(
+                    final ViewConfiguration viewConfig = ViewConfiguration.get(
                             mTextView.getContext());
+                    final int touchSlop = viewConfig.getScaledTouchSlop();
 
-                    if (mGestureStayedInTapRegion) {
-                        final float deltaX = event.getX() - mDownPositionX;
-                        final float deltaY = event.getY() - mDownPositionY;
+                    if (mGestureStayedInTapRegion || mHaventMovedEnoughToStartDrag) {
+                        final float deltaX = eventX - mDownPositionX;
+                        final float deltaY = eventY - mDownPositionY;
                         final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
 
-                        int doubleTapTouchSlop = viewConfiguration.getScaledDoubleTapTouchSlop();
-
-                        if (distanceSquared > doubleTapTouchSlop * doubleTapTouchSlop) {
-                            mGestureStayedInTapRegion = false;
+                        if (mGestureStayedInTapRegion) {
+                            int doubleTapTouchSlop = viewConfig.getScaledDoubleTapTouchSlop();
+                            mGestureStayedInTapRegion =
+                                    distanceSquared <= doubleTapTouchSlop * doubleTapTouchSlop;
+                        }
+                        if (mHaventMovedEnoughToStartDrag) {
+                            // We don't start dragging until the user has moved enough.
+                            mHaventMovedEnoughToStartDrag =
+                                    distanceSquared <= touchSlop * touchSlop;
                         }
                     }
 
@@ -4381,56 +4420,28 @@
                     }
 
                     if (mStartOffset != -1) {
-                        final int rawOffset = mTextView.getOffsetForPosition(event.getX(),
-                                event.getY());
-                        int offset = rawOffset;
-
-                        // We don't start "dragging" until the user is past the initial word that
-                        // gets selected on long press.
-                        int firstWordStart = getWordStart(mStartOffset);
-                        int firstWordEnd = getWordEnd(mStartOffset);
-                        if (offset > firstWordEnd || offset < firstWordStart) {
-
-                            // Basically the goal in the below code is to have the highlight be
-                            // offset so that your finger isn't covering the end point.
-                            int fingerOffset = viewConfiguration.getScaledTouchSlop();
-                            float mx = event.getX();
-                            float my = event.getY();
-                            if (mx > fingerOffset) mx -= fingerOffset;
-                            if (my > fingerOffset) my -= fingerOffset;
-                            offset = mTextView.getOffsetForPosition(mx, my);
-
-                            // Perform the check for closeness at edge of view, if we're very close
-                            // don't adjust the offset to be in front of the finger - otherwise the
-                            // user can't select words at the edge.
-                            if (mTextView.getWidth() - fingerOffset > mx) {
-                                // We're going by word, so we need to make sure that the offset
-                                // that we get is within this, so we'll get the previous boundary.
-                                final WordIterator wordIterator = getWordIteratorWithText();
-
-                                final int precedingOffset = wordIterator.preceding(offset);
-                                if (mStartOffset < offset) {
-                                    // Expanding with bottom handle, in this case the selection end
-                                    // is before the finger.
-                                    offset = Math.max(precedingOffset - 1, 0);
-                                } else {
-                                    // Expand with the start handle, in this case the selection
-                                    // start is before the finger.
-                                    if (precedingOffset == WordIterator.DONE) {
-                                        offset = 0;
-                                    } else {
-                                        offset = wordIterator.preceding(precedingOffset);
-                                    }
-                                }
+                        if (!mHaventMovedEnoughToStartDrag) {
+                            // Offset the finger by the same vertical offset as the handles. This
+                            // improves visibility of the content being selected by shifting
+                            // the finger below the content.
+                            final float fingerOffset = (mStartHandle != null)
+                                    ? mStartHandle.getIdealVerticalOffset()
+                                    : touchSlop;
+                            int offset =
+                                    mTextView.getOffsetForPosition(eventX, eventY - fingerOffset);
+                            int startOffset;
+                            // Snap to word boundaries.
+                            if (mStartOffset < offset) {
+                                // Expanding with end handle.
+                                offset = getWordEnd(offset);
+                                startOffset = getWordStart(mStartOffset);
+                            } else {
+                                // Expanding with start handle.
+                                offset = getWordStart(offset);
+                                startOffset = getWordEnd(mStartOffset);
                             }
-                            if (offset == WordIterator.DONE)
-                                offset = rawOffset;
-
-                            // Need to adjust start offset based on direction of movement.
-                            int newStart = mStartOffset < offset ? getWordStart(mStartOffset)
-                                    : getWordEnd(mStartOffset);
-                            Selection.setSelection((Spannable) mTextView.getText(), newStart,
-                                    offset);
+                            Selection.setSelection((Spannable) mTextView.getText(),
+                                    startOffset, offset);
                         }
                     }
                     break;
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
index b9a75d3..65dc743 100644
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -208,7 +208,6 @@
     public static final int APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
     public static final int APPLICATIONS_HIGH_POWER_APPS = 184;
     public static final int FUELGAUGE_HIGH_POWER_DETAILS = 185;
-    public static final int APPLICATIONS_MANAGE_ASSIST = 186;
 
     //aliases
     public static final int DEVICEINFO_STORAGE = DEVICEINFO_MEMORY;
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 32b5b02..5144457 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -27,6 +27,10 @@
 #define ENCODING_E_AC3      6
 #define ENCODING_DTS        7
 #define ENCODING_DTS_HD     8
+#define ENCODING_MP3        9
+#define ENCODING_AAC_LC     10
+#define ENCODING_AAC_HE_V1  11
+#define ENCODING_AAC_HE_V2  12
 #define ENCODING_INVALID    0
 #define ENCODING_DEFAULT    1
 
@@ -52,6 +56,14 @@
         return AUDIO_FORMAT_DTS;
     case ENCODING_DTS_HD:
         return AUDIO_FORMAT_DTS_HD;
+    case ENCODING_MP3:
+        return AUDIO_FORMAT_MP3;
+    case ENCODING_AAC_LC:
+        return AUDIO_FORMAT_AAC_LC;
+    case ENCODING_AAC_HE_V1:
+        return AUDIO_FORMAT_AAC_HE_V1;
+    case ENCODING_AAC_HE_V2:
+        return AUDIO_FORMAT_AAC_HE_V2;
     case ENCODING_DEFAULT:
         return AUDIO_FORMAT_DEFAULT;
     default:
@@ -76,6 +88,14 @@
         return ENCODING_DTS;
     case AUDIO_FORMAT_DTS_HD:
         return ENCODING_DTS_HD;
+    case AUDIO_FORMAT_MP3:
+        return ENCODING_MP3;
+    case AUDIO_FORMAT_AAC_LC:
+        return ENCODING_AAC_LC;
+    case AUDIO_FORMAT_AAC_HE_V1:
+        return ENCODING_AAC_HE_V1;
+    case AUDIO_FORMAT_AAC_HE_V2:
+        return ENCODING_AAC_HE_V2;
     case AUDIO_FORMAT_DEFAULT:
         return ENCODING_DEFAULT;
     default:
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 87b81d5..e5c4ba9 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -521,11 +521,11 @@
 }
 
 // ----------------------------------------------------------------------------
-static jint android_media_AudioRecord_get_native_frame_count(JNIEnv *env,  jobject thiz) {
+static jint android_media_AudioRecord_get_buffer_size_in_frames(JNIEnv *env,  jobject thiz) {
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
-            "Unable to retrieve AudioRecord pointer for getNativeFrameCount()");
+            "Unable to retrieve AudioRecord pointer for frameCount()");
         return (jint)AUDIO_JAVA_ERROR;
     }
     return lpRecorder->frameCount();
@@ -700,8 +700,8 @@
                                      (void *)android_media_AudioRecord_readInArray<jfloatArray>},
     {"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
                                        (void *)android_media_AudioRecord_readInDirectBuffer},
-    {"native_get_native_frame_count",
-                             "()I",    (void *)android_media_AudioRecord_get_native_frame_count},
+    {"native_get_buffer_size_in_frames",
+                             "()I", (void *)android_media_AudioRecord_get_buffer_size_in_frames},
     {"native_set_marker_pos","(I)I",   (void *)android_media_AudioRecord_set_marker_pos},
     {"native_get_marker_pos","()I",    (void *)android_media_AudioRecord_get_marker_pos},
     {"native_set_pos_update_period",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 595f9f0..4f451c7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -681,7 +681,7 @@
         android:permissionGroup="android.permission-group.SENSORS"
         android:label="@string/permlab_useFingerprint"
         android:description="@string/permdesc_useFingerprint"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="normal" />
 
     <!-- ====================================================================== -->
     <!-- INSTALLTIME PERMISSIONS                                                -->
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
index 1550b44..7ccb70a 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
index b309dfd..e65b89d 100644
--- a/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
index b36a413..775f1bb 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
index afd0bd2..68fd053 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
index 58f8c43..b5c2a91 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
index 42a893d..6c6185c 100644
--- a/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
index d0f274a..f0e32af 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
index f1f637a..260e090 100644
--- a/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
index 643168f..a7a48b8 100644
--- a/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_left_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
index e8f3aad..2c72f4f 100644
--- a/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
+++ b/core/res/res/drawable-xxxhdpi/text_select_handle_right_mtrl_alpha.png
Binary files differ
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f790d74..c715652 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2142,8 +2142,9 @@
     <!-- Keyguard component -->
     <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
 
-    <!-- This config is used to force VoiceInteractionService to start on certain low ram devices. -->
-    <bool name="config_forceEnableVoiceInteractionService">false</bool>
+    <!-- This config is used to force VoiceInteractionService to start on certain low ram devices.
+         It declares the package name of VoiceInteractionService that should be started. -->
+    <string translatable="false" name="config_forceVoiceInteractionServicePackage"></string>
 
     <!-- This config is ued to determine whether animations are allowed in low power mode. -->
     <bool name="config_allowAnimationsInLowPowerMode">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6124b5b..4b57a47 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -280,7 +280,6 @@
   <java-symbol type="bool" name="config_enableScreenshotChord" />
   <java-symbol type="bool" name="config_bluetooth_default_profiles" />
   <java-symbol type="bool" name="config_enableWifiDisplay" />
-  <java-symbol type="bool" name="config_forceEnableVoiceInteractionService" />
   <java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
   <java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
   <java-symbol type="bool" name="config_safe_media_volume_enabled" />
@@ -560,6 +559,7 @@
   <java-symbol type="string" name="chooseActivity" />
   <java-symbol type="string" name="config_default_dns_server" />
   <java-symbol type="string" name="config_ethernet_iface_regex" />
+  <java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
   <java-symbol type="string" name="config_mms_user_agent" />
   <java-symbol type="string" name="config_mms_user_agent_profile_url" />
   <java-symbol type="string" name="config_ntpServer" />
diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java b/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java
new file mode 100644
index 0000000..e677475
--- /dev/null
+++ b/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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.net.netlink;
+
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE;
+
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.StructNlMsgErr;
+import android.util.Log;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import junit.framework.TestCase;
+import libcore.util.HexEncoding;
+
+
+public class NetlinkErrorMessageTest extends TestCase {
+    private final String TAG = "NetlinkErrorMessageTest";
+
+    // Hexadecimal representation of packet capture.
+    public static final String NLM_ERROR_OK_HEX =
+            // struct nlmsghdr
+            "24000000" +     // length = 36
+            "0200"     +     // type = 2 (NLMSG_ERROR)
+            "0000"     +     // flags
+            "26350000" +     // seqno
+            "64100000" +     // pid = userspace process
+            // error integer
+            "00000000" +     // "errno" (0 == OK)
+            // struct nlmsghdr
+            "30000000" +     // length (48) of original request
+            "1C00"     +     // type = 28 (RTM_NEWNEIGH)
+            "0501"     +     // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
+            "26350000" +     // seqno
+            "00000000";      // pid = kernel
+    public static final byte[] NLM_ERROR_OK =
+            HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false);
+
+    public void testParseNlmErrorOk() {
+        final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK);
+        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);  // For testing.
+        final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer);
+        assertNotNull(msg);
+        assertTrue(msg instanceof NetlinkErrorMessage);
+        final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg;
+
+        final StructNlMsgHdr hdr = errorMsg.getHeader();
+        assertNotNull(hdr);
+        assertEquals(36, hdr.nlmsg_len);
+        assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type);
+        assertEquals(0, hdr.nlmsg_flags);
+        assertEquals(13606, hdr.nlmsg_seq);
+        assertEquals(4196, hdr.nlmsg_pid);
+
+        final StructNlMsgErr err = errorMsg.getNlMsgError();
+        assertNotNull(err);
+        assertEquals(0, err.error);
+        assertNotNull(err.msg);
+        assertEquals(48, err.msg.nlmsg_len);
+        assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type);
+        assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags);
+        assertEquals(13606, err.msg.nlmsg_seq);
+        assertEquals(0, err.msg.nlmsg_pid);
+    }
+}
diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java b/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java
index b32de78..c599fe3 100644
--- a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java
+++ b/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java
@@ -90,4 +90,27 @@
 
         s.close();
     }
+
+    public void testRepeatedCloseCallsAreQuiet() throws Exception {
+        // Create a working NetlinkSocket.
+        NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
+        assertNotNull(s);
+        s.connectToKernel();
+        NetlinkSocketAddress localAddr = s.getLocalAddress();
+        assertNotNull(localAddr);
+        assertEquals(0, localAddr.getGroupsMask());
+        assertTrue(0 != localAddr.getPortId());
+        // Close once.
+        s.close();
+        // Test that it is closed.
+        boolean expectedErrorSeen = false;
+        try {
+            localAddr = s.getLocalAddress();
+        } catch (ErrnoException e) {
+            expectedErrorSeen = true;
+        }
+        assertTrue(expectedErrorSeen);
+        // Close once more.
+        s.close();
+    }
 }
diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
index a7bebad..19ee000 100644
--- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
+++ b/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
@@ -222,7 +222,7 @@
                 // struct nlmsghdr
                 "30000000" +     // length = 48
                 "1c00" +         // type = 28 (RTM_NEWNEIGH)
-                "0101" +         // flags (NLM_F_REQUEST | NLM_F_REPLACE)
+                "0501" +         // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE)
                 "4b0a0000" +     // seqno
                 "00000000" +     // pid (0 == kernel)
                 // struct ndmsg
diff --git a/docs/html/preview/images/bugs.png b/docs/html/preview/images/bugs.png
deleted file mode 100644
index 46adf05..0000000
--- a/docs/html/preview/images/bugs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/dev-prev.png b/docs/html/preview/images/dev-prev.png
deleted file mode 100644
index eae6ede..0000000
--- a/docs/html/preview/images/dev-prev.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/m-preview-timeline.png b/docs/html/preview/images/m-preview-timeline.png
index a065c21..bda0b46 100644
--- a/docs/html/preview/images/m-preview-timeline.png
+++ b/docs/html/preview/images/m-preview-timeline.png
Binary files differ
diff --git a/docs/html/preview/images/updates.png b/docs/html/preview/images/updates.png
deleted file mode 100644
index f165c5a..0000000
--- a/docs/html/preview/images/updates.png
+++ /dev/null
Binary files differ
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a999b71..8ad7c12 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1575,11 +1575,12 @@
      */
     public boolean sameAs(Bitmap other) {
         checkRecycled("Can't call sameAs on a recycled bitmap!");
+        if (this == other) return true;
+        if (other == null) return false;
         if (other.isRecycled()) {
             throw new IllegalArgumentException("Can't compare to a recycled bitmap!");
         }
-        return this == other || (other != null
-                && nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap));
+        return nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap);
     }
 
     /**
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f75d6a0..1030451 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -23,6 +23,7 @@
 #include "Properties.h"
 #include "renderstate/RenderState.h"
 #include "ShadowTessellator.h"
+#include "utils/GLUtils.h"
 
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -276,6 +277,9 @@
 
     clearGarbage();
     glFinish();
+    // Errors during cleanup should be considered non-fatal, dump them and
+    // and move on. TODO: All errors or just errors like bad surface?
+    GLUtils::dumpGLErrors();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 6b8c780..a17904e 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -119,7 +119,6 @@
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
     if (mSurfaceTexture.get()) {
-        mRenderThread.eglManager().requireGlContext();
         status_t err = mSurfaceTexture->detachFromContext();
         if (err != 0) {
             // TODO: Elevate to fatal exception
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index e54fa5a..d7c8316 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -169,7 +169,8 @@
 
 void RenderState::requireGLContext() {
     assertOnGLThread();
-    mRenderThread.eglManager().requireGlContext();
+    LOG_ALWAYS_FATAL_IF(!mRenderThread.eglManager().hasEglContext(),
+            "No GL context!");
 }
 
 void RenderState::assertOnGLThread() {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8329cd4..706e14e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -262,8 +262,6 @@
 
     if (drew) {
         swapBuffers(dirty, width, height);
-    } else {
-        mEglManager.cancelFrame();
     }
 
     // TODO: Use a fence for real completion?
@@ -297,7 +295,6 @@
     ATRACE_CALL();
     DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
     if (thread.eglManager().hasEglContext()) {
-        thread.eglManager().requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
 
@@ -318,7 +315,6 @@
 
 void CanvasContext::freePrefetechedLayers() {
     if (mPrefetechedLayers.size()) {
-        requireGlContext();
         std::for_each(mPrefetechedLayers.begin(), mPrefetechedLayers.end(), destroyPrefetechedNode);
         mPrefetechedLayers.clear();
     }
@@ -329,7 +325,6 @@
     if (!mEglManager.hasEglContext() || !mCanvas) {
         return;
     }
-    requireGlContext();
     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
     stopDrawing();
 
@@ -352,7 +347,6 @@
 }
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
-    requireGlContext();
     layer->apply();
     return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
 }
@@ -360,7 +354,6 @@
 void CanvasContext::destroyHardwareResources() {
     stopDrawing();
     if (mEglManager.hasEglContext()) {
-        requireGlContext();
         freePrefetechedLayers();
         mRootRenderNode->destroyHardwareResources();
         Caches::getInstance().flush(Caches::kFlushMode_Layers);
@@ -372,7 +365,6 @@
     if (!thread.eglManager().hasEglContext()) return;
 
     ATRACE_CALL();
-    thread.eglManager().requireGlContext();
     if (level >= TRIM_MEMORY_COMPLETE) {
         Caches::getInstance().flush(Caches::kFlushMode_Full);
         thread.eglManager().destroy();
@@ -382,7 +374,8 @@
 }
 
 void CanvasContext::runWithGlContext(RenderTask* task) {
-    requireGlContext();
+    LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(),
+            "GL context not initialized!");
     task->run();
 }
 
@@ -391,10 +384,6 @@
     return LayerRenderer::createTextureLayer(mRenderThread.renderState());
 }
 
-void CanvasContext::requireGlContext() {
-    mEglManager.requireGlContext();
-}
-
 void CanvasContext::setTextureAtlas(RenderThread& thread,
         const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize) {
     thread.eglManager().setTextureAtlas(buffer, map, mapSize);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 17917af..10e66e9 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -122,8 +122,6 @@
     void swapBuffers(const SkRect& dirty, EGLint width, EGLint height);
     void requireSurface();
 
-    void requireGlContext();
-
     void freePrefetechedLayers();
 
     RenderThread& mRenderThread;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 6255f5e..c0e7c73 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -78,8 +78,7 @@
         , mAllowPreserveBuffer(load_dirty_regions_property())
         , mCurrentSurface(EGL_NO_SURFACE)
         , mAtlasMap(nullptr)
-        , mAtlasMapSize(0)
-        , mInFrame(false) {
+        , mAtlasMapSize(0) {
     mCanSetPreserveBuffer = mAllowPreserveBuffer;
     ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false");
 }
@@ -101,7 +100,8 @@
 
     loadConfig();
     createContext();
-    usePBufferSurface();
+    createPBufferSurface();
+    makeCurrent(mPBufferSurface);
     mRenderThread.renderState().onGLContextCreated();
     initAtlas();
 }
@@ -110,17 +110,6 @@
     return mEglDisplay != EGL_NO_DISPLAY;
 }
 
-void EglManager::requireGlContext() {
-    LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "No EGL context");
-
-    if (!mInFrame) {
-        // We can't be certain about the state of the current surface (whether
-        // or not it is destroyed, for example), so err on the side of using
-        // the pbuffer surface which we fully control
-        usePBufferSurface();
-    }
-}
-
 void EglManager::loadConfig() {
     EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
     EGLint attribs[] = {
@@ -173,7 +162,6 @@
     mAtlasMapSize = mapSize;
 
     if (hasEglContext()) {
-        usePBufferSurface();
         initAtlas();
     }
 }
@@ -185,7 +173,7 @@
     }
 }
 
-void EglManager::usePBufferSurface() {
+void EglManager::createPBufferSurface() {
     LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
             "usePBufferSurface() called on uninitialized GlobalContext!");
 
@@ -193,7 +181,6 @@
         EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
         mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
     }
-    makeCurrent(mPBufferSurface);
 }
 
 EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
@@ -217,8 +204,6 @@
 void EglManager::destroy() {
     if (mEglDisplay == EGL_NO_DISPLAY) return;
 
-    usePBufferSurface();
-
     mRenderThread.renderState().onGLContextDestroyed();
     eglDestroyContext(mEglDisplay, mEglContext);
     eglDestroySurface(mEglDisplay, mPBufferSurface);
@@ -236,11 +221,10 @@
     if (isCurrent(surface)) return false;
 
     if (surface == EGL_NO_SURFACE) {
-        // If we are setting EGL_NO_SURFACE we don't care about any of the potential
-        // return errors, which would only happen if mEglDisplay had already been
-        // destroyed in which case the current context is already NO_CONTEXT
-        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    } else if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
+        // Ensure we always have a valid surface & context
+        surface = mPBufferSurface;
+    }
+    if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
         LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
                 (void*)surface, egl_error_str());
     }
@@ -259,12 +243,10 @@
         eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
     }
     eglBeginFrame(mEglDisplay, surface);
-    mInFrame = true;
 }
 
 bool EglManager::swapBuffers(EGLSurface surface, const SkRect& dirty,
         EGLint width, EGLint height) {
-    mInFrame = false;
 
 #if WAIT_FOR_GPU_COMPLETION
     {
@@ -328,10 +310,6 @@
     eglDestroySyncKHR(mEglDisplay, fence);
 }
 
-void EglManager::cancelFrame() {
-    mInFrame = false;
-}
-
 bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
     if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false;
 
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 0855516..8881de6 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -36,9 +36,7 @@
     void initialize();
 
     bool hasEglContext();
-    void requireGlContext();
 
-    void usePBufferSurface();
     EGLSurface createSurface(EGLNativeWindowType window);
     void destroySurface(EGLSurface surface);
 
@@ -49,7 +47,6 @@
     bool makeCurrent(EGLSurface surface);
     void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
     bool swapBuffers(EGLSurface surface, const SkRect& dirty, EGLint width, EGLint height);
-    void cancelFrame();
 
     // Returns true iff the surface is now preserving buffers.
     bool setPreserveBuffer(EGLSurface surface, bool preserve);
@@ -65,6 +62,7 @@
     // EglContext is never destroyed, method is purposely not implemented
     ~EglManager();
 
+    void createPBufferSurface();
     void loadConfig();
     void createContext();
     void initAtlas();
@@ -84,12 +82,6 @@
     sp<GraphicBuffer> mAtlasBuffer;
     int64_t* mAtlasMap;
     size_t mAtlasMapSize;
-
-    // Whether or not we are in the middle of drawing a frame. This is used
-    // to avoid switching surfaces mid-frame if requireGlContext() is called
-    // TODO: Need to be better about surface/context management so that this isn't
-    // necessary
-    bool mInFrame;
 };
 
 } /* namespace renderthread */
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 4526839..0f1be6b 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -724,6 +725,26 @@
                 return USAGE_UNKNOWN;
         }
     }
+    /**
+     * @hide
+     * CANDIDATE FOR PUBLIC (or at least SYSTEM) API
+     * Returns the stream type matching the given attributes for volume control.
+     * Use this method to derive the stream type needed to configure the volume
+     * control slider in an {@link Activity} with {@link Activity#setVolumeControlStream(int)}.
+     * <BR>Do not use this method to set the stream type on an audio player object
+     * (e.g. {@link AudioTrack}, {@link MediaPlayer}), use <code>AudioAttributes</code> instead.
+     * @param aa non-null AudioAttributes.
+     * @return a valid stream type for <code>Activity</code> or stream volume control that matches
+     *     the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
+     *     match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value
+     *     for {@link AudioManager#setStreamVolume(int, int, int)}.
+     */
+    public static int getVolumeControlStream(@NonNull AudioAttributes aa) {
+        if (aa == null) {
+            throw new IllegalArgumentException("Invalid null audio attributes");
+        }
+        return toVolumeStreamType(true /*fromGetVolumeControlStream*/, aa);
+    }
 
     /**
      * @hide
@@ -732,13 +753,19 @@
      * @param aa non-null AudioAttributes.
      * @return a valid stream type for volume control that matches the attributes.
      */
-    public static int toLegacyStreamType(AudioAttributes aa) {
+    public static int toLegacyStreamType(@NonNull AudioAttributes aa) {
+        return toVolumeStreamType(false /*fromGetVolumeControlStream*/, aa);
+    }
+
+    private static int toVolumeStreamType(boolean fromGetVolumeControlStream, AudioAttributes aa) {
         // flags to stream type mapping
         if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
-            return AudioSystem.STREAM_SYSTEM_ENFORCED;
+            return fromGetVolumeControlStream ?
+                    AudioSystem.STREAM_SYSTEM : AudioSystem.STREAM_SYSTEM_ENFORCED;
         }
         if ((aa.getFlags() & FLAG_SCO) == FLAG_SCO) {
-            return AudioSystem.STREAM_BLUETOOTH_SCO;
+            return fromGetVolumeControlStream ?
+                    AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_BLUETOOTH_SCO;
         }
 
         // usage to stream type mapping
@@ -753,7 +780,8 @@
             case USAGE_VOICE_COMMUNICATION:
                 return AudioSystem.STREAM_VOICE_CALL;
             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
-                return AudioSystem.STREAM_DTMF;
+                return fromGetVolumeControlStream ?
+                        AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_DTMF;
             case USAGE_ALARM:
                 return AudioSystem.STREAM_ALARM;
             case USAGE_NOTIFICATION_RINGTONE:
@@ -765,8 +793,15 @@
             case USAGE_NOTIFICATION_EVENT:
                 return AudioSystem.STREAM_NOTIFICATION;
             case USAGE_UNKNOWN:
+                return fromGetVolumeControlStream ?
+                        AudioManager.USE_DEFAULT_STREAM_TYPE : AudioSystem.STREAM_MUSIC;
             default:
-                return AudioSystem.STREAM_MUSIC;
+                if (fromGetVolumeControlStream) {
+                    throw new IllegalArgumentException("Unknown usage value " + aa.getUsage() +
+                            " in audio attributes");
+                } else {
+                    return AudioSystem.STREAM_MUSIC;
+                }
         }
     }
 
diff --git a/media/java/android/media/AudioDeviceCallback.java b/media/java/android/media/AudioDeviceCallback.java
index d7fa492..d9f0037 100644
--- a/media/java/android/media/AudioDeviceCallback.java
+++ b/media/java/android/media/AudioDeviceCallback.java
@@ -17,16 +17,24 @@
 package android.media;
 
 /**
- * OnAudioDeviceConnectionListener defines the interface for notification listeners in the
- * {@link AudioManager}
+ * AudioDeviceCallback defines the mechanism by which applications can receive notifications
+ * of audio device connection and disconnection events.
+ * @see AudioManager#registerAudioDeviceCallback.
  */
 public abstract class AudioDeviceCallback {
     /**
-     * Called by the {@link AudioManager} to indicate that an audio device has been
-     * connected or disconnected. A listener will probably call the
-     * {@link AudioManager#getDevices} method to retrieve the current list of audio
-     * devices.
+     * Called by the {@link AudioManager} to indicate that one or more audio devices have been
+     * connected.
+     * @param addedDevices  An array of {@link AudioDeviceInfo} objects corresponding to any
+     * newly added audio devices.
      */
     public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {}
+
+    /**
+     * Called by the {@link AudioManager} to indicate that one or more audio devices have been
+     * disconnected.
+     * @param removedDevices  An array of {@link AudioDeviceInfo} objects corresponding to any
+     * newly removed audio devices.
+     */
     public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {}
 }
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 2099bd0..431d37e 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -204,7 +204,7 @@
      * @see AudioFormat
      */
     public @NonNull int[] getEncodings() {
-        return mPort.formats();
+        return AudioFormat.filterPublicFormats(mPort.formats());
     }
 
    /**
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index a7e092f..16ae58c 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 
 /**
  * The AudioFormat class is used to access a number of audio format and
@@ -53,6 +54,22 @@
     public static final int ENCODING_DTS = 7;
     /** Audio data format: DTS HD compressed */
     public static final int ENCODING_DTS_HD = 8;
+    /** Audio data format: MP3 compressed
+     * @hide
+     * */
+    public static final int ENCODING_MP3 = 9;
+    /** Audio data format: AAC LC compressed
+     * @hide
+     * */
+    public static final int ENCODING_AAC_LC = 10;
+    /** Audio data format: AAC HE V1 compressed
+     * @hide
+     * */
+    public static final int ENCODING_AAC_HE_V1 = 11;
+    /** Audio data format: AAC HE V2 compressed
+     * @hide
+     * */
+    public static final int ENCODING_AAC_HE_V2 = 12;
 
     /** Invalid audio channel configuration */
     /** @deprecated Use {@link #CHANNEL_INVALID} instead.  */
@@ -241,6 +258,27 @@
         case ENCODING_E_AC3:
         case ENCODING_DTS:
         case ENCODING_DTS_HD:
+        case ENCODING_MP3:
+        case ENCODING_AAC_LC:
+        case ENCODING_AAC_HE_V1:
+        case ENCODING_AAC_HE_V2:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    /** @hide */
+    public static boolean isPublicEncoding(int audioFormat)
+    {
+        switch (audioFormat) {
+        case ENCODING_PCM_8BIT:
+        case ENCODING_PCM_16BIT:
+        case ENCODING_PCM_FLOAT:
+        case ENCODING_AC3:
+        case ENCODING_E_AC3:
+        case ENCODING_DTS:
+        case ENCODING_DTS_HD:
             return true;
         default:
             return false;
@@ -260,6 +298,10 @@
         case ENCODING_E_AC3:
         case ENCODING_DTS:
         case ENCODING_DTS_HD:
+        case ENCODING_MP3:
+        case ENCODING_AAC_LC:
+        case ENCODING_AAC_HE_V1:
+        case ENCODING_AAC_HE_V2:
             return false;
         case ENCODING_INVALID:
         default:
@@ -267,6 +309,28 @@
         }
     }
 
+    /**
+     * Returns an array of public encoding values extracted from an array of
+     * encoding values.
+     * @hide
+     */
+    public static int[] filterPublicFormats(int[] formats) {
+        if (formats == null) {
+            return null;
+        }
+        int[] myCopy = Arrays.copyOf(formats, formats.length);
+        int size = 0;
+        for (int i = 0; i < myCopy.length; i++) {
+            if (isPublicEncoding(myCopy[i])) {
+                if (size != i) {
+                    myCopy[size] = myCopy[i];
+                }
+                size++;
+            }
+        }
+        return Arrays.copyOf(myCopy, size);
+    }
+
     /** @removed */
     public AudioFormat()
     {
@@ -503,7 +567,7 @@
          *    if both channel index mask and channel position mask
          *    are specified but do not have the same channel count.
          */
-        public @NonNull Builder setChannelMask(int channelMask) throws IllegalArgumentException {
+        public @NonNull Builder setChannelMask(int channelMask) {
             if (channelMask == 0) {
                 throw new IllegalArgumentException("Invalid zero channel mask");
             } else if (/* channelMask != 0 && */ mChannelIndexMask != 0 &&
@@ -555,8 +619,7 @@
          *    if both channel index mask and channel position mask
          *    are specified but do not have the same channel count.
          */
-        public @NonNull Builder setChannelIndexMask(int channelIndexMask)
-                throws IllegalArgumentException {
+        public @NonNull Builder setChannelIndexMask(int channelIndexMask) {
             if (channelIndexMask == 0) {
                 throw new IllegalArgumentException("Invalid zero channel index mask");
             } else if (/* channelIndexMask != 0 && */ mChannelMask != 0 &&
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e7013a5..316ccf6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3713,11 +3713,18 @@
     private final static int MSG_DEVICES_DEVICES_ADDED = 0;
     private final static int MSG_DEVICES_DEVICES_REMOVED = 1;
 
+    /**
+     * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
+     */
     private ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>
         mDeviceCallbacks =
             new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
 
     /**
+     * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
+     * the results list to only those device types they are interested in.
+     */
+    /**
      * Specifies to the {@link AudioManager#getDevices(int)} method to include
      * source (i.e. input) audio devices.
      */
@@ -3747,21 +3754,25 @@
     }
 
     /**
-     * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
-     * connected to the system and meeting the criteria specified in the <code>flags</code>
-     * parameter.
+     * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
+     * currently connected to the system and meeting the criteria specified in the
+     * <code>flags</code> parameter.
      * @param flags A set of bitflags specifying the criteria to test.
-     * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@lGET_DEVICES_CES_ALL}.
+     * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@link GET_DEVICES_ALL}.
      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
      */
     public AudioDeviceInfo[] getDevices(int flags) {
         return getDevicesStatic(flags);
     }
 
+    /**
+     * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
+     * objects from the current (internal) AudioDevicePort list.
+     */
     private static AudioDeviceInfo[]
         infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
 
-        // figure out how many AudioDeviceInfo we need space for
+        // figure out how many AudioDeviceInfo we need space for...
         int numRecs = 0;
         for (AudioDevicePort port : ports) {
             if (checkFlags(port, flags)) {
@@ -3769,7 +3780,7 @@
             }
         }
 
-        // Now load them up
+        // Now load them up...
         AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
         int slot = 0;
         for (AudioDevicePort port : ports) {
@@ -3782,7 +3793,12 @@
     }
 
     /*
-     * Calculate the list of ports that are in ports_B, but not in ports_A
+     * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
+     * the add/remove callback mechanism to provide a list of the newly added or removed devices
+     * rather than the whole list and make the app figure it out.
+     * Note that calling this method with:
+     *  ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
+     *  ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
      */
     private static AudioDeviceInfo[] calcListDeltas(
             ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
@@ -3811,6 +3827,7 @@
      * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
      * connected to the system and meeting the criteria specified in the <code>flags</code>
      * parameter.
+     * This is an internal function. The public API front is getDevices(int).
      * @param flags A set of bitflags specifying the criteria to test.
      * @see {@link GET_DEVICES_OUTPUTS}, {@link GET_DEVICES_INPUTS} and {@link GET_DEVICES_ALL}.
      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
@@ -3821,15 +3838,20 @@
         int status = AudioManager.listAudioDevicePorts(ports);
         if (status != AudioManager.SUCCESS) {
             // fail and bail!
-            return new AudioDeviceInfo[0];
+            return new AudioDeviceInfo[0];  // Always return an array.
         }
 
         return infoListFromPortList(ports, flags);
     }
 
     /**
-     * Adds an {@link AudioDeviceCallback} to receive notifications of changes
+     * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
      * to the set of connected audio devices.
+     * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
+     * notifications.
+     * @param handler Specifies the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the {@link Handler} associated with the main
+     * {@link Looper} will be used.
      */
     public void registerAudioDeviceCallback(AudioDeviceCallback callback,
             android.os.Handler handler) {
@@ -3842,8 +3864,10 @@
     }
 
     /**
-     * Removes an {@link AudioDeviceCallback} which has been previously registered
+     * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
      * to receive notifications of changes to the set of connected audio devices.
+     * @param callback The {@link AudioDeviceCallback} object that was previously registered
+     * with {@link AudioManager#registerAudioDeviceCallback) to be unregistered.
      */
     public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
         synchronized (mDeviceCallbacks) {
@@ -3854,7 +3878,8 @@
     }
 
     /**
-     * Sends device list change notification to all listeners.
+     * Internal method to compute and generate add/remove messages and then send to any
+     * registered callbacks.
      */
     private void broadcastDeviceListChange() {
         int status;
@@ -3908,7 +3933,8 @@
 
         /**
          * Callback method called upon audio patch list update.
-         * @param patchList the updated list of audio patches
+         * Note: We don't do anything with Patches at this time, so ignore this notification.
+         * @param patchList the updated list of audio patches.
          */
         public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
 
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index c0bc6d6..7eb1357 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -494,7 +494,7 @@
          * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
          * required buffer size for the successful creation of an AudioRecord instance.
          * Since bufferSizeInBytes may be internally increased to accommodate the source
-         * requirements, use {@link #getNativeFrameCount()} to determine the actual buffer size
+         * requirements, use {@link #getBufferSizeInFrames()} to determine the actual buffer size
          * in frames.
          * @param bufferSizeInBytes a value strictly greater than 0
          * @return the same Builder instance.
@@ -777,7 +777,7 @@
     }
 
     /**
-     *  Returns the "native frame count" of the <code>AudioRecord</code> buffer.
+     *  Returns the frame count of the native <code>AudioRecord</code> buffer.
      *  This is greater than or equal to the bufferSizeInBytes converted to frame units
      *  specified in the <code>AudioRecord</code> constructor or Builder.
      *  The native frame count may be enlarged to accommodate the requirements of the
@@ -786,8 +786,8 @@
      *  @return current size in frames of the <code>AudioRecord</code> buffer.
      *  @throws IllegalStateException
      */
-    public int getNativeFrameCount() throws IllegalStateException {
-        return native_get_native_frame_count();
+    public int getBufferSizeInFrames() {
+        return native_get_buffer_size_in_frames();
     }
 
     /**
@@ -1218,16 +1218,23 @@
     //--------------------------------------------------------------------------
     // (Re)Routing Info
     //--------------------
+    /**
+     * Defines the interface by which applications can receive notifications of routing
+     * changes for the associated {@link AudioRecord}.
+     */
     public interface OnRoutingChangedListener {
         /**
          * Called when the routing of an AudioRecord changes from either and explicit or
-         * policy rerouting.
+         * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
+         * device.
          */
         public void onRoutingChanged(AudioRecord audioRecord);
     }
 
     /**
      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord.
+     * Note: The query is only valid if the AudioRecord is currently recording. If it is not,
+     * <code>getRoutedDevice()</code> will return null.
      */
     public AudioDeviceInfo getRoutedDevice() {
         int deviceId = native_getRoutedDeviceId();
@@ -1245,8 +1252,9 @@
     }
 
     /**
-     * The message sent to apps when the routing of this AudioRecord changes if they provide
-     * a {#link Handler} object to addOnRoutingChangeListener().
+     * The list of AudioRecord.OnRoutingChangedListener interface added (with
+     * {@link AudioRecord#addOnRoutingChangedListener(OnRoutingChangedListener,android.os.Handler)}
+     * by an app to receive (re)routing notifications.
      */
     private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>
         mRoutingChangeListeners =
@@ -1255,6 +1263,11 @@
     /**
      * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
      * on this AudioRecord.
+     * @param listener The {@link OnRoutingChangedListener} interface to receive notifications
+     * of rerouting events.
+     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the {@link Handler} associated with the main
+     * {@link Looper} will be used.
      */
     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
             android.os.Handler handler) {
@@ -1271,7 +1284,8 @@
 
     /**
      * Removes an {@link OnRoutingChangedListener} which has been previously added
-     * to receive notifications of changes to the set of connected audio devices.
+     * to receive rerouting notifications.
+     * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
      */
     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
         synchronized (mRoutingChangeListeners) {
@@ -1528,7 +1542,7 @@
     private native final int native_read_in_direct_buffer(Object jBuffer,
             int sizeInBytes, boolean isBlocking);
 
-    private native final int native_get_native_frame_count();
+    private native final int native_get_buffer_size_in_frames();
 
     private native final int native_set_marker_pos(int marker);
     private native final int native_get_marker_pos();
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index d21762b..bd7a247 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -229,7 +229,7 @@
     /**
      * Sizes of the native audio buffer.
      * These values are set during construction and can be stale.
-     * To obtain the current native audio buffer frame count use {@link #getNativeFrameCount()}.
+     * To obtain the current native audio buffer frame count use {@link #getBufferSizeInFrames()}.
      */
     private int mNativeBufferSizeInBytes = 0;
     private int mNativeBufferSizeInFrames = 0;
@@ -346,7 +346,7 @@
      *   If <code>bufferSizeInBytes</code> is less than the
      *   minimum buffer size for the output sink, it is automatically increased to the minimum
      *   buffer size.
-     *   The method {@link #getNativeFrameCount()} returns the
+     *   The method {@link #getBufferSizeInFrames()} returns the
      *   actual size in frames of the native buffer created, which
      *   determines the frequency to write
      *   to the streaming <code>AudioTrack</code> to avoid underrun.
@@ -775,7 +775,7 @@
             audioFormat = AudioFormat.ENCODING_PCM_16BIT;
         }
 
-        if (!AudioFormat.isValidEncoding(audioFormat)) {
+        if (!AudioFormat.isPublicEncoding(audioFormat)) {
             throw new IllegalArgumentException("Unsupported audio encoding.");
         }
         mAudioFormat = audioFormat;
@@ -1009,7 +1009,7 @@
     }
 
     /**
-     *  Returns the "native frame count" of the <code>AudioTrack</code> buffer.
+     *  Returns the frame count of the native <code>AudioTrack</code> buffer.
      *  <p> If the track's creation mode is {@link #MODE_STATIC},
      *  it is equal to the specified bufferSizeInBytes on construction, converted to frame units.
      *  A static track's native frame count will not change.
@@ -1019,12 +1019,26 @@
      *  the target output sink, and
      *  if the track is subsequently routed to a different output sink, the native
      *  frame count may enlarge to accommodate.
-     *  See also {@link AudioManager#getProperty(String)} for key
+     *  <p> If the <code>AudioTrack</code> encoding indicates compressed data,
+     *  e.g. {@link AudioFormat#ENCODING_AC3}, then the frame count returned is
+     *  the size of the native <code>AudioTrack</code> buffer in bytes.
+     *  <p> See also {@link AudioManager#getProperty(String)} for key
      *  {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
-     *  @return current size in frames of the audio track buffer.
+     *  @return current size in frames of the <code>AudioTrack</code> buffer.
      *  @throws IllegalStateException
      */
-    public int getNativeFrameCount() throws IllegalStateException {
+    public int getBufferSizeInFrames() {
+        return native_get_native_frame_count();
+    }
+
+    /**
+     *  Returns the frame count of the native <code>AudioTrack</code> buffer.
+     *  @return current size in frames of the <code>AudioTrack</code> buffer.
+     *  @throws IllegalStateException
+     *  @deprecated Use the identical public method {@link #getBufferSizeInFrames()} instead.
+     */
+    @Deprecated
+    protected int getNativeFrameCount() {
         return native_get_native_frame_count();
     }
 
@@ -1119,7 +1133,7 @@
             }
         }
 
-        if (!AudioFormat.isValidEncoding(audioFormat)) {
+        if (!AudioFormat.isPublicEncoding(audioFormat)) {
             loge("getMinBufferSize(): Invalid audio format.");
             return ERROR_BAD_VALUE;
         }
@@ -1305,6 +1319,9 @@
      * The valid sample rate range is from 1 Hz to twice the value returned by
      * {@link #getNativeOutputSampleRate(int)}.
      * Use {@link #setPlaybackParams(PlaybackParams)} for speed control.
+     * <p> This method may also be used to repurpose an existing <code>AudioTrack</code>
+     * for playback of content of differing sample rate,
+     * but with identical encoding and channel mask.
      * @param sampleRateInHz the sample rate expressed in Hz
      * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
      *    {@link #ERROR_INVALID_OPERATION}
@@ -1474,7 +1491,7 @@
      * <p>
      * If the mode is {@link #MODE_STREAM}, you can optionally prime the data path prior to
      * calling play(), by writing up to <code>bufferSizeInBytes</code> (from constructor).
-     * If you don’t call write() first, or if you call write() but with an insufficient amount of
+     * If you don't call write() first, or if you call write() but with an insufficient amount of
      * data, then the track will be in underrun state at play().  In this case,
      * playback will not actually start playing until the data path is filled to a
      * device-specific minimum level.  This requirement for the path to be filled
@@ -2153,16 +2170,23 @@
     //--------------------------------------------------------------------------
     // (Re)Routing Info
     //--------------------
+    /**
+     * Defines the interface by which applications can receive notifications of routing
+     * changes for the associated {@link AudioTrack}.
+     */
     public interface OnRoutingChangedListener {
         /**
          * Called when the routing of an AudioTrack changes from either and explicit or
-         * policy rerouting.
+         * policy rerouting.  Use {@link #getRoutedDevice()} to retrieve the newly routed-to
+         * device.
          */
         public void onRoutingChanged(AudioTrack audioTrack);
     }
 
     /**
      * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack.
+     * Note: The query is only valid if the AudioTrack is currently playing. If it is not,
+     * <code>getRoutedDevice()</code> will return null.
      */
     public AudioDeviceInfo getRoutedDevice() {
         int deviceId = native_getRoutedDeviceId();
@@ -2180,8 +2204,9 @@
     }
 
     /**
-     * The message sent to apps when the routing of this AudioTrack changes if they provide
-     * a {#link Handler} object to addOnRoutingChangedListener().
+     * The list of AudioTrack.OnRoutingChangedListener interfaces added (with
+     * {@link AudioTrack#addOnRoutingChangedListener(OnRoutingChangedListener, android.os.Handler)}
+     * by an app to receive (re)routing notifications.
      */
     private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>
         mRoutingChangeListeners =
@@ -2190,6 +2215,11 @@
     /**
      * Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
      * on this AudioTrack.
+     * @param listener The {@link OnRoutingChangedListener} interface to receive notifications
+     * of rerouting events.
+     * @param handler  Specifies the {@link Handler} object for the thread on which to execute
+     * the callback. If <code>null</code>, the {@link Handler} associated with the main
+     * {@link Looper} will be used.
      */
     public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
             android.os.Handler handler) {
@@ -2206,7 +2236,8 @@
 
     /**
      * Removes an {@link OnRoutingChangedListener} which has been previously added
-     * to receive notifications of changes to the set of connected audio devices.
+     * to receive rerouting notifications.
+     * @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
      */
     public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
         synchronized (mRoutingChangeListeners) {
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 66b904b..fed0ddf 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -173,10 +173,7 @@
                 break;
             }
             case DO_TIME_SHIFT_SET_PLAYBACK_PARAMS: {
-                PlaybackParams params = new PlaybackParams()
-                        .setSpeed((Float) msg.obj)
-                        .setAudioFallbackMode(msg.arg1);
-                mTvInputSessionImpl.timeShiftSetPlaybackParams(params);
+                mTvInputSessionImpl.timeShiftSetPlaybackParams((PlaybackParams) msg.obj);
                 break;
             }
             case DO_TIME_SHIFT_ENABLE_POSITION_TRACKING: {
diff --git a/packages/DocumentsUI/res/layout/fragment_pick.xml b/packages/DocumentsUI/res/layout/fragment_pick.xml
index 87dc4f8..40d4eb5 100644
--- a/packages/DocumentsUI/res/layout/fragment_pick.xml
+++ b/packages/DocumentsUI/res/layout/fragment_pick.xml
@@ -19,13 +19,13 @@
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:baselineAligned="false"
-    android:gravity="center_vertical"
+    android:gravity="end"
+    android:paddingEnd="8dp"
     android:minHeight="?android:attr/listPreferredItemHeightSmall">
     <Button
         android:id="@android:id/button2"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_weight="1"
         android:text="@android:string/cancel"
         android:visibility="gone"
         style="?android:attr/buttonBarNegativeButtonStyle" />
@@ -33,7 +33,5 @@
         android:id="@android:id/button1"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:textAllCaps="false"
         style="?android:attr/buttonBarPositiveButtonStyle" />
 </LinearLayout>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 5281087..9794273 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -44,8 +44,6 @@
     <string name="menu_share">Share</string>
     <!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
     <string name="menu_delete">Delete</string>
-    <!-- Menu item title that selects the current directory [CHAR LIMIT=48] -->
-    <string name="menu_select">Select \"<xliff:g id="directory" example="My Directory">^1</xliff:g>\"</string>
     <!-- Menu item title that selects all documents in the current directory [CHAR LIMIT=24] -->
     <string name="menu_select_all">Select All</string>
     <!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
@@ -65,7 +63,9 @@
     <!-- Menu item that hides the sizes of displayed files [CHAR LIMIT=24] -->
     <string name="menu_file_size_hide">Hide file size</string>
 
-    <!-- Button label that copies files to the current directory [CHAR LIMIT=48] -->
+    <!-- Button label that select the current directory [CHAR LIMIT=24] -->
+    <string name="button_select">Select</string>
+    <!-- Button label that copies files to the current directory [CHAR LIMIT=24] -->
     <string name="button_copy">Copy</string>
 
     <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index cded717..8482438 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -571,9 +571,7 @@
             mState.action == ACTION_OPEN_COPY_DESTINATION) {
             final PickFragment pick = PickFragment.get(fm);
             if (pick != null) {
-                final CharSequence displayName = (mState.stack.size() <= 1) ? root.title
-                        : cwd.displayName;
-                pick.setPickTarget(mState.action, cwd, displayName);
+                pick.setPickTarget(mState.action, cwd);
             }
         }
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index e899379..d9b8568 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -38,15 +38,19 @@
 public class PickFragment extends Fragment {
     public static final String TAG = "PickFragment";
 
+    private int mAction;
     private DocumentInfo mPickTarget;
-
     private View mContainer;
     private Button mPick;
     private Button mCancel;
 
     public static void show(FragmentManager fm) {
-        final PickFragment fragment = new PickFragment();
+        // Fragment can be restored by FragmentManager automatically.
+        if (get(fm) != null) {
+            return;
+        }
 
+        final PickFragment fragment = new PickFragment();
         final FragmentTransaction ft = fm.beginTransaction();
         ft.replace(R.id.container_save, fragment, TAG);
         ft.commitAllowingStateLoss();
@@ -67,8 +71,7 @@
         mCancel = (Button) mContainer.findViewById(android.R.id.button2);
         mCancel.setOnClickListener(mCancelListener);
 
-        setPickTarget(0, null, null);
-
+        updateView();
         return mContainer;
     }
 
@@ -92,32 +95,38 @@
     /**
      * @param action Which action defined in BaseActivity.State is the picker shown for.
      */
-    public void setPickTarget(int action,
-                              DocumentInfo pickTarget,
-                              CharSequence displayName) {
-        if (mContainer != null) {
-            if (pickTarget != null) {
-                final Locale locale = getResources().getConfiguration().locale;
-                switch (action) {
-                    case BaseActivity.State.ACTION_OPEN_TREE:
-                        final String raw = getString(R.string.menu_select).toUpperCase(locale);
-                        mPick.setText(TextUtils.expandTemplate(raw, displayName));
-                        mCancel.setVisibility(View.GONE);
-                        break;
-                    case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
-                        mPick.setText(getString(R.string.button_copy).toUpperCase(locale));
-                        mCancel.setVisibility(View.VISIBLE);
-                        break;
-                    default:
-                        throw new IllegalArgumentException("Illegal action for PickFragment.");
-                }
-            }
-            if (pickTarget != null && pickTarget.isCreateSupported()) {
-                mContainer.setVisibility(View.VISIBLE);
-            } else {
-                mContainer.setVisibility(View.GONE);
-            }
-        }
+    public void setPickTarget(int action, DocumentInfo pickTarget) {
+        mAction = action;
         mPickTarget = pickTarget;
+        if (mContainer != null) {
+            updateView();
+        }
+    }
+
+    /**
+     * Applies the state of fragment to the view components.
+     */
+    private void updateView() {
+        switch (mAction) {
+            case BaseActivity.State.ACTION_OPEN_TREE:
+                mPick.setText(R.string.button_select);
+                mCancel.setVisibility(View.GONE);
+                break;
+            case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+                mPick.setText(R.string.button_copy);
+                mCancel.setVisibility(View.VISIBLE);
+                break;
+            default:
+                mContainer.setVisibility(View.GONE);
+                return;
+        }
+
+        if (mPickTarget != null && (
+                mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+                mPickTarget.isCreateSupported())) {
+            mContainer.setVisibility(View.VISIBLE);
+        } else {
+            mContainer.setVisibility(View.GONE);
+        }
     }
 }
diff --git a/packages/Keyguard/res/values-h650dp/dimens.xml b/packages/Keyguard/res/values-h650dp/dimens.xml
index 92035bb..1cd2162 100644
--- a/packages/Keyguard/res/values-h650dp/dimens.xml
+++ b/packages/Keyguard/res/values-h650dp/dimens.xml
@@ -16,5 +16,5 @@
   -->
 
 <resources>
-    <dimen name="widget_big_font_size">104dp</dimen>
+    <dimen name="widget_big_font_size">100dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5fece8d..5360645 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -361,9 +361,7 @@
                 Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
                 return;
             }
-            if (groupId == userId) {
-                onFingerprintAuthenticated(groupId);
-            }
+            onFingerprintAuthenticated(userId);
         } finally {
             setFingerprintRunningDetectionRunning(false);
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ad710a6..1dba942 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -201,14 +201,14 @@
     @GuardedBy("mLock")
     private SettingsRegistry mSettingsRegistry;
 
-    @GuardedBy("mLock")
-    private UserManager mUserManager;
+    // We have to call in the user manager with no lock held,
+    private volatile UserManager mUserManager;
 
-    @GuardedBy("mLock")
-    private AppOpsManager mAppOpsManager;
+    // We have to call in the app ops manager with no lock held,
+    private volatile AppOpsManager mAppOpsManager;
 
-    @GuardedBy("mLock")
-    private PackageManager mPackageManager;
+    // We have to call in the package manager with no lock held,
+    private volatile PackageManager mPackageManager;
 
     @Override
     public boolean onCreate() {
@@ -224,44 +224,46 @@
 
     @Override
     public Bundle call(String method, String name, Bundle args) {
-        synchronized (mLock) {
-            final int requestingUserId = getRequestingUserId(args);
-            switch (method) {
-                case Settings.CALL_METHOD_GET_GLOBAL: {
-                    Setting setting = getGlobalSettingLocked(name);
-                    return packageValueForCallResult(setting);
-                }
-
-                case Settings.CALL_METHOD_GET_SECURE: {
-                    Setting setting = getSecureSettingLocked(name, requestingUserId);
-                    return packageValueForCallResult(setting);
-                }
-
-                case Settings.CALL_METHOD_GET_SYSTEM: {
-                    Setting setting = getSystemSettingLocked(name, requestingUserId);
-                    return packageValueForCallResult(setting);
-                }
-
-                case Settings.CALL_METHOD_PUT_GLOBAL: {
-                    String value = getSettingValue(args);
-                    insertGlobalSettingLocked(name, value, requestingUserId);
-                } break;
-
-                case Settings.CALL_METHOD_PUT_SECURE: {
-                    String value = getSettingValue(args);
-                    insertSecureSettingLocked(name, value, requestingUserId);
-                } break;
-
-                case Settings.CALL_METHOD_PUT_SYSTEM: {
-                    String value = getSettingValue(args);
-                    insertSystemSettingLocked(name, value, requestingUserId);
-                } break;
-
-                default: {
-                    Slog.w(LOG_TAG, "call() with invalid method: " + method);
-                } break;
+        final int requestingUserId = getRequestingUserId(args);
+        switch (method) {
+            case Settings.CALL_METHOD_GET_GLOBAL: {
+                Setting setting = getGlobalSetting(name);
+                return packageValueForCallResult(setting);
             }
+
+            case Settings.CALL_METHOD_GET_SECURE: {
+                Setting setting = getSecureSetting(name, requestingUserId);
+                return packageValueForCallResult(setting);
+            }
+
+            case Settings.CALL_METHOD_GET_SYSTEM: {
+                Setting setting = getSystemSetting(name, requestingUserId);
+                return packageValueForCallResult(setting);
+            }
+
+            case Settings.CALL_METHOD_PUT_GLOBAL: {
+                String value = getSettingValue(args);
+                insertGlobalSetting(name, value, requestingUserId);
+                break;
+            }
+
+            case Settings.CALL_METHOD_PUT_SECURE: {
+                String value = getSettingValue(args);
+                insertSecureSetting(name, value, requestingUserId);
+                break;
+            }
+
+            case Settings.CALL_METHOD_PUT_SYSTEM: {
+                String value = getSettingValue(args);
+                insertSystemSetting(name, value, requestingUserId);
+                break;
+            }
+
+            default: {
+                Slog.w(LOG_TAG, "call() with invalid method: " + method);
+            } break;
         }
+
         return null;
     }
 
@@ -271,7 +273,7 @@
         if (TextUtils.isEmpty(args.name)) {
             return "vnd.android.cursor.dir/" + args.table;
         } else {
-                return "vnd.android.cursor.item/" + args.table;
+            return "vnd.android.cursor.item/" + args.table;
         }
     }
 
@@ -290,40 +292,38 @@
             return new MatrixCursor(normalizedProjection, 0);
         }
 
-        synchronized (mLock) {
-            switch (args.table) {
-                case TABLE_GLOBAL: {
-                    if (args.name != null) {
-                        Setting setting = getGlobalSettingLocked(args.name);
-                        return packageSettingForQuery(setting, normalizedProjection);
-                    } else {
-                        return getAllGlobalSettingsLocked(projection);
-                    }
+        switch (args.table) {
+            case TABLE_GLOBAL: {
+                if (args.name != null) {
+                    Setting setting = getGlobalSetting(args.name);
+                    return packageSettingForQuery(setting, normalizedProjection);
+                } else {
+                    return getAllGlobalSettings(projection);
                 }
+            }
 
-                case TABLE_SECURE: {
-                    final int userId = UserHandle.getCallingUserId();
-                    if (args.name != null) {
-                        Setting setting = getSecureSettingLocked(args.name, userId);
-                        return packageSettingForQuery(setting, normalizedProjection);
-                    } else {
-                        return getAllSecureSettingsLocked(userId, projection);
-                    }
+            case TABLE_SECURE: {
+                final int userId = UserHandle.getCallingUserId();
+                if (args.name != null) {
+                    Setting setting = getSecureSetting(args.name, userId);
+                    return packageSettingForQuery(setting, normalizedProjection);
+                } else {
+                    return getAllSecureSettings(userId, projection);
                 }
+            }
 
-                case TABLE_SYSTEM: {
-                    final int userId = UserHandle.getCallingUserId();
-                    if (args.name != null) {
-                        Setting setting = getSystemSettingLocked(args.name, userId);
-                        return packageSettingForQuery(setting, normalizedProjection);
-                    } else {
-                        return getAllSystemSettingsLocked(userId, projection);
-                    }
+            case TABLE_SYSTEM: {
+                final int userId = UserHandle.getCallingUserId();
+                if (args.name != null) {
+                    Setting setting = getSystemSetting(args.name, userId);
+                    return packageSettingForQuery(setting, normalizedProjection);
+                } else {
+                    return getAllSystemSettings(userId, projection);
                 }
+            }
 
-                default: {
-                    throw new IllegalArgumentException("Invalid Uri path:" + uri);
-                }
+            default: {
+                throw new IllegalArgumentException("Invalid Uri path:" + uri);
             }
         }
     }
@@ -348,29 +348,27 @@
 
         String value = values.getAsString(Settings.Secure.VALUE);
 
-        synchronized (mLock) {
-            switch (table) {
-                case TABLE_GLOBAL: {
-                    if (insertGlobalSettingLocked(name, value, UserHandle.getCallingUserId())) {
-                        return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
-                    }
-                } break;
-
-                case TABLE_SECURE: {
-                    if (insertSecureSettingLocked(name, value, UserHandle.getCallingUserId())) {
-                        return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
-                    }
-                } break;
-
-                case TABLE_SYSTEM: {
-                    if (insertSystemSettingLocked(name, value, UserHandle.getCallingUserId())) {
-                        return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
-                    }
-                } break;
-
-                default: {
-                    throw new IllegalArgumentException("Bad Uri path:" + uri);
+        switch (table) {
+            case TABLE_GLOBAL: {
+                if (insertGlobalSetting(name, value, UserHandle.getCallingUserId())) {
+                    return Uri.withAppendedPath(Settings.Global.CONTENT_URI, name);
                 }
+            } break;
+
+            case TABLE_SECURE: {
+                if (insertSecureSetting(name, value, UserHandle.getCallingUserId())) {
+                    return Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
+                }
+            } break;
+
+            case TABLE_SYSTEM: {
+                if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) {
+                    return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);
+                }
+            } break;
+
+            default: {
+                throw new IllegalArgumentException("Bad Uri path:" + uri);
             }
         }
 
@@ -412,26 +410,25 @@
             return 0;
         }
 
-        synchronized (mLock) {
-            switch (args.table) {
-                case TABLE_GLOBAL: {
-                    final int userId = UserHandle.getCallingUserId();
-                    return deleteGlobalSettingLocked(args.name, userId) ? 1 : 0;
-                }
 
-                case TABLE_SECURE: {
-                    final int userId = UserHandle.getCallingUserId();
-                    return deleteSecureSettingLocked(args.name, userId) ? 1 : 0;
-                }
+        switch (args.table) {
+            case TABLE_GLOBAL: {
+                final int userId = UserHandle.getCallingUserId();
+                return deleteGlobalSetting(args.name, userId) ? 1 : 0;
+            }
 
-                case TABLE_SYSTEM: {
-                    final int userId = UserHandle.getCallingUserId();
-                    return deleteSystemSettingLocked(args.name, userId) ? 1 : 0;
-                }
+            case TABLE_SECURE: {
+                final int userId = UserHandle.getCallingUserId();
+                return deleteSecureSetting(args.name, userId) ? 1 : 0;
+            }
 
-                default: {
-                    throw new IllegalArgumentException("Bad Uri path:" + uri);
-                }
+            case TABLE_SYSTEM: {
+                final int userId = UserHandle.getCallingUserId();
+                return deleteSystemSetting(args.name, userId) ? 1 : 0;
+            }
+
+            default: {
+                throw new IllegalArgumentException("Bad Uri path:" + uri);
             }
         }
     }
@@ -454,26 +451,24 @@
             return 0;
         }
 
-        synchronized (mLock) {
-            switch (args.table) {
-                case TABLE_GLOBAL: {
-                    final int userId = UserHandle.getCallingUserId();
-                    return updateGlobalSettingLocked(args.name, value, userId) ? 1 : 0;
-                }
+        switch (args.table) {
+            case TABLE_GLOBAL: {
+                final int userId = UserHandle.getCallingUserId();
+                return updateGlobalSetting(args.name, value, userId) ? 1 : 0;
+            }
 
-                case TABLE_SECURE: {
-                    final int userId = UserHandle.getCallingUserId();
-                    return updateSecureSettingLocked(args.name, value, userId) ? 1 : 0;
-                }
+            case TABLE_SECURE: {
+                final int userId = UserHandle.getCallingUserId();
+                return updateSecureSetting(args.name, value, userId) ? 1 : 0;
+            }
 
-                case TABLE_SYSTEM: {
-                    final int userId = UserHandle.getCallingUserId();
-                    return updateSystemSettingLocked(args.name, value, userId) ? 1 : 0;
-                }
+            case TABLE_SYSTEM: {
+                final int userId = UserHandle.getCallingUserId();
+                return updateSystemSetting(args.name, value, userId) ? 1 : 0;
+            }
 
-                default: {
-                    throw new IllegalArgumentException("Invalid Uri path:" + uri);
-                }
+            default: {
+                throw new IllegalArgumentException("Invalid Uri path:" + uri);
             }
         }
     }
@@ -504,18 +499,18 @@
     private void dumpForUser(int userId, PrintWriter pw) {
         if (userId == UserHandle.USER_OWNER) {
             pw.println("GLOBAL SETTINGS (user " + userId + ")");
-            Cursor globalCursor = getAllGlobalSettingsLocked(ALL_COLUMNS);
+            Cursor globalCursor = getAllGlobalSettings(ALL_COLUMNS);
             dumpSettings(globalCursor, pw);
             pw.println();
         }
 
         pw.println("SECURE SETTINGS (user " + userId + ")");
-        Cursor secureCursor = getAllSecureSettingsLocked(userId, ALL_COLUMNS);
+        Cursor secureCursor = getAllSecureSettings(userId, ALL_COLUMNS);
         dumpSettings(secureCursor, pw);
         pw.println();
 
         pw.println("SYSTEM SETTINGS (user " + userId + ")");
-        Cursor systemCursor = getAllSystemSettingsLocked(userId, ALL_COLUMNS);
+        Cursor systemCursor = getAllSystemSettings(userId, ALL_COLUMNS);
         dumpSettings(systemCursor, pw);
         pw.println();
     }
@@ -575,64 +570,68 @@
                 UserHandle.ALL, true);
     }
 
-    private Cursor getAllGlobalSettingsLocked(String[] projection) {
+    private Cursor getAllGlobalSettings(String[] projection) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "getAllGlobalSettingsLocked()");
+            Slog.v(LOG_TAG, "getAllGlobalSettings()");
         }
 
-        // Get the settings.
-        SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
-                SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+        synchronized (mLock) {
+            // Get the settings.
+            SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+                    SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
 
-        List<String> names = settingsState.getSettingNamesLocked();
+            List<String> names = settingsState.getSettingNamesLocked();
 
-        final int nameCount = names.size();
+            final int nameCount = names.size();
 
-        String[] normalizedProjection = normalizeProjection(projection);
-        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+            String[] normalizedProjection = normalizeProjection(projection);
+            MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
 
-        // Anyone can get the global settings, so no security checks.
-        for (int i = 0; i < nameCount; i++) {
-            String name = names.get(i);
-            Setting setting = settingsState.getSettingLocked(name);
-            appendSettingToCursor(result, setting);
+            // Anyone can get the global settings, so no security checks.
+            for (int i = 0; i < nameCount; i++) {
+                String name = names.get(i);
+                Setting setting = settingsState.getSettingLocked(name);
+                appendSettingToCursor(result, setting);
+            }
+
+            return result;
         }
-
-        return result;
     }
 
-    private Setting getGlobalSettingLocked(String name) {
+    private Setting getGlobalSetting(String name) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
         }
 
         // Get the value.
-        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                UserHandle.USER_OWNER, name);
-    }
-
-    private boolean updateGlobalSettingLocked(String name, String value, int requestingUserId) {
-        if (DEBUG) {
-            Slog.v(LOG_TAG, "updateGlobalSettingLocked(" + name + ", " + value + ")");
+        synchronized (mLock) {
+            return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                    UserHandle.USER_OWNER, name);
         }
-        return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
     }
 
-    private boolean insertGlobalSettingLocked(String name, String value, int requestingUserId) {
+    private boolean updateGlobalSetting(String name, String value, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "insertGlobalSettingLocked(" + name + ", " + value + ")");
+            Slog.v(LOG_TAG, "updateGlobalSetting(" + name + ", " + value + ")");
         }
-        return mutateGlobalSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+        return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
     }
 
-    private boolean deleteGlobalSettingLocked(String name, int requestingUserId) {
+    private boolean insertGlobalSetting(String name, String value, int requestingUserId) {
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ")");
+        }
+        return mutateGlobalSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+    }
+
+    private boolean deleteGlobalSetting(String name, int requestingUserId) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "deleteGlobalSettingLocked(" + name + ")");
         }
-        return mutateGlobalSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+        return mutateGlobalSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
     }
 
-    private boolean mutateGlobalSettingLocked(String name, String value, int requestingUserId,
+    private boolean mutateGlobalSetting(String name, String value, int requestingUserId,
             int operation) {
         // Make sure the caller can change the settings - treated as secure.
         enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
@@ -651,28 +650,32 @@
         }
 
         // Perform the mutation.
-        switch (operation) {
-            case MUTATION_OPERATION_INSERT: {
-                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                        UserHandle.USER_OWNER, name, value, getCallingPackage());
-            }
+        synchronized (mLock) {
+            switch (operation) {
+                case MUTATION_OPERATION_INSERT: {
+                    return mSettingsRegistry
+                            .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                                    UserHandle.USER_OWNER, name, value, getCallingPackage());
+                }
 
-            case MUTATION_OPERATION_DELETE: {
-                return mSettingsRegistry.deleteSettingLocked(
-                        SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                        UserHandle.USER_OWNER, name);
-            }
+                case MUTATION_OPERATION_DELETE: {
+                    return mSettingsRegistry.deleteSettingLocked(
+                            SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                            UserHandle.USER_OWNER, name);
+                }
 
-            case MUTATION_OPERATION_UPDATE: {
-                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                        UserHandle.USER_OWNER, name, value, getCallingPackage());
+                case MUTATION_OPERATION_UPDATE: {
+                    return mSettingsRegistry
+                            .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
+                                    UserHandle.USER_OWNER, name, value, getCallingPackage());
+                }
             }
         }
 
         return false;
     }
 
-    private Cursor getAllSecureSettingsLocked(int userId, String[] projection) {
+    private Cursor getAllSecureSettings(int userId, String[] projection) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getAllSecureSettings(" + userId + ")");
         }
@@ -680,34 +683,36 @@
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
-        List<String> names = mSettingsRegistry.getSettingsNamesLocked(
-                SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
+        synchronized (mLock) {
+            List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+                    SettingsRegistry.SETTINGS_TYPE_SECURE, callingUserId);
 
-        final int nameCount = names.size();
+            final int nameCount = names.size();
 
-        String[] normalizedProjection = normalizeProjection(projection);
-        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+            String[] normalizedProjection = normalizeProjection(projection);
+            MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
 
-        for (int i = 0; i < nameCount; i++) {
-            String name = names.get(i);
+            for (int i = 0; i < nameCount; i++) {
+                String name = names.get(i);
+                // Determine the owning user as some profile settings are cloned from the parent.
+                final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId,
+                        name);
 
-            // Determine the owning user as some profile settings are cloned from the parent.
-            final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
+                // Special case for location (sigh).
+                if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
+                    return null;
+                }
 
-            // Special case for location (sigh).
-            if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
-                return null;
+                Setting setting = mSettingsRegistry.getSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
+                appendSettingToCursor(result, setting);
             }
 
-            Setting setting = mSettingsRegistry.getSettingLocked(
-                    SettingsRegistry.SETTINGS_TYPE_SECURE, owningUserId, name);
-            appendSettingToCursor(result, setting);
+            return result;
         }
-
-        return result;
     }
 
-    private Setting getSecureSettingLocked(String name, int requestingUserId) {
+    private Setting getSecureSetting(String name, int requestingUserId) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getSecureSetting(" + name + ", " + requestingUserId + ")");
         }
@@ -724,37 +729,39 @@
         }
 
         // Get the value.
-        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
-                owningUserId, name);
+        synchronized (mLock) {
+            return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                    owningUserId, name);
+        }
     }
 
-    private boolean insertSecureSettingLocked(String name, String value, int requestingUserId) {
+    private boolean insertSecureSetting(String name, String value, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "insertSecureSettingLocked(" + name + ", " + value + ", "
+            Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", "
                     + requestingUserId + ")");
         }
 
-        return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+        return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
     }
 
-    private boolean deleteSecureSettingLocked(String name, int requestingUserId) {
+    private boolean deleteSecureSetting(String name, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "deleteSecureSettingLocked(" + name + ", " + requestingUserId + ")");
+            Slog.v(LOG_TAG, "deleteSecureSetting(" + name + ", " + requestingUserId + ")");
         }
 
-        return mutateSecureSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+        return mutateSecureSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
     }
 
-    private boolean updateSecureSettingLocked(String name, String value, int requestingUserId) {
+    private boolean updateSecureSetting(String name, String value, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "updateSecureSettingLocked(" + name + ", " + value + ", "
+            Slog.v(LOG_TAG, "updateSecureSetting(" + name + ", " + value + ", "
                     + requestingUserId + ")");
         }
 
-        return mutateSecureSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+        return mutateSecureSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
     }
 
-    private boolean mutateSecureSettingLocked(String name, String value, int requestingUserId,
+    private boolean mutateSecureSetting(String name, String value, int requestingUserId,
             int operation) {
         // Make sure the caller can change the settings.
         enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
@@ -786,58 +793,65 @@
         }
 
         // Mutate the value.
-        switch(operation) {
-            case MUTATION_OPERATION_INSERT: {
-                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
-                        owningUserId, name, value, getCallingPackage());
-            }
+        synchronized (mLock) {
+            switch (operation) {
+                case MUTATION_OPERATION_INSERT: {
+                    return mSettingsRegistry
+                            .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                                    owningUserId, name, value, getCallingPackage());
+                }
 
-            case MUTATION_OPERATION_DELETE: {
-                return mSettingsRegistry.deleteSettingLocked(
-                        SettingsRegistry.SETTINGS_TYPE_SECURE,
-                        owningUserId, name);
-            }
+                case MUTATION_OPERATION_DELETE: {
+                    return mSettingsRegistry.deleteSettingLocked(
+                            SettingsRegistry.SETTINGS_TYPE_SECURE,
+                            owningUserId, name);
+                }
 
-            case MUTATION_OPERATION_UPDATE: {
-                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
-                        owningUserId, name, value, getCallingPackage());
+                case MUTATION_OPERATION_UPDATE: {
+                    return mSettingsRegistry
+                            .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SECURE,
+                                    owningUserId, name, value, getCallingPackage());
+                }
             }
         }
 
         return false;
     }
 
-    private Cursor getAllSystemSettingsLocked(int userId, String[] projection) {
+    private Cursor getAllSystemSettings(int userId, String[] projection) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "getAllSecureSystemLocked(" + userId + ")");
+            Slog.v(LOG_TAG, "getAllSecureSystem(" + userId + ")");
         }
 
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
-        List<String> names = mSettingsRegistry.getSettingsNamesLocked(
-                SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
+        synchronized (mLock) {
+            List<String> names = mSettingsRegistry.getSettingsNamesLocked(
+                    SettingsRegistry.SETTINGS_TYPE_SYSTEM, callingUserId);
 
-        final int nameCount = names.size();
+            final int nameCount = names.size();
 
-        String[] normalizedProjection = normalizeProjection(projection);
-        MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
+            String[] normalizedProjection = normalizeProjection(projection);
+            MatrixCursor result = new MatrixCursor(normalizedProjection, nameCount);
 
-        for (int i = 0; i < nameCount; i++) {
-            String name = names.get(i);
+            for (int i = 0; i < nameCount; i++) {
+                String name = names.get(i);
 
-            // Determine the owning user as some profile settings are cloned from the parent.
-            final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
+                // Determine the owning user as some profile settings are cloned from the parent.
+                final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId,
+                        name);
 
-            Setting setting = mSettingsRegistry.getSettingLocked(
-                    SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
-            appendSettingToCursor(result, setting);
+                Setting setting = mSettingsRegistry.getSettingLocked(
+                        SettingsRegistry.SETTINGS_TYPE_SYSTEM, owningUserId, name);
+                appendSettingToCursor(result, setting);
+            }
+
+            return result;
         }
-
-        return result;
     }
 
-    private Setting getSystemSettingLocked(String name, int requestingUserId) {
+    private Setting getSystemSetting(String name, int requestingUserId) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "getSystemSetting(" + name + ", " + requestingUserId + ")");
         }
@@ -849,37 +863,39 @@
         final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
 
         // Get the value.
-        return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
-                owningUserId, name);
+        synchronized (mLock) {
+            return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                    owningUserId, name);
+        }
     }
 
-    private boolean insertSystemSettingLocked(String name, String value, int requestingUserId) {
+    private boolean insertSystemSetting(String name, String value, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "insertSystemSettingLocked(" + name + ", " + value + ", "
+            Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", "
                     + requestingUserId + ")");
         }
 
-        return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
+        return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);
     }
 
-    private boolean deleteSystemSettingLocked(String name, int requestingUserId) {
+    private boolean deleteSystemSetting(String name, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "deleteSystemSettingLocked(" + name + ", " + requestingUserId + ")");
+            Slog.v(LOG_TAG, "deleteSystemSetting(" + name + ", " + requestingUserId + ")");
         }
 
-        return mutateSystemSettingLocked(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
+        return mutateSystemSetting(name, null, requestingUserId, MUTATION_OPERATION_DELETE);
     }
 
-    private boolean updateSystemSettingLocked(String name, String value, int requestingUserId) {
+    private boolean updateSystemSetting(String name, String value, int requestingUserId) {
         if (DEBUG) {
-            Slog.v(LOG_TAG, "updateSystemSettingLocked(" + name + ", " + value + ", "
+            Slog.v(LOG_TAG, "updateSystemSetting(" + name + ", " + value + ", "
                     + requestingUserId + ")");
         }
 
-        return mutateSystemSettingLocked(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
+        return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
     }
 
-    private boolean mutateSystemSettingLocked(String name, String value, int runAsUserId,
+    private boolean mutateSystemSetting(String name, String value, int runAsUserId,
             int operation) {
         // Make sure the caller can change the settings.
         enforceWritePermission(Manifest.permission.WRITE_SETTINGS);
@@ -904,27 +920,31 @@
         }
 
         // Mutate the value.
-        switch (operation) {
-            case MUTATION_OPERATION_INSERT: {
-                validateSystemSettingValue(name, value);
-                return mSettingsRegistry.insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
-                        owningUserId, name, value, getCallingPackage());
+        synchronized (mLock) {
+            switch (operation) {
+                case MUTATION_OPERATION_INSERT: {
+                    validateSystemSettingValue(name, value);
+                    return mSettingsRegistry
+                            .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                                    owningUserId, name, value, getCallingPackage());
+                }
+
+                case MUTATION_OPERATION_DELETE: {
+                    return mSettingsRegistry.deleteSettingLocked(
+                            SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                            owningUserId, name);
+                }
+
+                case MUTATION_OPERATION_UPDATE: {
+                    validateSystemSettingValue(name, value);
+                    return mSettingsRegistry
+                            .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
+                                    owningUserId, name, value, getCallingPackage());
+                }
             }
 
-            case MUTATION_OPERATION_DELETE: {
-                return mSettingsRegistry.deleteSettingLocked(
-                        SettingsRegistry.SETTINGS_TYPE_SYSTEM,
-                        owningUserId, name);
-            }
-
-            case MUTATION_OPERATION_UPDATE: {
-                validateSystemSettingValue(name, value);
-                return mSettingsRegistry.updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,
-                        owningUserId, name, value, getCallingPackage());
-            }
+            return false;
         }
-
-        return false;
     }
 
     private void validateSystemSettingValue(String name, String value) {
@@ -1043,6 +1063,7 @@
         // user info is a cached instance, so just look up instead of cache.
         final long identity = Binder.clearCallingIdentity();
         try {
+            // Just a lookup and not reentrant, so holding a lock is fine.
             UserInfo userInfo = mUserManager.getProfileParent(userId);
             return (userInfo != null) ? userInfo.id : userId;
         } finally {
@@ -1088,7 +1109,7 @@
         // skip prefix
         value = value.substring(1);
 
-        Setting settingValue = getSecureSettingLocked(
+        Setting settingValue = getSecureSetting(
                 Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
 
         String oldProviders = (settingValue != null) ? settingValue.getValue() : "";
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
index e71cf54..bb6bdbb 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
@@ -63,4 +63,10 @@
             throws AssociationServiceException {
         return AssetFactory.create(assetJson);
     }
+
+    /**
+     * If this is the source asset of a statement file, should the retriever follow
+     * any insecure (non-HTTPS) include statements made by the asset.
+     */
+    public abstract boolean followInsecureInclude();
 }
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
index 0c96038..8ead90b 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
@@ -99,6 +99,12 @@
         return getPackageName().hashCode();
     }
 
+    @Override
+    public boolean followInsecureInclude() {
+        // Non-HTTPS includes are not allowed in Android App assets.
+        return false;
+    }
+
     /**
      * Checks that the input is a valid Android app asset.
      *
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
index 6516516..548149e 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
@@ -136,7 +136,8 @@
         }
     }
 
-    private Result retrieveStatementFromUrl(String url, int maxIncludeLevel, AbstractAsset source)
+    private Result retrieveStatementFromUrl(String urlString, int maxIncludeLevel,
+                                            AbstractAsset source)
             throws AssociationServiceException {
         List<Statement> statements = new ArrayList<Statement>();
         if (maxIncludeLevel < 0) {
@@ -145,7 +146,12 @@
 
         WebContent webContent;
         try {
-            webContent = mUrlFetcher.getWebContentFromUrl(new URL(url),
+            URL url = new URL(urlString);
+            if (!source.followInsecureInclude()
+                    && !url.getProtocol().toLowerCase().equals("https")) {
+                return Result.create(statements, DO_NOT_CACHE_RESULT);
+            }
+            webContent = mUrlFetcher.getWebContentFromUrl(url,
                     HTTP_CONTENT_SIZE_LIMIT_IN_BYTES, HTTP_CONNECTION_TIMEOUT_MILLIS);
         } catch (IOException e) {
             return Result.create(statements, DO_NOT_CACHE_RESULT);
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
index 4828ff9..969aa88 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
@@ -16,6 +16,8 @@
 
 package com.android.statementservice.retriever;
 
+import android.util.Log;
+
 import com.android.volley.Cache;
 import com.android.volley.NetworkResponse;
 import com.android.volley.toolbox.HttpHeaderParser;
@@ -39,6 +41,7 @@
  * @hide
  */
 public class URLFetcher {
+    private static final String TAG = URLFetcher.class.getSimpleName();
 
     private static final long DO_NOT_CACHE_RESULT = 0L;
     private static final int INPUT_BUFFER_SIZE_IN_BYTES = 1024;
@@ -63,11 +66,17 @@
         connection.setConnectTimeout(connectionTimeoutMillis);
         connection.setReadTimeout(connectionTimeoutMillis);
         connection.setUseCaches(true);
+        connection.setInstanceFollowRedirects(false);
         connection.addRequestProperty("Cache-Control", "max-stale=60");
 
+        if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+            Log.e(TAG, "The responses code is not 200 but "  + connection.getResponseCode());
+            return new WebContent("", DO_NOT_CACHE_RESULT);
+        }
+
         if (connection.getContentLength() > fileSizeLimit) {
-            throw new AssociationServiceException("The content size of the url is larger than "
-                    + fileSizeLimit);
+            Log.e(TAG, "The content size of the url is larger than "  + fileSizeLimit);
+            return new WebContent("", DO_NOT_CACHE_RESULT);
         }
 
         Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(connection.getHeaderFields());
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
index 44af864..afb4c75 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
@@ -61,7 +61,7 @@
      */
     public static final String ASSET_DESCRIPTOR_FIELD_RELATION = "relation";
     public static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target";
-    public static final String DELEGATE_FIELD_DELEGATE = "delegate";
+    public static final String DELEGATE_FIELD_DELEGATE = "include";
 
     private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
             'A', 'B', 'C', 'D', 'E', 'F' };
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
index ca9e62d..947087a 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
@@ -39,6 +39,7 @@
 /* package private */ final class WebAsset extends AbstractAsset {
 
     private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set.";
+    private static final String SCHEME_HTTP = "http";
 
     private final URL mUrl;
 
@@ -105,6 +106,12 @@
         return toJson().hashCode();
     }
 
+    @Override
+    public boolean followInsecureInclude() {
+        // Only allow insecure include file if the asset scheme is http.
+        return SCHEME_HTTP.equals(getScheme());
+    }
+
     /**
      * Checks that the input is a valid web asset.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9ef9211..c10be7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -117,6 +117,7 @@
      * intercepted yet.
      */
     private boolean mIntercepting;
+    private boolean mPanelExpanded;
     private boolean mQsExpanded;
     private boolean mQsExpandedWhenExpandingStarted;
     private boolean mQsFullyExpanded;
@@ -1496,13 +1497,22 @@
         updateHeader();
         updateUnlockIcon();
         updateNotificationTranslucency();
-        mHeadsUpManager.setIsExpanded(!isFullyCollapsed());
+        updatePanelExpanded();
         mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
         if (DEBUG) {
             invalidate();
         }
     }
 
+    private void updatePanelExpanded() {
+        boolean isExpanded = !isFullyCollapsed();
+        if (mPanelExpanded != isExpanded) {
+            mHeadsUpManager.setIsExpanded(isExpanded);
+            mStatusBar.setPanelExpanded(isExpanded);
+            mPanelExpanded = isExpanded;
+        }
+    }
+
     /**
      * @return a temporary override of {@link #mQsMaxExpansionHeight}, which is needed when
      *         collapsing QS / the panel when QS was scrolled
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1361038..9fe591e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1967,6 +1967,10 @@
         return !mUnlockMethodCache.isCurrentlyInsecure();
     }
 
+    public void setPanelExpanded(boolean isExpanded) {
+        mStatusBarWindowManager.setPanelExpanded(isExpanded);
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -2027,7 +2031,7 @@
 
         // Expand the window to encompass the full screen in anticipation of the drag.
         // This is only possible to do atomically because the status bar is at the top of the screen!
-        mStatusBarWindowManager.setStatusBarExpanded(true);
+        mStatusBarWindowManager.setPanelVisible(true);
         mStatusBarView.setFocusable(false);
 
         visibilityChanged(true);
@@ -2156,7 +2160,7 @@
         visibilityChanged(false);
 
         // Shrink the window to the size of the status bar only
-        mStatusBarWindowManager.setStatusBarExpanded(false);
+        mStatusBarWindowManager.setPanelVisible(false);
         mStatusBarWindowManager.setForceStatusBarVisible(false);
         mStatusBarView.setFocusable(true);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 422d868..4f1c652 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -114,12 +114,12 @@
     }
 
     private void applyFocusableFlag(State state) {
+        boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
         if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
-                && state.bouncerShowing
-                || BaseStatusBar.ENABLE_REMOTE_INPUT && state.statusBarExpanded) {
+                && state.bouncerShowing || BaseStatusBar.ENABLE_REMOTE_INPUT && panelFocusable) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
+        } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
             mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
             mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         } else {
@@ -130,7 +130,7 @@
 
     private void applyHeight(State state) {
         boolean expanded = !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
-                || state.statusBarExpanded || state.keyguardFadingAway || state.bouncerShowing
+                || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
                 || state.headsUpShowing);
         if (expanded) {
             mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -213,9 +213,9 @@
         apply(mCurrentState);
     }
 
-    public void setStatusBarExpanded(boolean expanded) {
-        mCurrentState.statusBarExpanded = expanded;
-        mCurrentState.statusBarFocusable = expanded;
+    public void setPanelVisible(boolean visible) {
+        mCurrentState.panelVisible = visible;
+        mCurrentState.statusBarFocusable = visible;
         apply(mCurrentState);
     }
 
@@ -267,11 +267,17 @@
         apply(mCurrentState);
     }
 
+    public void setPanelExpanded(boolean isExpanded) {
+        mCurrentState.panelExpanded = isExpanded;
+        apply(mCurrentState);
+    }
+
     private static class State {
         boolean keyguardShowing;
         boolean keyguardOccluded;
         boolean keyguardNeedsInput;
-        boolean statusBarExpanded;
+        boolean panelVisible;
+        boolean panelExpanded;
         boolean statusBarFocusable;
         boolean bouncerShowing;
         boolean keyguardFadingAway;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 114427c..ed98a159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -59,6 +59,9 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("BluetoothController state:");
         pw.print("  mLocalBluetoothManager="); pw.println(mLocalBluetoothManager);
+        if (mLocalBluetoothManager == null) {
+            return;
+        }
         pw.print("  mEnabled="); pw.println(mEnabled);
         pw.print("  mConnecting="); pw.println(mConnecting);
         pw.print("  mLastDevice="); pw.println(mLastDevice);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 23813d1..ad21555 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -148,6 +148,11 @@
                 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
 
         // Kick current state into place
+        final List<DiskInfo> disks = mStorageManager.getDisks();
+        for (DiskInfo disk : disks) {
+            onDiskScannedInternal(disk, disk.volumeCount);
+        }
+
         final List<VolumeInfo> vols = mStorageManager.getVolumes();
         for (VolumeInfo vol : vols) {
             onVolumeStateChangedInternal(vol);
@@ -194,7 +199,7 @@
     }
 
     private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
-        if (volumeCount == 0) {
+        if (volumeCount == 0 && disk.size > 0) {
             // No supported volumes found, give user option to format
             final CharSequence title = mContext.getString(
                     R.string.ext_media_unmountable_notification_title, disk.getDescription());
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6c1023c..01cc2ca 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1725,28 +1725,68 @@
                 // At package-changed we only care about looking at new transport states
                 if (changed) {
                     try {
+                        String[] components =
+                                intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+
                         if (MORE_DEBUG) {
                             Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
+                            for (int i = 0; i < components.length; i++) {
+                                Slog.i(TAG, "   * " + components[i]);
+                            }
                         }
-                        // unbind existing possibly-stale connections to that package's transports
+
+                        // In general we need to try to bind any time we see a component enable
+                        // state change, because that change may have made a transport available.
+                        // However, because we currently only support a single transport component
+                        // per package, we can skip the bind attempt if the change (a) affects a
+                        // package known to host a transport, but (b) does not affect the known
+                        // transport component itself.
+                        //
+                        // In addition, if the change *is* to a known transport component, we need
+                        // to unbind it before retrying the binding.
+                        boolean tryBind = true;
                         synchronized (mTransports) {
                             TransportConnection conn = mTransportConnections.get(pkgName);
                             if (conn != null) {
+                                // We have a bound transport in this package; do we need to rebind it?
                                 final ServiceInfo svc = conn.mTransport;
                                 ComponentName svcName =
                                         new ComponentName(svc.packageName, svc.name);
-                                String flatName = svcName.flattenToShortString();
-                                Slog.i(TAG, "Unbinding " + svcName);
-
-                                mContext.unbindService(conn);
-                                mTransportConnections.remove(pkgName);
-                                mTransports.remove(mTransportNames.get(flatName));
-                                mTransportNames.remove(flatName);
+                                if (svc.packageName.equals(pkgName)) {
+                                    final String className = svcName.getClassName();
+                                    if (MORE_DEBUG) {
+                                        Slog.i(TAG, "Checking need to rebind " + className);
+                                    }
+                                    // See whether it's the transport component within this package
+                                    boolean isTransport = false;
+                                    for (int i = 0; i < components.length; i++) {
+                                        if (className.equals(components[i])) {
+                                            // Okay, it's an existing transport component.
+                                            final String flatName = svcName.flattenToShortString();
+                                            mContext.unbindService(conn);
+                                            mTransportConnections.remove(pkgName);
+                                            mTransports.remove(mTransportNames.get(flatName));
+                                            mTransportNames.remove(flatName);
+                                            isTransport = true;
+                                            break;
+                                        }
+                                    }
+                                    if (!isTransport) {
+                                        // A non-transport component within a package that is hosting
+                                        // a bound transport
+                                        tryBind = false;
+                                    }
+                                }
                             }
                         }
-                        // and then (re)bind as appropriate
-                        PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
-                        checkForTransportAndBind(app);
+                        // and now (re)bind as appropriate
+                        if (tryBind) {
+                            if (MORE_DEBUG) {
+                                Slog.i(TAG, "Yes, need to recheck binding");
+                            }
+                            PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
+                            checkForTransportAndBind(app);
+                        }
                     } catch (NameNotFoundException e) {
                         // Nope, can't find it - just ignore
                         if (MORE_DEBUG) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 7d427d6..79c66b9 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -408,11 +408,19 @@
             }
         }
         if (repCbs != null) {
-            for (int i=0; i<repCbs.size(); i++) {
-                try {
-                    repCbs.get(i).mCallback.opChanged(code, packageName);
-                } catch (RemoteException e) {
+            // There are components watching for mode changes such as window manager
+            // and location manager which are in our process. The callbacks in these
+            // components may require permissions our remote caller does not have.
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                for (int i = 0; i < repCbs.size(); i++) {
+                    try {
+                        repCbs.get(i).mCallback.opChanged(code, packageName);
+                    } catch (RemoteException e) {
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
         }
     }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index c46fa76..66fd36f 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -205,6 +205,7 @@
                         // Clear registered LE apps to force shut-off
                         synchronized (this) {
                             mBleAppCount = 0;
+                            mBleApps.clear();
                         }
                         if (st == BluetoothAdapter.STATE_BLE_ON) {
                             //if state is BLE_ON make sure you trigger disableBLE part
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index e00cf5b..d48953d 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -973,6 +973,7 @@
             }
         }
 
+        disk.volumeCount = volumeCount;
         mCallbacks.notifyDiskScanned(disk, volumeCount);
     }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 62f168d..d214a20 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2355,9 +2355,9 @@
             callingUid = packageUid;
         }
         checkReadAccountsPermission();
-        UserAccounts accounts = getUserAccounts(userId);
         long identityToken = clearCallingIdentity();
         try {
+            UserAccounts accounts = getUserAccounts(userId);
             synchronized (accounts.cacheLock) {
                 return getAccountsFromCacheLocked(accounts, type, callingUid, callingPackage);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6842304..5a9b5b2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8884,7 +8884,8 @@
             throw new SecurityException("updateLockTaskPackage called from non-system process");
         }
         synchronized (this) {
-            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" + packages);
+            if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":" +
+                    Arrays.toString(packages));
             mLockTaskPackages.put(userId, packages);
             mStackSupervisor.onLockTaskPackagesUpdatedLocked();
         }
@@ -8927,7 +8928,7 @@
             mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
                     ActivityManager.LOCK_TASK_MODE_PINNED :
                     ActivityManager.LOCK_TASK_MODE_LOCKED,
-                    "startLockTask");
+                    "startLockTask", true);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -8992,7 +8993,7 @@
             // Stop lock task
             synchronized (this) {
                 mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
-                        "stopLockTask");
+                        "stopLockTask", true);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -19433,7 +19434,7 @@
                 }
 
                 mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
-                        "startUser");
+                        "startUser", false);
 
                 final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
                 if (userInfo == null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f304828..5eee34f 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1185,7 +1185,7 @@
 
         final TaskRecord task = r.task;
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
-            setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE");
+            setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
         }
 
         final ActivityStack stack = task.stack;
@@ -3675,7 +3675,11 @@
     }
 
     void removeLockedTaskLocked(final TaskRecord task) {
-        if (mLockTaskModeTasks.remove(task) && mLockTaskModeTasks.isEmpty()) {
+        if (!mLockTaskModeTasks.remove(task)) {
+            return;
+        }
+        if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "removeLockedTaskLocked: removed " + task);
+        if (mLockTaskModeTasks.isEmpty()) {
             // Last one.
             if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "removeLockedTask: task=" + task +
                     " last task, reverting locktask mode. Callers=" + Debug.getCallers(3));
@@ -3696,7 +3700,8 @@
         }
     }
 
-    void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason) {
+    void setLockTaskModeLocked(TaskRecord task, int lockTaskModeState, String reason,
+            boolean andResume) {
         if (task == null) {
             // Take out of lock task mode if necessary
             final TaskRecord lockedTask = getLockedTaskLocked();
@@ -3745,8 +3750,11 @@
         if (task.mLockTaskUid == -1) {
             task.mLockTaskUid = task.mCallingUid;
         }
-        findTaskToMoveToFrontLocked(task, 0, null, reason);
-        resumeTopActivitiesLocked();
+
+        if (andResume) {
+            findTaskToMoveToFrontLocked(task, 0, null, reason);
+            resumeTopActivitiesLocked();
+        }
     }
 
     boolean isLockTaskModeViolation(TaskRecord task) {
@@ -3780,6 +3788,8 @@
             lockedTask.setLockTaskAuth();
             if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) {
                 // Lost whitelisting authorization. End it now.
+                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
+                        lockedTask + " mLockTaskAuth=" + lockedTask.lockTaskAuthToString());
                 removeLockedTaskLocked(lockedTask);
                 lockedTask.performClearTaskLocked();
                 didSomething = true;
@@ -3797,7 +3807,11 @@
         if (mLockTaskModeTasks.isEmpty() && task != null
                 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
             // This task must have just been authorized.
-            setLockTaskModeLocked(task, ActivityManager.LOCK_TASK_MODE_LOCKED, "package updated");
+            if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK,
+                    "onLockTaskPackagesUpdated: starting new locktask task=" + task);
+            setLockTaskModeLocked(task, ActivityManager.LOCK_TASK_MODE_LOCKED, "package updated",
+                    false);
+            didSomething = true;
         }
         if (didSomething) {
             resumeTopActivitiesLocked();
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 3a20ded..9f11def 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -435,9 +435,7 @@
      */
     int trimForTaskLocked(TaskRecord task, boolean doTrim) {
         int recentsCount = size();
-        final Intent intent = task.intent;
-        final boolean document = intent != null && intent.isDocument();
-
+        final boolean document = task.intent != null && task.intent.isDocument();
         int maxRecents = task.maxRecents - 1;
         for (int i = 0; i < recentsCount; i++) {
             final TaskRecord tr = get(i);
@@ -448,12 +446,11 @@
                 if (i > MAX_RECENT_BITMAPS) {
                     tr.freeLastThumbnail();
                 }
-                final Intent trIntent = tr.intent;
-                if ((task.affinity == null || !task.affinity.equals(tr.affinity)) &&
-                        (intent == null || !intent.filterEquals(trIntent))) {
+                if (task.realActivity == null || tr.realActivity == null ||
+                        !task.realActivity.equals(tr.realActivity)) {
                     continue;
                 }
-                final boolean trIsDocument = trIntent != null && trIntent.isDocument();
+                final boolean trIsDocument = tr.intent != null && tr.intent.isDocument();
                 if (document && trIsDocument) {
                     // These are the same document activity (not necessarily the same doc).
                     if (maxRecents > 0) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 417c7c3..d56a024 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -739,38 +739,40 @@
         performClearTaskAtIndexLocked(0);
     }
 
+    String lockTaskAuthToString() {
+        switch (mLockTaskAuth) {
+            case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
+            case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
+            case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
+            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+            default: return "unknown=" + mLockTaskAuth;
+        }
+    }
+
     void setLockTaskAuth() {
         switch (mLockTaskMode) {
             case LOCK_TASK_LAUNCH_MODE_DEFAULT:
-                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
-                        " mLockTaskAuth=" + (isLockTaskWhitelistedLocked() ?
-                        "WHITELISTED" : "PINNABLE"));
                 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
                     LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_NEVER:
-                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
-                        " mLockTaskAuth=" + (mPrivileged ? "DONT_LOCK" : "PINNABLE"));
                 mLockTaskAuth = mPrivileged ?
                         LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_ALWAYS:
-                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
-                        " mLockTaskAuth=" + (mPrivileged ? "LAUNCHABLE" : "PINNABLE"));
                 mLockTaskAuth = mPrivileged ?
                         LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE;
                 break;
 
             case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
-                if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
-                        " mLockTaskAuth=" + (isLockTaskWhitelistedLocked() ?
-                        "LAUNCHABLE" : "PINNABLE"));
                 mLockTaskAuth = isLockTaskWhitelistedLocked() ?
                         LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
                 break;
         }
+        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
+                " mLockTaskAuth=" + lockTaskAuthToString());
     }
 
     boolean isLockTaskWhitelistedLocked() {
@@ -1173,10 +1175,12 @@
                     pw.print(" taskType="); pw.print(taskType);
                     pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
         }
-        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask) {
+        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
+                || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
             pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
                     pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
-                    pw.print(" mReuseTask="); pw.println(mReuseTask);
+                    pw.print(" mReuseTask="); pw.print(mReuseTask);
+                    pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
         }
         if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
                 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9f35843..352c499 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4787,7 +4787,7 @@
                         if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
                                 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
                             // format the list of supported encodings
-                            int[] formats = devicePort.formats();
+                            int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
                             if (formats.length > 0) {
                                 ArrayList<Integer> encodingList = new ArrayList(1);
                                 for (int format : formats) {
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index 1d77bc2..777a9dd 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.hardware.ICameraService;
+import android.hardware.ICameraServiceProxy;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserManager;
@@ -42,14 +43,30 @@
      */
     private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
 
+    public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
+
     // Event arguments to use with the camera service notifySystemEvent call:
     public static final int NO_EVENT = 0; // NOOP
     public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
 
     private final Context mContext;
     private UserManager mUserManager;
+
+    private final Object mLock = new Object();
     private Set<Integer> mEnabledCameraUsers;
 
+    private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() {
+        @Override
+        public void pingForUserUpdate() {
+            // Binder call
+            synchronized(mLock) {
+                if (mEnabledCameraUsers != null) {
+                    notifyMediaserver(USER_SWITCHED, mEnabledCameraUsers);
+                }
+            }
+        }
+    };
+
     public CameraService(Context context) {
         super(context);
         mContext = context;
@@ -62,18 +79,27 @@
             // Should never see this unless someone messes up the SystemServer service boot order.
             throw new IllegalStateException("UserManagerService must start before CameraService!");
         }
+        publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
     }
 
     @Override
     public void onStartUser(int userHandle) {
-        if (mEnabledCameraUsers == null) {
-            // Initialize mediaserver, or update mediaserver if we are recovering from a crash.
-            onSwitchUser(userHandle);
+        synchronized(mLock) {
+            if (mEnabledCameraUsers == null) {
+                // Initialize mediaserver, or update mediaserver if we are recovering from a crash.
+                switchUserLocked(userHandle);
+            }
         }
     }
 
     @Override
     public void onSwitchUser(int userHandle) {
+        synchronized(mLock) {
+            switchUserLocked(userHandle);
+        }
+    }
+
+    private void switchUserLocked(int userHandle) {
         Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
         if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
             // Some user handles have been added or removed, update mediaserver.
@@ -82,7 +108,6 @@
         }
     }
 
-
     private Set<Integer> getEnabledUserHandles(int currentUserHandle) {
         List<UserInfo> userProfiles = mUserManager.getEnabledProfiles(currentUserHandle);
         Set<Integer> handles = new HashSet<>(userProfiles.size());
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index fba9258..bf896a5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -190,10 +190,8 @@
     private int mReevaluateToken = 0;
     private static final int INVALID_UID = -1;
     private int mUidResponsibleForReeval = INVALID_UID;
-    // When network has been evaluated this many times:
-    //   1. report NETWORK_TEST_RESULT_INVALID
-    //   2. stop blaming UID that requested re-evaluation for further attempts
-    private static final int INITIAL_EVALUATION_ATTEMPTS = 3;
+    // Stop blaming UID that requested re-evaluation after this many attempts.
+    private static final int BLAME_FOR_EVALUATION_ATTEMPTS = 5;
 
     private final Context mContext;
     private final Handler mConnectivityServiceHandler;
@@ -438,12 +436,12 @@
                     } else if (httpResponseCode >= 200 && httpResponseCode <= 399) {
                         transitionTo(mCaptivePortalState);
                     } else {
-                        Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
+                        final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
                         sendMessageDelayed(msg, mReevaluateDelayMs);
-                        if (mAttempts >= INITIAL_EVALUATION_ATTEMPTS) {
-                            mConnectivityServiceHandler.sendMessage(obtainMessage(
-                                    EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
-                                    mNetworkAgentInfo));
+                        mConnectivityServiceHandler.sendMessage(obtainMessage(
+                                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0,
+                                mNetworkAgentInfo));
+                        if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
                             // Don't continue to blame UID forever.
                             TrafficStats.clearThreadStatsUid();
                         }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index d725d94..1057ce3 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Slog;
 
 import com.android.server.SystemService;
@@ -37,6 +38,8 @@
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.IFingerprintDaemon;
+import android.hardware.fingerprint.IFingerprintDaemonCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
@@ -55,20 +58,19 @@
  *
  * @hide
  */
-public class FingerprintService extends SystemService {
+public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
     private static final String TAG = "FingerprintService";
     private static final boolean DEBUG = true;
+    private static final String FP_DATA_DIR = "fpdata";
+    private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
+    private static final int MSG_USER_SWITCHING = 10;
+    private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+
     private ClientMonitor mAuthClient = null;
     private ClientMonitor mEnrollClient = null;
     private ClientMonitor mRemoveClient = null;
-
     private final AppOpsManager mAppOps;
 
-    private static final int MSG_NOTIFY = 10;
-    private static final int MSG_USER_SWITCHING = 11;
-
-    private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
-
     // Message types. Used internally to dispatch messages to the correct callback.
     // Must agree with the list in fingerprint.h
     private static final int FINGERPRINT_ERROR = -1;
@@ -83,11 +85,6 @@
     Handler mHandler = new Handler() {
         public void handleMessage(android.os.Message msg) {
             switch (msg.what) {
-                case MSG_NOTIFY:
-                    FpHalMsg m = (FpHalMsg) msg.obj;
-                    handleNotify(m.type, m.arg1, m.arg2, m.arg3);
-                    break;
-
                 case MSG_USER_SWITCHING:
                     handleUserSwitching(msg.arg1);
                     break;
@@ -97,10 +94,13 @@
             }
         }
     };
-    private Context mContext;
-    private int mHalDeviceId;
-    private int mFailedAttempts;
+
     private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
+    private Context mContext;
+    private long mHalDeviceId;
+    private int mFailedAttempts;
+    private IFingerprintDaemon mDaemon;
+
     private final Runnable mLockoutReset = new Runnable() {
         @Override
         public void run() {
@@ -112,127 +112,115 @@
         super(context);
         mContext = context;
         mAppOps = context.getSystemService(AppOpsManager.class);
-        nativeInit(Looper.getMainLooper().getQueue(), this);
     }
 
-    // TODO: Move these into separate process
-    // JNI methods to communicate from FingerprintService to HAL
-    static native int nativeEnroll(byte [] token, int groupId, int timeout);
-    static native long nativePreEnroll();
-    static native int nativeStopEnrollment();
-    static native int nativeAuthenticate(long sessionId, int groupId);
-    static native int nativeStopAuthentication();
-    static native int nativeRemove(int fingerId, int groupId);
-    static native int nativeOpenHal();
-    static native int nativeCloseHal();
-    static native void nativeInit(MessageQueue queue, FingerprintService service);
-    static native long nativeGetAuthenticatorId();
-    static native int nativeSetActiveGroup(int gid, byte[] storePath);
-
-    static final class FpHalMsg {
-        int type; // Type of the message. One of the constants in fingerprint.h
-        int arg1; // optional arguments
-        int arg2;
-        int arg3;
-
-        FpHalMsg(int type, int arg1, int arg2, int arg3) {
-            this.type = type;
-            this.arg1 = arg1;
-            this.arg2 = arg2;
-            this.arg3 = arg3;
-        }
+    @Override
+    public void binderDied() {
+        Slog.v(TAG, "fingerprintd died");
+        mDaemon = null;
     }
 
-    /**
-     * Called from JNI to communicate messages from fingerprint HAL.
-     */
-    void notify(int type, int arg1, int arg2, int arg3) {
-        mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget();
-    }
-
-    void handleNotify(int type, int arg1, int arg2, int arg3) {
-        Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
-                + ", mAuthClients = " + mAuthClient + ", mEnrollClient = " + mEnrollClient);
-        if (mEnrollClient != null) {
-            final IBinder token = mEnrollClient.token;
-            if (dispatchNotify(mEnrollClient, type, arg1, arg2, arg3)) {
-                stopEnrollment(token, false);
-                removeClient(mEnrollClient);
+    public IFingerprintDaemon getFingerprintDaemon() {
+        if (mDaemon == null) {
+            mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));
+            if (mDaemon == null) {
+                Slog.w(TAG, "fingerprind service not available");
+            } else {
+                try {
+                    mDaemon.asBinder().linkToDeath(this, 0);
+                }   catch (RemoteException e) {
+                    Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
+                    mDaemon = null; // try again!
+                }
             }
         }
+        return mDaemon;
+    }
+
+    protected void dispatchEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
+        if (fingerIds.length != groupIds.length) {
+            Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
+                    + fingerIds + ", g[]=" + groupIds);
+            return;
+        }
+        if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
+        // TODO: update fingerprint/name pairs
+    }
+
+    protected void dispatchRemoved(long deviceId, int fingerId, int groupId) {
+        final ClientMonitor client = mRemoveClient;
+        if (fingerId != 0) {
+            ContentResolver res = mContext.getContentResolver();
+            removeTemplateForUser(mRemoveClient, fingerId);
+        }
+        if (client != null && client.sendRemoved(fingerId, groupId)) {
+            removeClient(mRemoveClient);
+        }
+    }
+
+    protected void dispatchError(long deviceId, int error) {
+        if (mEnrollClient != null) {
+            final IBinder token = mEnrollClient.token;
+            if (mEnrollClient.sendError(error)) {
+                stopEnrollment(token, false);
+            }
+        } else if (mAuthClient != null) {
+            final IBinder token = mAuthClient.token;
+            if (mAuthClient.sendError(error)) {
+                stopAuthentication(token, false);
+            }
+        } else if (mRemoveClient != null) {
+            if (mRemoveClient.sendError(error)) removeClient(mRemoveClient);
+        }
+    }
+
+    protected void dispatchAuthenticated(long deviceId, int fingerId, int groupId) {
         if (mAuthClient != null) {
             final IBinder token = mAuthClient.token;
-            if (dispatchNotify(mAuthClient, type, arg1, arg2, arg3)) {
+            if (mAuthClient.sendAuthenticated(fingerId, groupId)) {
                 stopAuthentication(token, false);
                 removeClient(mAuthClient);
             }
         }
-        if (mRemoveClient != null) {
-            if (dispatchNotify(mRemoveClient, type, arg1, arg2, arg3)) {
-                removeClient(mRemoveClient);
+    }
+
+    protected void dispatchAcquired(long deviceId, int acquiredInfo) {
+        if (mEnrollClient != null) {
+            if (mEnrollClient.sendAcquired(acquiredInfo)) {
+                removeClient(mEnrollClient);
+            }
+        } else if (mAuthClient != null) {
+            if (mAuthClient.sendAcquired(acquiredInfo)) {
+                removeClient(mAuthClient);
             }
         }
+
     }
 
     void handleUserSwitching(int userId) {
         updateActiveGroup(userId);
     }
 
-    /*
-     * Dispatch notify events to clients.
-     *
-     * @return true if the operation is done, i.e. authentication completed
-     */
-    boolean dispatchNotify(ClientMonitor clientMonitor, int type, int arg1, int arg2, int arg3) {
-        boolean operationCompleted = false;
-        int fpId;
-        int groupId;
-        int remaining;
-        int acquireInfo;
-        switch (type) {
-            case FINGERPRINT_ERROR:
-                fpId = arg1;
-                operationCompleted = clientMonitor.sendError(fpId);
-                break;
-            case FINGERPRINT_ACQUIRED:
-                acquireInfo = arg1;
-                operationCompleted = clientMonitor.sendAcquired(acquireInfo);
-                break;
-            case FINGERPRINT_AUTHENTICATED:
-                fpId = arg1;
-                groupId = arg2;
-                operationCompleted = clientMonitor.sendAuthenticated(fpId, groupId);
-                break;
-            case FINGERPRINT_TEMPLATE_ENROLLING:
-                fpId = arg1;
-                groupId = arg2;
-                remaining = arg3;
-                operationCompleted = clientMonitor.sendEnrollResult(fpId, groupId, remaining);
+    protected void dispatchEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
+        if (mEnrollClient != null) {
+            if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
                 if (remaining == 0) {
-                    addTemplateForUser(clientMonitor, fpId);
-                    operationCompleted = true; // enroll completed
+                    ContentResolver res = mContext.getContentResolver();
+                    addTemplateForUser(mEnrollClient, fingerId);
+                    removeClient(mEnrollClient);
                 }
-                break;
-            case FINGERPRINT_TEMPLATE_REMOVED:
-                fpId = arg1;
-                groupId = arg2;
-                operationCompleted = clientMonitor.sendRemoved(fpId, groupId);
-                if (fpId != 0) {
-                    removeTemplateForUser(clientMonitor, fpId);
-                }
-                break;
+            }
         }
-        return operationCompleted;
     }
 
-    private void removeClient(ClientMonitor clientMonitor) {
-        if (clientMonitor == null) return;
-        clientMonitor.destroy();
-        if (clientMonitor == mAuthClient) {
+    private void removeClient(ClientMonitor client) {
+        if (client == null) return;
+        client.destroy();
+        if (client == mAuthClient) {
             mAuthClient = null;
-        } else if (clientMonitor == mEnrollClient) {
+        } else if (client == mEnrollClient) {
             mEnrollClient = null;
-        } else if (clientMonitor == mRemoveClient) {
+        } else if (client == mRemoveClient) {
             mRemoveClient = null;
         }
     }
@@ -273,17 +261,36 @@
 
     void startEnrollment(IBinder token, byte[] cryptoToken, int groupId,
             IFingerprintServiceReceiver receiver, int flags) {
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "enroll: no fingeprintd!");
+            return;
+        }
         stopPendingOperations();
         mEnrollClient = new ClientMonitor(token, receiver, groupId);
         final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
-        final int result = nativeEnroll(cryptoToken, groupId, timeout);
-        if (result != 0) {
-            Slog.w(TAG, "startEnroll failed, result=" + result);
+        try {
+            final int result = daemon.enroll(cryptoToken, groupId, timeout);
+            if (result != 0) {
+                Slog.w(TAG, "startEnroll failed, result=" + result);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "startEnroll failed", e);
         }
     }
 
     public long startPreEnroll(IBinder token) {
-        return nativePreEnroll();
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "startPreEnroll: no fingeprintd!");
+            return 0;
+        }
+        try {
+            return daemon.preEnroll();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "startPreEnroll failed", e);
+        }
+        return 0;
     }
 
     private void stopPendingOperations() {
@@ -297,20 +304,34 @@
     }
 
     void stopEnrollment(IBinder token, boolean notify) {
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "stopEnrollment: no fingeprintd!");
+            return;
+        }
         final ClientMonitor client = mEnrollClient;
         if (client == null || client.token != token) return;
-        int result = nativeStopEnrollment();
+        try {
+            int result = daemon.cancelEnrollment();
+            if (result != 0) {
+                Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "stopEnrollment failed", e);
+        }
         if (notify) {
             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
         removeClient(mEnrollClient);
-        if (result != 0) {
-            Slog.w(TAG, "startEnrollCancel failed, result=" + result);
-        }
     }
 
     void startAuthentication(IBinder token, long opId, int groupId,
             IFingerprintServiceReceiver receiver, int flags) {
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "startAuthentication: no fingeprintd!");
+            return;
+        }
         stopPendingOperations();
         mAuthClient = new ClientMonitor(token, receiver, groupId);
         if (inLockoutMode()) {
@@ -322,32 +343,54 @@
             return;
         }
         final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
-        final int result = nativeAuthenticate(opId, groupId);
-        if (result != 0) {
-            Slog.w(TAG, "startAuthentication failed, result=" + result);
+        try {
+            final int result = daemon.authenticate(opId, groupId);
+            if (result != 0) {
+                Slog.w(TAG, "startAuthentication failed, result=" + result);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "startAuthentication failed", e);
         }
     }
 
     void stopAuthentication(IBinder token, boolean notify) {
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "stopAuthentication: no fingeprintd!");
+            return;
+        }
         final ClientMonitor client = mAuthClient;
         if (client == null || client.token != token) return;
-        int result = nativeStopAuthentication();
+        try {
+            int result = daemon.cancelAuthentication();
+            if (result != 0) {
+                Slog.w(TAG, "stopAuthentication failed, result=" + result);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "stopAuthentication failed", e);
+        }
         if (notify) {
             client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
         }
         removeClient(mAuthClient);
-        if (result != 0) {
-            Slog.w(TAG, "stopAuthentication failed, result=" + result);
-        }
     }
 
     void startRemove(IBinder token, int fingerId, int userId,
             IFingerprintServiceReceiver receiver) {
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "startRemove: no fingeprintd!");
+            return;
+        }
         mRemoveClient = new ClientMonitor(token, receiver, userId);
         // The fingerprint template ids will be removed when we get confirmation from the HAL
-        final int result = nativeRemove(fingerId, userId);
-        if (result != 0) {
-            Slog.w(TAG, "startRemove with id = " + fingerId + " failed with result=" + result);
+        try {
+            final int result = daemon.remove(fingerId, userId);
+            if (result != 0) {
+                Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "startRemove failed", e);
         }
     }
 
@@ -364,7 +407,7 @@
                 "Must have " + permission + " permission.");
     }
 
-    private boolean canUserFingerPrint(String opPackageName) {
+    private boolean canUseFingerprint(String opPackageName) {
         checkPermission(USE_FINGERPRINT);
 
         return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(),
@@ -496,15 +539,48 @@
         }
     }
 
-    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+    private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
+
         @Override
+        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
+            dispatchEnrollResult(deviceId, fingerId, groupId, remaining);
+        }
+
+        @Override
+        public void onAcquired(long deviceId, int acquiredInfo) {
+            dispatchAcquired(deviceId, acquiredInfo);
+        }
+
+        @Override
+        public void onAuthenticated(long deviceId, int fingerId, int groupId) {
+            dispatchAuthenticated(deviceId, fingerId, groupId);
+        }
+
+        @Override
+        public void onError(long deviceId, int error) {
+            dispatchError(deviceId, error);
+        }
+
+        @Override
+        public void onRemoved(long deviceId, int fingerId, int groupId) {
+            dispatchRemoved(deviceId, fingerId, groupId);
+        }
+
+        @Override
+        public void onEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
+            dispatchEnumerate(deviceId, fingerIds, groupIds);
+        }
+
+    };
+
+    private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
+        @Override // Binder call
         public long preEnroll(IBinder token) {
             checkPermission(MANAGE_FINGERPRINT);
             return startPreEnroll(token);
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags) {
             checkPermission(MANAGE_FINGERPRINT);
@@ -517,8 +593,7 @@
             });
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public void cancelEnrollment(final IBinder token) {
             checkPermission(MANAGE_FINGERPRINT);
             mHandler.post(new Runnable() {
@@ -529,12 +604,11 @@
             });
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags, String opPackageName) {
             checkPermission(USE_FINGERPRINT);
-            if (!canUserFingerPrint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName)) {
                 return;
             }
             mHandler.post(new Runnable() {
@@ -545,11 +619,9 @@
             });
         }
 
-        @Override
-
-        // Binder call
+        @Override // Binder call
         public void cancelAuthentication(final IBinder token, String opPackageName) {
-            if (!canUserFingerPrint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName)) {
                 return;
             }
             mHandler.post(new Runnable() {
@@ -560,8 +632,7 @@
             });
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public void remove(final IBinder token, final int fingerId, final int groupId,
                 final IFingerprintServiceReceiver receiver) {
             checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
@@ -574,17 +645,15 @@
 
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public boolean isHardwareDetected(long deviceId, String opPackageName) {
-            if (!canUserFingerPrint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName)) {
                 return false;
             }
-            return mHalDeviceId != 0; // TODO
+            return mHalDeviceId != 0;
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public void rename(final int fingerId, final int groupId, final String name) {
             checkPermission(MANAGE_FINGERPRINT);
             mHandler.post(new Runnable() {
@@ -595,69 +664,102 @@
             });
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public List<Fingerprint> getEnrolledFingerprints(int groupId, String opPackageName) {
-            if (!canUserFingerPrint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName)) {
                 return Collections.emptyList();
             }
             return FingerprintService.this.getEnrolledFingerprints(groupId);
         }
 
-        @Override
-        // Binder call
+        @Override // Binder call
         public boolean hasEnrolledFingerprints(int groupId, String opPackageName) {
-            if (!canUserFingerPrint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName)) {
                 return false;
             }
             return FingerprintService.this.hasEnrolledFingerprints(groupId);
         }
 
-        @Override
+        @Override // Binder call
         public long getAuthenticatorId(String opPackageName) {
-            if (!canUserFingerPrint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName)) {
                 return 0;
             }
-            return nativeGetAuthenticatorId();
+            return FingerprintService.this.getAuthenticatorId();
         }
     }
 
     @Override
     public void onStart() {
         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
-        mHalDeviceId = nativeOpenHal();
-        updateActiveGroup(ActivityManager.getCurrentUser());
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon != null) {
+            try {
+                daemon.init(mDaemonCallback);
+                mHalDeviceId = daemon.openHal();
+            	updateActiveGroup(ActivityManager.getCurrentUser());
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to open fingeprintd HAL", e);
+            }
+        }
         if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
         listenForUserSwitches();
     }
 
     private void updateActiveGroup(int userId) {
-        if (mHalDeviceId != 0) {
-            File path = Environment.getUserSystemDirectory(userId);
-            nativeSetActiveGroup(userId, path.getAbsolutePath().getBytes());
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon != null) {
+            try {
+                // TODO: if this is a managed profile, use the profile parent's directory for
+                // storage.
+                final File systemDir = Environment.getUserSystemDirectory(userId);
+                final File fpDir = new File(systemDir, FP_DATA_DIR);
+                if (!fpDir.exists()) {
+                    if (!fpDir.mkdir()) {
+                        Slog.v(TAG, "Cannot make directory: " + fpDir.getAbsolutePath());
+                        return;
+                    }
+                }
+                daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to setActiveGroup():", e);
+            }
         }
     }
 
     private void listenForUserSwitches() {
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
-                    new IUserSwitchObserver.Stub() {
-                        @Override
-                        public void onUserSwitching(int newUserId, IRemoteCallback reply) {
-                            mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
-                                    .sendToTarget();
-                        }
-                        @Override
-                        public void onUserSwitchComplete(int newUserId) throws RemoteException {
-                            // Ignore.
-                        }
-                        @Override
-                        public void onForegroundProfileSwitch(int newProfileId) {
-                            // Ignore.
-                        }
-                    });
+                new IUserSwitchObserver.Stub() {
+                    @Override
+                    public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+                        mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
+                                .sendToTarget();
+                    }
+                    @Override
+                    public void onUserSwitchComplete(int newUserId) throws RemoteException {
+                        // Ignore.
+                    }
+                    @Override
+                    public void onForegroundProfileSwitch(int newProfileId) {
+                        // Ignore.
+                    }
+                });
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to listen for user switching event" ,e);
         }
     }
+
+    public long getAuthenticatorId() {
+        IFingerprintDaemon daemon = getFingerprintDaemon();
+        if (daemon != null) {
+            try {
+                return daemon.getAuthenticatorId();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "getAuthenticatorId failed", e);
+            }
+        }
+        return 0;
+    }
+
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0ecdd61..6a47238 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -369,11 +369,14 @@
     /** Permission grant: grant the permission as an install permission. */
     private static final int GRANT_INSTALL = 2;
 
+    /** Permission grant: grant the permission as an install permission for a legacy app. */
+    private static final int GRANT_INSTALL_LEGACY = 3;
+
     /** Permission grant: grant the permission as a runtime one. */
-    private static final int GRANT_RUNTIME = 3;
+    private static final int GRANT_RUNTIME = 4;
 
     /** Permission grant: grant as runtime a permission that was granted as an install time one. */
-    private static final int GRANT_UPGRADE = 4;
+    private static final int GRANT_UPGRADE = 5;
 
     final ServiceThread mHandlerThread;
 
@@ -3180,6 +3183,12 @@
 
             final PermissionsState permissionsState = sb.getPermissionsState();
 
+            final int flags = permissionsState.getPermissionFlags(name, userId);
+            if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+                throw new SecurityException("Cannot grant system fixed permission: "
+                        + name + " for package: " + packageName);
+            }
+
             final int result = permissionsState.grantRuntimePermission(bp, userId);
             switch (result) {
                 case PermissionsState.PERMISSION_OPERATION_FAILURE: {
@@ -3237,6 +3246,12 @@
 
             final PermissionsState permissionsState = sb.getPermissionsState();
 
+            final int flags = permissionsState.getPermissionFlags(name, userId);
+            if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
+                throw new SecurityException("Cannot revoke system fixed permission: "
+                        + name + " for package: " + packageName);
+            }
+
             if (permissionsState.revokeRuntimePermission(bp, userId) ==
                     PermissionsState.PERMISSION_OPERATION_FAILURE) {
                 return;
@@ -4133,6 +4148,7 @@
 
         final int userId = UserHandle.getCallingUserId();
         ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
         ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
@@ -4155,27 +4171,22 @@
                     // Try to get the status from User settings first
                     int status = getDomainVerificationStatusLPr(ps, userId);
                     if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
-                        result.add(info);
+                        alwaysList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
                         neverList.add(info);
-                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED ||
+                            status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) {
                         undefinedList.add(info);
                     }
                 }
             }
-            // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
-            result.addAll(undefinedList);
-            // If there is nothing selected, add all candidates and remove the ones that the User
-            // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state and
-            // also remove Browser Apps ones.
-            // If there is still none after this pass, add all Browser Apps and
-            // let the User decide with the Disambiguation dialog if there are several ones.
-            if (result.size() == 0) {
-                result.addAll(candidates);
-            }
-            result.removeAll(neverList);
-            result.removeAll(matchAllList);
-            if (result.size() == 0) {
+            // First try to add the "always" if there is any
+            if (alwaysList.size() > 0) {
+                result.addAll(alwaysList);
+            } else {
+                // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
+                result.addAll(undefinedList);
+                // Also add Browsers (all of them or only the default one)
                 if ((flags & MATCH_ALL) != 0) {
                     result.addAll(matchAllList);
                 } else {
@@ -4200,6 +4211,13 @@
                         result.addAll(matchAllList);
                     }
                 }
+
+                // If there is nothing selected, add all candidates and remove the ones that the User
+                // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state
+                if (result.size() == 0) {
+                    result.addAll(candidates);
+                    result.removeAll(neverList);
+                }
             }
         }
         if (DEBUG_PREFERRED) {
@@ -6338,12 +6356,14 @@
                 // to scan the package again.
                 deriveNonSystemPackageAbi(pkg, scanFile, cpuAbiOverride, false /* extract libs */);
                 if (!TextUtils.equals(oldPrimaryCpuAbi, pkg.applicationInfo.primaryCpuAbi)) {
-                    throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " ("
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "unexpected abi change for " + pkg.packageName + " ("
                             + oldPrimaryCpuAbi + "-> " + pkg.applicationInfo.primaryCpuAbi);
                 }
 
                 if (!TextUtils.equals(oldSecondaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi)) {
-                    throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " ("
+                    throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                            "unexpected abi change for " + pkg.packageName + " ("
                             + oldSecondaryCpuAbi + "-> " + pkg.applicationInfo.secondaryCpuAbi);
                 }
             }
@@ -7738,7 +7758,7 @@
                 case PermissionInfo.PROTECTION_DANGEROUS: {
                     if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
                         // For legacy apps dangerous permissions are install time ones.
-                        grant = GRANT_INSTALL;
+                        grant = GRANT_INSTALL_LEGACY;
                     } else if (ps.isSystem()) {
                         final int[] updatedUserIds = ps.getPermissionsUpdatedForUserIds();
                         if (origPermissions.hasInstallPermission(bp.name)) {
@@ -7798,6 +7818,28 @@
 
                 switch (grant) {
                     case GRANT_INSTALL: {
+                        // Revoke this as runtime permission to handle the case of
+                        // a runtime permssion being downgraded to an install one.
+                        for (int userId : UserManagerService.getInstance().getUserIds()) {
+                            if (origPermissions.getRuntimePermissionState(
+                                    bp.name, userId) != null) {
+                                // Revoke the runtime permission and clear the flags.
+                                origPermissions.revokeRuntimePermission(bp, userId);
+                                origPermissions.updatePermissionFlags(bp, userId,
+                                      PackageManager.MASK_PERMISSION_FLAGS, 0);
+                                // If we revoked a permission permission, we have to write.
+                                changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+                                        changedRuntimePermissionUserIds, userId);
+                            }
+                        }
+                        // Grant an install permission.
+                        if (permissionsState.grantInstallPermission(bp) !=
+                                PermissionsState.PERMISSION_OPERATION_FAILURE) {
+                            changedInstallPermission = true;
+                        }
+                    } break;
+
+                    case GRANT_INSTALL_LEGACY: {
                         // Grant an install permission.
                         if (permissionsState.grantInstallPermission(bp) !=
                                 PermissionsState.PERMISSION_OPERATION_FAILURE) {
@@ -11621,7 +11663,7 @@
                         true /* extract libs */);
             } catch (PackageManagerException pme) {
                 Slog.e(TAG, "Error deriving application ABI", pme);
-                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error ");
+                res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
                 return;
             }
 
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 8942325..ad662be 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -381,10 +381,10 @@
      *
      * @return The gids for all device users.
      */
-    public int[] computeGids() {
+    public int[] computeGids(int[] userIds) {
         int[] gids = mGlobalGids;
 
-        for (int userId : UserManagerService.getInstance().getUserIds()) {
+        for (int userId : userIds) {
             final int[] userGids = computeGids(userId);
             gids = appendInts(gids, userGids);
         }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 76ef19f..d2a135c 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2022,83 +2022,8 @@
                     |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
                     -1, -1);
 
-            // Write package list file now, use a JournaledFile.
-            File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp");
-            JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
-
-            final File writeTarget = journal.chooseForWrite();
-            fstr = new FileOutputStream(writeTarget);
-            str = new BufferedOutputStream(fstr);
-            try {
-                FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
-
-                StringBuilder sb = new StringBuilder();
-                for (final PackageSetting pkg : mPackages.values()) {
-                    if (pkg.pkg == null || pkg.pkg.applicationInfo == null) {
-                        Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
-                        continue;
-                    }
-
-                    final ApplicationInfo ai = pkg.pkg.applicationInfo;
-                    final String dataPath = ai.dataDir;
-                    final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-                    final int[] gids = pkg.getPermissionsState().computeGids();
-
-                    // Avoid any application that has a space in its path.
-                    if (dataPath.indexOf(" ") >= 0)
-                        continue;
-
-                    // we store on each line the following information for now:
-                    //
-                    // pkgName    - package name
-                    // userId     - application-specific user id
-                    // debugFlag  - 0 or 1 if the package is debuggable.
-                    // dataPath   - path to package's data path
-                    // seinfo     - seinfo label for the app (assigned at install time)
-                    // gids       - supplementary gids this app launches with
-                    //
-                    // NOTE: We prefer not to expose all ApplicationInfo flags for now.
-                    //
-                    // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
-                    // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
-                    //   system/core/logd/LogStatistics.cpp
-                    //   system/core/run-as/run-as.c
-                    //   system/core/sdcard/sdcard.c
-                    //   external/libselinux/src/android.c:package_info_init()
-                    //
-                    sb.setLength(0);
-                    sb.append(ai.packageName);
-                    sb.append(" ");
-                    sb.append((int)ai.uid);
-                    sb.append(isDebug ? " 1 " : " 0 ");
-                    sb.append(dataPath);
-                    sb.append(" ");
-                    sb.append(ai.seinfo);
-                    sb.append(" ");
-                    if (gids != null && gids.length > 0) {
-                        sb.append(gids[0]);
-                        for (int i = 1; i < gids.length; i++) {
-                            sb.append(",");
-                            sb.append(gids[i]);
-                        }
-                    } else {
-                        sb.append("none");
-                    }
-                    sb.append("\n");
-                    str.write(sb.toString().getBytes());
-                }
-                str.flush();
-                FileUtils.sync(fstr);
-                str.close();
-                journal.commit();
-            } catch (Exception e) {
-                Slog.wtf(TAG, "Failed to write packages.list", e);
-                IoUtils.closeQuietly(str);
-                journal.rollback();
-            }
-
+            writePackageListLPr();
             writeAllUsersPackageRestrictionsLPr();
-
             writeAllRuntimePermissionsLPr();
             return;
 
@@ -2119,6 +2044,99 @@
         //Debug.stopMethodTracing();
     }
 
+    void writePackageListLPr() {
+        writePackageListLPr(-1);
+    }
+
+    void writePackageListLPr(int creatingUserId) {
+        // Only derive GIDs for active users (not dying)
+        final List<UserInfo> users = UserManagerService.getInstance().getUsers(true);
+        int[] userIds = new int[users.size()];
+        for (int i = 0; i < userIds.length; i++) {
+            userIds[i] = users.get(i).id;
+        }
+        if (creatingUserId != -1) {
+            userIds = ArrayUtils.appendInt(userIds, creatingUserId);
+        }
+
+        // Write package list file now, use a JournaledFile.
+        File tempFile = new File(mPackageListFilename.getAbsolutePath() + ".tmp");
+        JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
+
+        final File writeTarget = journal.chooseForWrite();
+        FileOutputStream fstr = null;
+        BufferedOutputStream str = null;
+        try {
+            fstr = new FileOutputStream(writeTarget);
+            str = new BufferedOutputStream(fstr);
+            FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+
+            StringBuilder sb = new StringBuilder();
+            for (final PackageSetting pkg : mPackages.values()) {
+                if (pkg.pkg == null || pkg.pkg.applicationInfo == null) {
+                    Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+                    continue;
+                }
+
+                final ApplicationInfo ai = pkg.pkg.applicationInfo;
+                final String dataPath = ai.dataDir;
+                final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                final int[] gids = pkg.getPermissionsState().computeGids(userIds);
+
+                // Avoid any application that has a space in its path.
+                if (dataPath.indexOf(" ") >= 0)
+                    continue;
+
+                // we store on each line the following information for now:
+                //
+                // pkgName    - package name
+                // userId     - application-specific user id
+                // debugFlag  - 0 or 1 if the package is debuggable.
+                // dataPath   - path to package's data path
+                // seinfo     - seinfo label for the app (assigned at install time)
+                // gids       - supplementary gids this app launches with
+                //
+                // NOTE: We prefer not to expose all ApplicationInfo flags for now.
+                //
+                // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
+                // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
+                //   system/core/logd/LogStatistics.cpp
+                //   system/core/run-as/run-as.c
+                //   system/core/sdcard/sdcard.c
+                //   external/libselinux/src/android.c:package_info_init()
+                //
+                sb.setLength(0);
+                sb.append(ai.packageName);
+                sb.append(" ");
+                sb.append((int)ai.uid);
+                sb.append(isDebug ? " 1 " : " 0 ");
+                sb.append(dataPath);
+                sb.append(" ");
+                sb.append(ai.seinfo);
+                sb.append(" ");
+                if (gids != null && gids.length > 0) {
+                    sb.append(gids[0]);
+                    for (int i = 1; i < gids.length; i++) {
+                        sb.append(",");
+                        sb.append(gids[i]);
+                    }
+                } else {
+                    sb.append("none");
+                }
+                sb.append("\n");
+                str.write(sb.toString().getBytes());
+            }
+            str.flush();
+            FileUtils.sync(fstr);
+            str.close();
+            journal.commit();
+        } catch (Exception e) {
+            Slog.wtf(TAG, "Failed to write packages.list", e);
+            IoUtils.closeQuietly(str);
+            journal.rollback();
+        }
+    }
+
     void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
             throws java.io.IOException {
         serializer.startTag(null, "updated-package");
@@ -3491,6 +3509,7 @@
         }
         readDefaultPreferredAppsLPw(service, userHandle);
         writePackageRestrictionsLPr(userHandle);
+        writePackageListLPr(userHandle);
     }
 
     void removeUserLPw(int userId) {
@@ -3506,6 +3525,8 @@
         removeCrossProfileIntentFiltersLPw(userId);
 
         mRuntimePermissionsPersistence.onUserRemoved(userId);
+
+        writePackageListLPr();
     }
 
     void removeCrossProfileIntentFiltersLPw(int userId) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index a4e9c68..9bb5e40 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -51,7 +51,6 @@
 import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.media.session.MediaSessionLegacyHelper;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.FactoryTest;
@@ -97,7 +96,6 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewRootImpl;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -458,7 +456,7 @@
     // menu needs to be displayed.
     boolean mLastFocusNeedsMenu = false;
 
-    FakeWindow mHideNavFakeWindow = null;
+    InputConsumer mInputConsumer = null;
 
     static final Rect mTmpParentFrame = new Rect();
     static final Rect mTmpDisplayFrame = new Rect();
@@ -1817,7 +1815,7 @@
             case TYPE_APPLICATION_STARTING:
             case TYPE_BOOT_PROGRESS:
             case TYPE_DISPLAY_OVERLAY:
-            case TYPE_HIDDEN_NAV_CONSUMER:
+            case TYPE_INPUT_CONSUMER:
             case TYPE_KEYGUARD_SCRIM:
             case TYPE_KEYGUARD_DIALOG:
             case TYPE_MAGNIFICATION_OVERLAY:
@@ -1942,75 +1940,75 @@
         case TYPE_VOICE_INTERACTION:
             // voice interaction layer is almost immediately above apps.
             return 5;
-        case TYPE_SYSTEM_DIALOG:
+        case TYPE_INPUT_CONSUMER:
             return 6;
+        case TYPE_SYSTEM_DIALOG:
+            return 7;
         case TYPE_TOAST:
             // toasts and the plugged-in battery thing
-            return 7;
+            return 8;
         case TYPE_PRIORITY_PHONE:
             // SIM errors and unlock.  Not sure if this really should be in a high layer.
-            return 8;
+            return 9;
         case TYPE_DREAM:
             // used for Dreams (screensavers with TYPE_DREAM windows)
-            return 9;
+            return 10;
         case TYPE_SYSTEM_ALERT:
             // like the ANR / app crashed dialogs
-            return 10;
+            return 11;
         case TYPE_INPUT_METHOD:
             // on-screen keyboards and other such input method user interfaces go here.
-            return 11;
+            return 12;
         case TYPE_INPUT_METHOD_DIALOG:
             // on-screen keyboards and other such input method user interfaces go here.
-            return 12;
+            return 13;
         case TYPE_KEYGUARD_SCRIM:
             // the safety window that shows behind keyguard while keyguard is starting
-            return 13;
-        case TYPE_STATUS_BAR_SUB_PANEL:
             return 14;
-        case TYPE_STATUS_BAR:
+        case TYPE_STATUS_BAR_SUB_PANEL:
             return 15;
-        case TYPE_STATUS_BAR_PANEL:
+        case TYPE_STATUS_BAR:
             return 16;
-        case TYPE_KEYGUARD_DIALOG:
+        case TYPE_STATUS_BAR_PANEL:
             return 17;
+        case TYPE_KEYGUARD_DIALOG:
+            return 18;
         case TYPE_VOLUME_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 18;
+            return 19;
         case TYPE_SYSTEM_OVERLAY:
             // the on-screen volume indicator and controller shown when the user
             // changes the device volume
-            return 19;
+            return 20;
         case TYPE_NAVIGATION_BAR:
             // the navigation bar, if available, shows atop most things
-            return 20;
+            return 21;
         case TYPE_NAVIGATION_BAR_PANEL:
             // some panels (e.g. search) need to show on top of the navigation bar
-            return 21;
+            return 22;
         case TYPE_SYSTEM_ERROR:
             // system-level error dialogs
-            return 22;
+            return 23;
         case TYPE_MAGNIFICATION_OVERLAY:
             // used to highlight the magnified portion of a display
-            return 23;
+            return 24;
         case TYPE_DISPLAY_OVERLAY:
             // used to simulate secondary display devices
-            return 24;
+            return 25;
         case TYPE_DRAG:
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
-            return 25;
+            return 26;
         case TYPE_ACCESSIBILITY_OVERLAY:
             // overlay put by accessibility services to intercept user interaction
-            return 26;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 27;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 28;
+        case TYPE_BOOT_PROGRESS:
+            return 29;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 29;
-        case TYPE_HIDDEN_NAV_CONSUMER:
             return 30;
         }
         Log.e(TAG, "Unknown window type: " + type);
@@ -3385,15 +3383,13 @@
             // detect when the user presses anywhere to bring back the nav
             // bar and ensure the application doesn't see the event.
             if (navVisible || navAllowedHidden) {
-                if (mHideNavFakeWindow != null) {
-                    mHideNavFakeWindow.dismiss();
-                    mHideNavFakeWindow = null;
+                if (mInputConsumer != null) {
+                    mInputConsumer.dismiss();
+                    mInputConsumer = null;
                 }
-            } else if (mHideNavFakeWindow == null) {
-                mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
-                        mHandler.getLooper(), mHideNavInputEventReceiverFactory,
-                        "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 0,
-                        0, false, false, true);
+            } else if (mInputConsumer == null) {
+                mInputConsumer = mWindowManagerFuncs.addInputConsumer(mHandler.getLooper(),
+                        mHideNavInputEventReceiverFactory);
             }
 
             // For purposes of positioning and showing the nav bar, if we have
@@ -6311,7 +6307,8 @@
         vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis);
 
         // prevent status bar interaction from clearing certain flags
-        boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR;
+        int type = win.getAttrs().type;
+        boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
         if (statusBarHasFocus && !isStatusBarKeyguard()) {
             int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
@@ -6323,6 +6320,11 @@
             }
             vis = (vis & ~flags) | (oldVis & flags);
         }
+        if (windowTypeToLayerLw(type) > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) {
+            // We can't get into fullscreen from this window otherwise the consumer would not get
+            // the input events.
+            vis = (vis & ~View.SYSTEM_UI_FLAG_FULLSCREEN);
+        }
 
         if (!areTranslucentBarsAllowed() && transWin != mStatusBar) {
             vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 482ae24..66ae9ef 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1248,7 +1248,7 @@
                     && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
                     && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_DRAG
-                    && windowType != WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER
+                    && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
                     && windowType != WindowManager.LayoutParams.TYPE_POINTER
                     && windowType != WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY
                     && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
diff --git a/services/core/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
similarity index 77%
rename from services/core/java/com/android/server/wm/FakeWindowImpl.java
rename to services/core/java/com/android/server/wm/InputConsumerImpl.java
index 1136ced..0581a16 100644
--- a/services/core/java/com/android/server/wm/FakeWindowImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,17 +16,18 @@
 
 package com.android.server.wm;
 
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.input.InputWindowHandle;
-
 import android.os.Looper;
 import android.os.Process;
 import android.view.Display;
 import android.view.InputChannel;
 import android.view.InputEventReceiver;
+import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 
-public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow {
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputWindowHandle;
+
+public final class InputConsumerImpl implements WindowManagerPolicy.InputConsumer {
     final WindowManagerService mService;
     final InputChannel mServerChannel, mClientChannel;
     final InputApplicationHandle mApplicationHandle;
@@ -34,12 +35,9 @@
     final InputEventReceiver mInputEventReceiver;
     final int mWindowLayer;
 
-    boolean mTouchFullscreen;
-
-    public FakeWindowImpl(WindowManagerService service,
-            Looper looper, InputEventReceiver.Factory inputEventReceiverFactory,
-            String name, int windowType, int layoutParamsFlags,
-            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) {
+    public InputConsumerImpl(WindowManagerService service, Looper looper,
+            InputEventReceiver.Factory inputEventReceiverFactory) {
+        String name = "input consumer";
         mService = service;
 
         InputChannel[] channels = InputChannel.openInputChannelPair(name);
@@ -58,31 +56,25 @@
         mWindowHandle = new InputWindowHandle(mApplicationHandle, null, Display.DEFAULT_DISPLAY);
         mWindowHandle.name = name;
         mWindowHandle.inputChannel = mServerChannel;
-        mWindowLayer = getLayerLw(windowType);
+        mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+        mWindowLayer = getLayerLw(mWindowHandle.layoutParamsType);
         mWindowHandle.layer = mWindowLayer;
-        mWindowHandle.layoutParamsFlags = layoutParamsFlags;
-        mWindowHandle.layoutParamsType = windowType;
+        mWindowHandle.layoutParamsFlags = 0;
         mWindowHandle.dispatchingTimeoutNanos =
                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
         mWindowHandle.visible = true;
-        mWindowHandle.canReceiveKeys = canReceiveKeys;
-        mWindowHandle.hasFocus = hasFocus;
+        mWindowHandle.canReceiveKeys = false;
+        mWindowHandle.hasFocus = false;
         mWindowHandle.hasWallpaper = false;
         mWindowHandle.paused = false;
         mWindowHandle.ownerPid = Process.myPid();
         mWindowHandle.ownerUid = Process.myUid();
         mWindowHandle.inputFeatures = 0;
         mWindowHandle.scaleFactor = 1.0f;
-
-        mTouchFullscreen = touchFullscreen;
     }
 
     void layout(int dw, int dh) {
-        if (mTouchFullscreen) {
-            mWindowHandle.touchableRegion.set(0, 0, dw, dh);
-        } else {
-            mWindowHandle.touchableRegion.setEmpty();
-        }
+        mWindowHandle.touchableRegion.set(0, 0, dw, dh);
         mWindowHandle.frameLeft = 0;
         mWindowHandle.frameTop = 0;
         mWindowHandle.frameRight = dw;
@@ -92,7 +84,7 @@
     @Override
     public void dismiss() {
         synchronized (mService.mWindowMap) {
-            if (mService.removeFakeWindowLocked(this)) {
+            if (mService.removeInputConsumer()) {
                 mInputEventReceiver.dispose();
                 mService.mInputManager.unregisterInputChannel(mServerChannel);
                 mClientChannel.dispose();
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index c24fcb3..ae442e5 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,10 +16,6 @@
 
 package com.android.server.wm;
 
-import com.android.server.input.InputManagerService;
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.input.InputWindowHandle;
-
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -30,17 +26,21 @@
 import android.view.KeyEvent;
 import android.view.WindowManager;
 
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputManagerService;
+import com.android.server.input.InputWindowHandle;
+
 import java.util.Arrays;
 
 final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
     private final WindowManagerService mService;
-    
+
     // Current window with input focus for keys and other non-touch events.  May be null.
     private WindowState mInputFocus;
-    
+
     // When true, prevents input dispatch from proceeding until set to false again.
     private boolean mInputDispatchFrozen;
-    
+
     // When true, input dispatch proceeds normally.  Otherwise all events are dropped.
     // Initially false, so that input does not get dispatched until boot is finished at
     // which point the ActivityManager will enable dispatching.
@@ -256,10 +256,7 @@
             }
         }
 
-        final int NFW = mService.mFakeWindows.size();
-        for (int i = 0; i < NFW; i++) {
-            addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle);
-        }
+        boolean addInputConsumerHandle = mService.mInputConsumer != null;
 
         // Add all windows on the default display.
         final int numDisplays = mService.mDisplayContents.size();
@@ -273,6 +270,11 @@
                     // Skip this window because it cannot possibly receive input.
                     continue;
                 }
+                if (addInputConsumerHandle
+                        && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) {
+                    addInputWindowHandleLw(mService.mInputConsumer.mWindowHandle);
+                    addInputConsumerHandle = false;
+                }
 
                 final int flags = child.mAttrs.flags;
                 final int privateFlags = child.mAttrs.privateFlags;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b84b506..cebb909 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -108,7 +108,6 @@
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerInternal;
 import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.FakeWindow;
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -382,10 +381,10 @@
     final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
 
     /**
-     * Fake windows added to the window manager.  Note: ordered from top to
-     * bottom, opposite of mWindows.
+     * The input consumer added to the window manager which consumes input events to windows below
+     * it.
      */
-    final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<>();
+    InputConsumerImpl mInputConsumer;
 
     /**
      * Windows that are being resized.  Used so we can tell the client about
@@ -3187,10 +3186,13 @@
                     }
                 }
                 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
-                    // To change the format, we need to re-build the surface.
-                    winAnimator.destroySurfaceLocked();
-                    toBeDisplayed = true;
-                    surfaceChanged = true;
+                    // If the format can be changed in place yaay!
+                    // If not, fall back to a surface re-build
+                    if (!winAnimator.tryChangeFormatInPlaceLocked()) {
+                        winAnimator.destroySurfaceLocked();
+                        toBeDisplayed = true;
+                        surfaceChanged = true;
+                    }
                 }
                 try {
                     if (!win.mHasSurface) {
@@ -8963,9 +8965,8 @@
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
 
-        final int NFW = mFakeWindows.size();
-        for (int i=0; i<NFW; i++) {
-            mFakeWindows.get(i).layout(dw, dh);
+        if (mInputConsumer != null) {
+            mInputConsumer.layout(dw, dh);
         }
 
         final int N = windows.size();
@@ -10992,28 +10993,19 @@
     }
 
     @Override
-    public FakeWindow addFakeWindow(Looper looper,
-            InputEventReceiver.Factory inputEventReceiverFactory,
-            String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags,
-            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) {
+    public InputConsumerImpl addInputConsumer(Looper looper,
+            InputEventReceiver.Factory inputEventReceiverFactory) {
         synchronized (mWindowMap) {
-            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
-                    name, windowType, layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
-            int i=0;
-            while (i<mFakeWindows.size()) {
-                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
-                    break;
-                }
-            }
-            mFakeWindows.add(i, fw);
+            mInputConsumer = new InputConsumerImpl(this, looper, inputEventReceiverFactory);
             mInputMonitor.updateInputWindowsLw(true);
-            return fw;
+            return mInputConsumer;
         }
     }
 
-    boolean removeFakeWindowLocked(FakeWindow window) {
+    boolean removeInputConsumer() {
         synchronized (mWindowMap) {
-            if (mFakeWindows.remove(window)) {
+            if (mInputConsumer != null) {
+                mInputConsumer = null;
                 mInputMonitor.updateInputWindowsLw(true);
                 return true;
             }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 424e2e2..e9023fd 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -146,6 +146,9 @@
 
     boolean mKeyguardGoingAwayAnimation;
 
+    /** The pixel format of the underlying SurfaceControl */
+    int mSurfaceFormat;
+
     /** This is set when there is no Surface */
     static final int NO_SURFACE = 0;
     /** This is set after the Surface has been created but before the window has been drawn. During
@@ -845,6 +848,7 @@
                     flags |= SurfaceControl.OPAQUE;
                 }
 
+                mSurfaceFormat = format;
                 if (DEBUG_SURFACE_TRACE) {
                     mSurfaceControl = new SurfaceTrace(
                             mSession.mSurfaceSession,
@@ -1610,6 +1614,28 @@
         }
     }
 
+    /**
+     * Try to change the pixel format without recreating the surface. This
+     * will be common in the case of changing from PixelFormat.OPAQUE to
+     * PixelFormat.TRANSLUCENT in the hardware-accelerated case as both
+     * requested formats resolve to the same underlying SurfaceControl format
+     * @return True if format was succesfully changed, false otherwise
+     */
+    boolean tryChangeFormatInPlaceLocked() {
+        if (mSurfaceControl == null) {
+            return false;
+        }
+        final LayoutParams attrs = mWin.getAttrs();
+        final boolean isHwAccelerated = (attrs.flags &
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+        final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+        if (format == mSurfaceFormat) {
+            setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
+            return true;
+        }
+        return false;
+    }
+
     void setOpaqueLocked(boolean isOpaque) {
         if (mSurfaceControl == null) {
             return;
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index a5546cf..9556b08 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -10,7 +10,6 @@
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_fingerprint_FingerprintService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 7db7414..67872da 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,7 +41,6 @@
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
 int register_android_server_PersistentDataBlockService(JNIEnv* env);
-int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
 int register_android_server_Watchdog(JNIEnv* env);
 };
 
@@ -79,7 +78,6 @@
     register_android_server_hdmi_HdmiCecController(env);
     register_android_server_tv_TvInputHal(env);
     register_android_server_PersistentDataBlockService(env);
-    register_android_server_fingerprint_FingerprintService(env);
     register_android_server_Watchdog(env);
 
     return JNI_VERSION_1_4;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9ad7e11..a9e76d8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -6392,25 +6392,34 @@
     }
 
     @Override
-    public boolean setPermissionGranted(ComponentName admin, String packageName,
-            String permission, boolean granted) throws RemoteException {
+    public boolean setPermissionGrantState(ComponentName admin, String packageName,
+            String permission, int grantState) throws RemoteException {
         UserHandle user = Binder.getCallingUserHandle();
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             long ident = Binder.clearCallingIdentity();
             try {
                 PackageManager packageManager = mContext.getPackageManager();
-                if (granted) {
-                    packageManager.grantRuntimePermission(packageName, permission, user);
-                    packageManager.updatePermissionFlags(permission, packageName,
-                            PackageManager.FLAG_PERMISSION_POLICY_FIXED,
-                            PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
-                } else {
-                    packageManager.revokeRuntimePermission(packageName,
-                            permission, user);
-                    packageManager.updatePermissionFlags(permission, packageName,
-                            PackageManager.FLAG_PERMISSION_POLICY_FIXED,
-                            PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
+                switch (grantState) {
+                    case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
+                        packageManager.grantRuntimePermission(packageName, permission, user);
+                        packageManager.updatePermissionFlags(permission, packageName,
+                                PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+                                PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
+                    } break;
+
+                    case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: {
+                        packageManager.revokeRuntimePermission(packageName,
+                                permission, user);
+                        packageManager.updatePermissionFlags(permission, packageName,
+                                PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+                                PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
+                    } break;
+
+                    case DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT: {
+                        packageManager.updatePermissionFlags(permission, packageName,
+                                PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, user);
+                    } break;
                 }
                 return true;
             } catch (SecurityException se) {
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index d6ff475..a615675 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -131,6 +131,11 @@
         usageStats.mBeginIdleTime = timeStamp;
     }
 
+    void updateLastUsedTime(String packageName, long lastUsedTime) {
+        UsageStats usageStats = getOrCreateUsageStats(packageName);
+        usageStats.mLastTimeUsed = lastUsedTime;
+    }
+
     void updateConfigurationStats(Configuration config, long timeStamp) {
         if (activeConfiguration != null) {
             ConfigurationStats activeStats = configurations.get(activeConfiguration);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f7bcf2a..ff3bb28 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -99,7 +99,9 @@
     private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
 
     static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 4
-            : 1L * 24 * 60 * ONE_MINUTE; // 1 day
+            : 12 * 60 * ONE_MINUTE; // 12 hours of screen-on time sans dream-time
+    static final long DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS = DEBUG ? ONE_MINUTE * 8
+            : 2L * 24 * 60 * ONE_MINUTE; // 2 days
     static final long DEFAULT_CHECK_IDLE_INTERVAL = DEBUG ? ONE_MINUTE
             : 8 * 60 * ONE_MINUTE; // 8 hours
     static final long DEFAULT_PAROLE_INTERVAL = DEBUG ? ONE_MINUTE * 10
@@ -356,7 +358,7 @@
                 final int packageCount = packages.size();
                 for (int p = 0; p < packageCount; p++) {
                     final String packageName = packages.get(p).packageName;
-                    final boolean isIdle = isAppIdleFiltered(packageName, userId);
+                    final boolean isIdle = isAppIdleFiltered(packageName, userId, timeNow);
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
                             userId, isIdle ? 1 : 0, packageName));
                     mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
@@ -386,7 +388,8 @@
 
     void updateDisplayLocked() {
         boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
-                != Display.STATE_OFF;
+                == Display.STATE_ON;
+
         if (screenOn == mScreenOn) return;
 
         mScreenOn = screenOn;
@@ -533,14 +536,16 @@
     void reportEvent(UsageEvents.Event event, int userId) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
+            final long screenOnTime = getScreenOnTimeLocked(timeNow);
             convertToSystemTimeLocked(event);
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            final long lastUsed = service.getBeginIdleTime(event.mPackage);
-            final long screenOnTime = getScreenOnTimeLocked(timeNow);
-            final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed, screenOnTime);
-            service.reportEvent(event, screenOnTime);
+            final long beginIdleTime = service.getBeginIdleTime(event.mPackage);
+            final long lastUsedTime = service.getLastUsedTime(event.mPackage);
+            final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
+                    lastUsedTime, screenOnTime, timeNow);
+            service.reportEvent(event, getScreenOnTimeLocked(timeNow));
             // Inform listeners if necessary
             if ((event.mEventType == Event.MOVE_TO_FOREGROUND
                     || event.mEventType == Event.MOVE_TO_BACKGROUND
@@ -556,8 +561,9 @@
     }
 
     /**
-     * Forces the app's beginIdleTime to reflect idle or active. If idle, then it rolls back the
-     * beginIdleTime to a point in time thats behind the threshold for idle.
+     * Forces the app's beginIdleTime and lastUsedTime to reflect idle or active. If idle,
+     * then it rolls back the beginIdleTime and lastUsedTime to a point in time that's behind
+     * the threshold for idle.
      */
     void forceIdleState(String packageName, int userId, boolean idle) {
         synchronized (mLock) {
@@ -567,10 +573,13 @@
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
-            final long lastUsed = service.getBeginIdleTime(packageName);
-            final boolean previouslyIdle = hasPassedIdleTimeout(lastUsed,
-                    getScreenOnTimeLocked(timeNow));
+            final long beginIdleTime = service.getBeginIdleTime(packageName);
+            final long lastUsedTime = service.getLastUsedTime(packageName);
+            final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
+                    lastUsedTime, screenOnTime, timeNow);
             service.setBeginIdleTime(packageName, deviceUsageTime);
+            service.setLastUsedTime(packageName,
+                    timeNow - (idle ? DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS : 0) - 5000);
             // Inform listeners if necessary
             if (previouslyIdle != idle) {
                 // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
@@ -650,13 +659,14 @@
         }
     }
 
-    private boolean isAppIdleUnfiltered(String packageName, int userId) {
+    private boolean isAppIdleUnfiltered(String packageName, int userId, long timeNow) {
         synchronized (mLock) {
-            final long timeNow = checkAndGetTimeLocked();
+            final long screenOnTime = getScreenOnTimeLocked(timeNow);
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
             long beginIdleTime = service.getBeginIdleTime(packageName);
-            return hasPassedIdleTimeout(beginIdleTime, getScreenOnTimeLocked(timeNow));
+            long lastUsedTime = service.getLastUsedTime(packageName);
+            return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime, timeNow);
         }
     }
 
@@ -665,8 +675,10 @@
      * @param currentTime current time in device usage timebase
      * @return whether it's been used far enough in the past to be considered inactive
      */
-    boolean hasPassedIdleTimeout(long timestamp, long currentTime) {
-        return timestamp <= currentTime - mAppIdleDurationMillis;
+    boolean hasPassedIdleTimeoutLocked(long beginIdleTime, long lastUsedTime,
+            long screenOnTime, long currentTime) {
+        return (beginIdleTime <= screenOnTime - mAppIdleDurationMillis)
+                && (lastUsedTime <= currentTime - DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS);
     }
 
     void addListener(AppIdleStateChangeListener listener) {
@@ -689,9 +701,12 @@
      * This happens if the device is plugged in or temporarily allowed to make exceptions.
      * Called by interface impls.
      */
-    boolean isAppIdleFiltered(String packageName, int userId) {
+    boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
         if (packageName == null) return false;
         synchronized (mLock) {
+            if (timeNow == -1) {
+                timeNow = checkAndGetTimeLocked();
+            }
             // Temporary exemption, probably due to device charging or occasional allowance to
             // be allowed to sync, etc.
             if (mAppIdleParoled) {
@@ -715,7 +730,7 @@
             return false;
         }
 
-        return isAppIdleUnfiltered(packageName, userId);
+        return isAppIdleUnfiltered(packageName, userId, timeNow);
     }
 
     void setAppIdle(String packageName, boolean idle, int userId) {
@@ -948,7 +963,7 @@
             }
             final long token = Binder.clearCallingIdentity();
             try {
-                return UsageStatsService.this.isAppIdleFiltered(packageName, userId);
+                return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1053,7 +1068,7 @@
 
         @Override
         public boolean isAppIdle(String packageName, int userId) {
-            return UsageStatsService.this.isAppIdleFiltered(packageName, userId);
+            return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
         }
 
         @Override
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b7e1c22..7c00dae 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -216,12 +216,19 @@
     }
 
     /**
-     * Sets the last timestamp for each of the intervals.
-     * @param lastTimestamp
+     * Sets the beginIdleTime for each of the intervals.
+     * @param beginIdleTime
      */
-    void setBeginIdleTime(String packageName, long deviceUsageTime) {
+    void setBeginIdleTime(String packageName, long beginIdleTime) {
         for (IntervalStats stats : mCurrentStats) {
-            stats.updateBeginIdleTime(packageName, deviceUsageTime);
+            stats.updateBeginIdleTime(packageName, beginIdleTime);
+        }
+        notifyStatsChanged();
+    }
+
+    void setLastUsedTime(String packageName, long lastUsedTime) {
+        for (IntervalStats stats : mCurrentStats) {
+            stats.updateLastUsedTime(packageName, lastUsedTime);
         }
         notifyStatsChanged();
     }
@@ -390,6 +397,16 @@
         }
     }
 
+    long getLastUsedTime(String packageName) {
+        final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
+        UsageStats packageUsage;
+        if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+            return -1;
+        } else {
+            return packageUsage.getLastTimeUsed();
+        }
+    }
+
     void persistActiveStats() {
         if (mStatsChanged) {
             Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index fcdb6d6..35bdceb 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -151,7 +151,7 @@
                 // the user to have the default voice interaction service enabled.
                 // Note that we don't do this for low-RAM devices, since we aren't
                 // supporting voice interaction services there.
-                curInteractorInfo = findAvailInteractor(userHandle, curRecognizer);
+                curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName());
                 if (curInteractorInfo != null) {
                     // Looks good!  We'll apply this one.  To make it happen, we clear the
                     // recognizer so that we don't think we have anything set and will
@@ -162,6 +162,18 @@
                 }
             }
 
+            // If forceInteractorPackage exists, try to apply the interactor from this package if
+            // possible and ignore the regular interactor setting.
+            String forceInteractorPackage =
+                    getForceVoiceInteractionServicePackage(mContext.getResources());
+            if (forceInteractorPackage != null) {
+                curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage);
+                if (curInteractorInfo != null) {
+                    // We'll apply this one. Clear the recognizer and re-apply the settings.
+                    curRecognizer = null;
+                }
+            }
+
             // If we are on a svelte device, make sure an interactor is not currently
             // enabled; if it is, turn it off.
             if (!mEnableService && curInteractorStr != null) {
@@ -225,8 +237,14 @@
 
         private boolean shouldEnableService(Resources res) {
             // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag.
-            return !ActivityManager.isLowRamDeviceStatic()
-                    || res.getBoolean(com.android.internal.R.bool.config_forceEnableVoiceInteractionService);
+            return !ActivityManager.isLowRamDeviceStatic() ||
+                    getForceVoiceInteractionServicePackage(res) != null;
+        }
+
+        private String getForceVoiceInteractionServicePackage(Resources res) {
+            String interactorPackage =
+                    res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
+            return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
         }
 
         public void systemRunning(boolean safeMode) {
@@ -279,7 +297,7 @@
             }
         }
 
-        VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) {
+        VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) {
             List<ResolveInfo> available =
                     mContext.getPackageManager().queryIntentServicesAsUser(
                             new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle);
@@ -300,8 +318,8 @@
                             VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
                                     mContext.getPackageManager(), comp, userHandle);
                             if (info.getParseError() == null) {
-                                if (recognizer == null || info.getServiceInfo().packageName.equals(
-                                        recognizer.getPackageName())) {
+                                if (packageName == null || info.getServiceInfo().packageName.equals(
+                                        packageName)) {
                                     if (foundInfo == null) {
                                         foundInfo = info;
                                     } else {
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index f05a1ef..a25d327 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -151,6 +151,7 @@
     private final CharSequence mShortDescription;
     private final List<String> mSupportedUriSchemes;
     private final Icon mIcon;
+    private boolean mIsEnabled;
 
     /**
      * Helper class for creating a {@link PhoneAccount}.
@@ -165,6 +166,7 @@
         private CharSequence mShortDescription;
         private List<String> mSupportedUriSchemes = new ArrayList<String>();
         private Icon mIcon;
+        private boolean mIsEnabled = false;
 
         /**
          * Creates a builder with the specified {@link PhoneAccountHandle} and label.
@@ -190,6 +192,7 @@
             mShortDescription = phoneAccount.getShortDescription();
             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
             mIcon = phoneAccount.getIcon();
+            mIsEnabled = phoneAccount.isEnabled();
         }
 
         /**
@@ -288,6 +291,18 @@
         }
 
         /**
+         * Sets the enabled state of the phone account.
+         *
+         * @param isEnabled The enabled state.
+         * @return The builder.
+         * @hide
+         */
+        public Builder setIsEnabled(boolean isEnabled) {
+            mIsEnabled = isEnabled;
+            return this;
+        }
+
+        /**
          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
          *
          * @return The {@link PhoneAccount}.
@@ -307,7 +322,8 @@
                     mHighlightColor,
                     mLabel,
                     mShortDescription,
-                    mSupportedUriSchemes);
+                    mSupportedUriSchemes,
+                    mIsEnabled);
         }
     }
 
@@ -320,7 +336,8 @@
             int highlightColor,
             CharSequence label,
             CharSequence shortDescription,
-            List<String> supportedUriSchemes) {
+            List<String> supportedUriSchemes,
+            boolean isEnabled) {
         mAccountHandle = account;
         mAddress = address;
         mSubscriptionAddress = subscriptionAddress;
@@ -330,6 +347,7 @@
         mLabel = label;
         mShortDescription = shortDescription;
         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
+        mIsEnabled = isEnabled;
     }
 
     public static Builder builder(
@@ -437,6 +455,15 @@
     }
 
     /**
+     * Indicates whether the user has enabled this phone account or not {@code PhoneAccounts}.
+     *
+     * @return The {@code true} if the account is enabled by the user, {@code false} otherwise.
+     */
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    /**
      * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
      * scheme.
      *
@@ -466,6 +493,14 @@
         return mHighlightColor;
     }
 
+    /**
+     * Sets the enabled state of the phone account.
+     * @hide
+     */
+    public void setIsEnabled(boolean isEnabled) {
+        mIsEnabled = isEnabled;
+    }
+
     //
     // Parcelable implementation
     //
@@ -500,12 +535,14 @@
         out.writeCharSequence(mLabel);
         out.writeCharSequence(mShortDescription);
         out.writeStringList(mSupportedUriSchemes);
+
         if (mIcon == null) {
             out.writeInt(0);
         } else {
             out.writeInt(1);
             mIcon.writeToParcel(out, flags);
         }
+        out.writeByte((byte) (mIsEnabled ? 1 : 0));
     }
 
     public static final Creator<PhoneAccount> CREATOR
@@ -547,11 +584,14 @@
         } else {
             mIcon = null;
         }
+        mIsEnabled = in.readByte() == 1;
     }
 
     @Override
     public String toString() {
-        StringBuilder sb = new StringBuilder().append("[PhoneAccount: ")
+        StringBuilder sb = new StringBuilder().append("[[")
+                .append(mIsEnabled ? 'X' : ' ')
+                .append("] PhoneAccount: ")
                 .append(mAccountHandle)
                 .append(" Capabilities: ")
                 .append(mCapabilities)
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index c8ed2b0..308c204 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -377,15 +377,23 @@
     }
 
     /**
-     * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
-     * calls with a specified URI scheme.
+     * Return the {@link PhoneAccount} which will be used to place outgoing calls to addresses with
+     * the specified {@code uriScheme}. This {@link PhoneAccount} will always be a member of the
+     * list which is returned from invoking {@link #getCallCapablePhoneAccounts()}. The specific
+     * account returned depends on the following priorities:
+     * <ul>
+     * <li> If the user-selected default {@link PhoneAccount} supports the specified scheme, it will
+     * be returned.
+     * </li>
+     * <li> If there exists only one {@link PhoneAccount} that supports the specified scheme, it
+     * will be returned.
+     * </li>
+     * </ul>
      * <p>
-     * Apps must be prepared for this method to return {@code null}, indicating that there currently
-     * exists no user-chosen default {@code PhoneAccount}.
-     * <p>
+     * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
+     *
      * @param uriScheme The URI scheme.
-     * @return The {@link PhoneAccountHandle} corresponding to the user-chosen default for outgoing
-     * phone calls for a specified URI scheme.
+     * @return The {@link PhoneAccountHandle} corresponding to the account to be used.
      */
     public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
         try {
@@ -403,7 +411,7 @@
      * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
      * calls. This {@code PhoneAccount} will always be a member of the list which is returned from
      * calling {@link #getCallCapablePhoneAccounts()}
-     *
+     * <p>
      * Apps must be prepared for this method to return {@code null}, indicating that there currently
      * exists no user-chosen default {@code PhoneAccount}.
      *
@@ -422,7 +430,7 @@
     }
 
     /**
-     * Sets the default account for making outgoing phone calls.
+     * Sets the user-chosen default for making outgoing phone calls.
      * @hide
      */
     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
@@ -439,6 +447,7 @@
      * Returns the current SIM call manager. Apps must be prepared for this method to return
      * {@code null}, indicating that there currently exists no user-chosen default
      * {@code PhoneAccount}.
+     *
      * @return The phone account handle of the current sim call manager.
      */
     public PhoneAccountHandle getSimCallManager() {
@@ -454,6 +463,7 @@
 
     /**
      * Sets the SIM call manager to the specified phone account.
+     *
      * @param accountHandle The phone account handle of the account to set as the sim call manager.
      * @hide
      */
@@ -469,6 +479,7 @@
 
     /**
      * Returns the list of registered SIM call managers.
+     *
      * @return List of registered SIM call managers.
      * @hide
      */
@@ -497,16 +508,6 @@
     }
 
     /**
-     * Returns the list of registered SIM call managers.
-     * @return List of registered SIM call managers.
-     * @hide
-     */
-    @SystemApi
-    public List<PhoneAccountHandle> getRegisteredConnectionManagers() {
-        return getSimCallManagers();
-    }
-
-    /**
      * Returns a list of the {@link PhoneAccountHandle}s which can be used to make and receive phone
      * calls which support the specified URI scheme.
      * <P>
@@ -534,20 +535,33 @@
 
 
     /**
-     * Return a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
-     * calls.
+     * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
+     * calls. The returned list includes only those accounts which have been explicitly enabled
+     * by the user.
      *
      * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @return A list of {@code PhoneAccountHandle} objects.
-     *
      */
     public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
+        return getCallCapablePhoneAccounts(false);
+    }
+
+    /**
+     * Returns a list of {@link PhoneAccountHandle}s including those which have not been enabled
+     * by the user.
+     *
+     * @return A list of {@code PhoneAccountHandle} objects.
+     * @hide
+     */
+    public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().getCallCapablePhoneAccounts(mContext.getOpPackageName());
+                return getTelecomService().getCallCapablePhoneAccounts(
+                        includeDisabledAccounts, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts", e);
+            Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
+                    includeDisabledAccounts + ")", e);
         }
         return new ArrayList<>();
     }
@@ -1163,6 +1177,25 @@
         }
     }
 
+    /**
+     * Enables and disables specified phone account.
+     *
+     * @param handle Handle to the phone account.
+     * @param isEnabled Enable state of the phone account.
+     * @hide
+     */
+    @SystemApi
+    public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                service.enablePhoneAccount(handle, isEnabled);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error enablePhoneAbbount", e);
+            }
+        }
+    }
+
     private ITelecomService getTelecomService() {
         return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
     }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index bc76f06..aa02021 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -53,7 +53,8 @@
     /**
      * @see TelecomServiceImpl#getCallCapablePhoneAccounts
      */
-    List<PhoneAccountHandle> getCallCapablePhoneAccounts(String callingPackage);
+    List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+            boolean includeDisabledAccounts, String callingPackage);
 
     /**
      * @see TelecomManager#getPhoneAccountsSupportingScheme
@@ -226,4 +227,9 @@
      * @see TelecomServiceImpl#placeCall
      */
     void placeCall(in Uri handle, in Bundle extras, String callingPackage);
+
+    /**
+     * @see TelecomServiceImpl#enablePhoneAccount
+     */
+    void enablePhoneAccount(in PhoneAccountHandle accountHandle, boolean isEnabled);
 }
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
index 42b1cf1..0c177ef 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
@@ -116,7 +116,6 @@
     rs_allocation allMeshes = rsGetAllocation(gMeshes);
     int size = rsAllocationGetDimX(allMeshes);
     gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
     for (int i = 0; i < size; i++) {
         MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
         rsgDrawMesh(info->mMesh);
@@ -124,7 +123,6 @@
 }
 
 static void drawDescription() {
-    uint width = rsgGetWidth();
     uint height = rsgGetHeight();
     int left = 0, right = 0, top = 0, bottom = 0;
 
@@ -196,7 +194,6 @@
 
     uint32_t w = rsAllocationGetDimX(gOffscreen);
     uint32_t h = rsAllocationGetDimY(gOffscreen);
-    uint32_t numElements = w*h;
 
     rsgAllocationSyncAll(gOffscreen, RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET);
 
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
index 05ef3ac..13a3c85 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
@@ -115,7 +115,6 @@
     rs_allocation allMeshes = rsGetAllocation(gMeshes);
     int size = rsAllocationGetDimX(allMeshes);
     gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
     for (int i = 0; i < size; i++) {
         MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
         rsgDrawMesh(info->mMesh);
@@ -123,7 +122,6 @@
 }
 
 static void drawDescription() {
-    uint width = rsgGetWidth();
     uint height = rsgGetHeight();
     int left = 0, right = 0, top = 0, bottom = 0;
 
diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index de2a0a7..d3dd5b9 100644
--- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -123,7 +123,6 @@
     rs_allocation allMeshes = rsGetAllocation(gMeshes);
     int size = rsAllocationGetDimX(allMeshes);
     gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
     for (int i = 0; i < size; i++) {
         MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
         rsgDrawMesh(info->mMesh);
@@ -131,7 +130,6 @@
 }
 
 void drawDescription() {
-    uint width = rsgGetWidth();
     uint height = rsgGetHeight();
     int left = 0, right = 0, top = 0, bottom = 0;
 
@@ -163,7 +161,7 @@
     rsMatrixMultiply(&matrix, &gPostureMatrix);
     rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f);
     rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
-    
+
     rsgProgramVertexLoadModelMatrix(&matrix);
 
     renderAllMeshes();
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index 27e5b11..43cf4e0 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -85,7 +85,7 @@
     TestData testData;
     fillSurfaceParams(&testData);
 
-    rs_allocation null_alloc;
+    rs_allocation null_alloc = {0};
     rsForEach(gTestScripts[index].testScript,
               gTestScripts[index].testData,
               null_alloc,
@@ -125,7 +125,6 @@
 
 static int benchMode = 0;
 static bool benchmarkSingleTest = false;
-static int benchSubMode = 0;
 static int runningLoops = 0;
 static bool sendMsgFlag = false;
 
@@ -209,7 +208,6 @@
     drawOffscreenResult(0, 0, quadW, quadH);
 
     int left = 0, right = 0, top = 0, bottom = 0;
-    uint width = rsgGetWidth();
     uint height = rsgGetHeight();
     rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f);
     rsgBindFont(gFontSerif);
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
index 7f10019..0f50828 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
@@ -52,7 +52,6 @@
     fonts[3] = gFontSerif;
     fonts[4] = gFontSans;
 
-    uint width = gRenderSurfaceW;
     uint height = gRenderSurfaceH;
     int left = 0, right = 0, top = 0, bottom = 0;
     rsgMeasureText(sampleText, &left, &right, &top, &bottom);
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs
index 5089092..e87db39 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs
@@ -143,7 +143,6 @@
     float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f);
     float id = d / gGalaxyRadius;
     float z = randomGauss() * 0.4f * (1.0f - id);
-    float p = -d * ELLIPSE_TWIST;
 
     if (d < gGalaxyRadius * 0.33f) {
         part->color.x = (uchar) (220 + id * 35);
@@ -305,7 +304,6 @@
     int left = 0, right = 0, top = 0, bottom = 0;
     rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom);
     float textHeight = (float)(top - bottom);
-    float textWidth = (float)(right - left);
 
     rs_matrix4x4 matrix;
     rsMatrixLoadScale(&matrix, size, size, 1.0);
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
index 575794b..00793c0 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
@@ -19,7 +19,7 @@
 #include "scenegraph_objects.rsh"
 
 //#define DEBUG_PARAMS
-static void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
+static inline void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
     rsDebug("____________ Param ____________", p);
     printName(pData->paramName);
     rsDebug("bufferOffset", p->bufferOffset);
@@ -44,8 +44,7 @@
     }
 }
 
-
-static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+static inline void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
 #ifdef DEBUG_PARAMS
     rsDebug("Writing value ", *input);
     rsDebug("Writing vec size ", vecSize);
@@ -67,7 +66,7 @@
     }
 }
 
-static bool processParam(SgShaderParam *p, SgShaderParamData *pData,
+static inline bool processParam(SgShaderParam *p, SgShaderParamData *pData,
                          uint8_t *constantBuffer,
                          const SgCamera *currentCam,
                          SgFragmentShader *shader) {
@@ -155,7 +154,7 @@
     return true;
 }
 
-static void processAllParams(rs_allocation shaderConst,
+static inline void processAllParams(rs_allocation shaderConst,
                              rs_allocation allParams,
                              const SgCamera *camera) {
     if (rsIsObject(shaderConst)) {
@@ -177,7 +176,7 @@
     }
 }
 
-static void processTextureParams(SgFragmentShader *shader) {
+static inline void processTextureParams(SgFragmentShader *shader) {
     int numParams = 0;
     if (rsIsObject(shader->shaderTextureParams)) {
         numParams = rsAllocationGetDimX(shader->shaderTextureParams);
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
index 8a73dbd..205b2cb 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
@@ -78,7 +78,7 @@
     if (rsIsObject(renderState->pr)) {
         rsgBindProgramRaster(renderState->pr);
     } else {
-        rs_program_raster pr;
+        rs_program_raster pr = {0};
         rsgBindProgramRaster(pr);
     }
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
index bdca3ab..90ae212 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
@@ -208,7 +208,7 @@
     rs_allocation texture;
 } SgTexture;
 
-static void printName(rs_allocation name) {
+static inline void printName(rs_allocation name) {
     if (!rsIsObject(name)) {
         rsDebug("no name", 0);
         return;
@@ -217,7 +217,7 @@
     rsDebug((const char*)rsGetElementAt(name, 0), 0);
 }
 
-static void printCameraInfo(const SgCamera *cam) {
+static inline void printCameraInfo(const SgCamera *cam) {
     rsDebug("***** Camera information. ptr:", cam);
     printName(cam->name);
     const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
@@ -233,7 +233,7 @@
     rsDebug("View: ", &cam->view);
 }
 
-static void printLightInfo(const SgLight *light) {
+static inline void printLightInfo(const SgLight *light) {
     rsDebug("***** Light information. ptr:", light);
     printName(light->name);
     const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
@@ -246,7 +246,7 @@
     rsDebug("Type: ", light->type);
 }
 
-static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
+static inline void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
     rsDebug("=================================", screenX);
     rsDebug("Point X", screenX);
     rsDebug("Point Y", screenY);
@@ -290,7 +290,7 @@
     *pnt = cam->position.xyz;
 }
 
-static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
+static inline bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
     // Solving for t^2 + Bt + C = 0
     float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz;
     float B = dot(originMinusCenter, vec) * 2.0f;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
index 941b5a8..1d0b5be 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
@@ -26,6 +26,7 @@
 } ParentData;
 
 //#define DEBUG_TRANSFORMS
+/* Unused function:
 static void debugTransform(SgTransform *data, const ParentData *parent) {
     rsDebug("****** <Transform> ******", (int)data);
     printName(data->name);
@@ -53,6 +54,7 @@
     rsDebug("timestamp", data->timestamp);
     rsDebug("****** </Transform> ******", (int)data);
 }
+*/
 
 static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
     rs_matrix4x4 temp;
@@ -119,7 +121,7 @@
     }
 
     if (rsIsObject(data->children)) {
-        rs_allocation nullAlloc;
+        rs_allocation nullAlloc = {0};
         rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
     }
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
index 997a1a7..d94da52 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
@@ -41,9 +41,7 @@
     gRotate = 0.0f;
 }
 
-static int pos = 50;
 static float gRotateY = 120.0f;
-static float3 gLookAt = 0;
 static float gZoom = 50.0f;
 static void displayLoading() {
     if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) {
diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
index ae32e3a..735f6b9 100644
--- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
+++ b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs
@@ -131,7 +131,6 @@
     rs_allocation allMeshes = rsGetAllocation(gMeshes);
     int size = rsAllocationGetDimX(allMeshes);
     gLookAt = 0.0f;
-    float minX, minY, minZ, maxX, maxY, maxZ;
     for (int i = 0; i < size; i++) {
         MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i);
         rsgDrawMesh(info->mMesh);
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 572fdc9..54a508a 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -320,7 +320,8 @@
                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                         parser, mContext, resValue.isFramework());
                 try {
-                    return ColorStateList.createFromXml(mContext.getResources(), blockParser);
+                    return ColorStateList.createFromXml(mContext.getResources(), blockParser,
+                            mContext.getTheme());
                 } finally {
                     blockParser.ensurePopped();
                 }
@@ -444,7 +445,7 @@
     @Override
     public int getDimensionPixelSize(int index, int defValue) {
         try {
-            return getDimension(index);
+            return getDimension(index, null);
         } catch (RuntimeException e) {
             String s = getString(index);
 
@@ -474,12 +475,12 @@
     @Override
     public int getLayoutDimension(int index, String name) {
         try {
-            // this will throw an exception
-            return getDimension(index);
+            // this will throw an exception if not found.
+            return getDimension(index, name);
         } catch (RuntimeException e) {
 
             if (LayoutInflater_Delegate.sIsInInclude) {
-                throw new RuntimeException();
+                throw new RuntimeException("Layout Dimension '" + name + "' not found.");
             }
 
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
@@ -494,9 +495,13 @@
         return getDimensionPixelSize(index, defValue);
     }
 
-    private int getDimension(int index) {
+    /** @param name attribute name, used for error reporting. */
+    private int getDimension(int index, @Nullable String name) {
         String s = getString(index);
         if (s == null) {
+            if (name != null) {
+                throw new RuntimeException("Attribute '" + name + "' not found");
+            }
             throw new RuntimeException();
         }
         // Check if the value is a magic constant that doesn't require a unit.
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index dda8ebb..4226526 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -82,36 +82,8 @@
 
         builder.mText = text;
         builder.mWidths = new float[length];
-
-        // compute all possible breakpoints.
-        BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
-        it.setText(new Segment(builder.mText, 0, length));
-
-        // average word length in english is 5. So, initialize the possible breaks with a guess.
-        List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
-        int loc;
-        it.first();
-        while ((loc = it.next()) != BreakIterator.DONE) {
-            breaks.add(loc);
-        }
-        LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
-        TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
-        List<Primitive> primitives =
-                computePrimitives(builder.mText, builder.mWidths, length, breaks);
-        BreakStrategy strategy = BreakStrategy.getStrategy(breakStrategy);
-        switch (strategy) {
-            case GREEDY:
-                builder.mLineBreaker =
-                        new GreedyLineBreaker(primitives, lineWidth, tabStopCalculator);
-                break;
-            case HIGH_QUALITY:
-                // TODO
-//                break;
-            case BALANCED:
-                builder.mLineBreaker = new OptimizingLineBreaker(primitives, lineWidth,
-                        tabStopCalculator);
-                break;
-        }
+        builder.mLineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
+        builder.mTabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
     }
 
     @LayoutlibDelegate
@@ -160,6 +132,37 @@
         if (builder == null) {
             return 0;
         }
+
+        // compute all possible breakpoints.
+        int length = builder.mWidths.length;
+        BreakIterator it = BreakIterator.getLineInstance(new ULocale(builder.mLocale));
+        it.setText(new Segment(builder.mText, 0, length));
+
+        // average word length in english is 5. So, initialize the possible breaks with a guess.
+        List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
+        int loc;
+        it.first();
+        while ((loc = it.next()) != BreakIterator.DONE) {
+            breaks.add(loc);
+        }
+
+        List<Primitive> primitives =
+                computePrimitives(builder.mText, builder.mWidths, length, breaks);
+        switch (builder.mBreakStrategy) {
+            case Layout.BREAK_STRATEGY_SIMPLE:
+                builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth,
+                        builder.mTabStopCalculator);
+                break;
+            case Layout.BREAK_STRATEGY_HIGH_QUALITY:
+                // TODO
+//                break;
+            case Layout.BREAK_STRATEGY_BALANCED:
+                builder.mLineBreaker = new OptimizingLineBreaker(primitives, builder.mLineWidth,
+                        builder.mTabStopCalculator);
+                break;
+            default:
+                throw new AssertionError("Unknown break strategy: " + builder.mBreakStrategy);
+        }
         builder.mLineBreaker.computeBreaks(recycle);
         return recycle.breaks.length;
     }
@@ -223,22 +226,8 @@
         float[] mWidths;
         LineBreaker mLineBreaker;
         long mNativeHyphenator;
-    }
-
-    private enum BreakStrategy {
-        GREEDY, HIGH_QUALITY, BALANCED;
-
-        static BreakStrategy getStrategy(int strategy) {
-            switch (strategy) {
-                case 0:
-                    return GREEDY;
-                case 1:
-                    return HIGH_QUALITY;
-                case 2:
-                    return BALANCED;
-                default:
-                    throw new AssertionError("Unknown break strategy: " + strategy);
-            }
-        }
+        int mBreakStrategy;
+        LineWidth mLineWidth;
+        TabStops mTabStopCalculator;
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 87762a6..32ee9e8 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -53,9 +53,14 @@
      */
     private static final String[] sClassPrefixList = {
         "android.widget.",
-        "android.webkit."
+        "android.webkit.",
+        "android.app."
     };
 
+    public static String[] getClassPrefixList() {
+        return sClassPrefixList;
+    }
+
     protected BridgeInflater(LayoutInflater original, Context newContext) {
         super(original, newContext);
         newContext = getBaseContext(newContext);
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 4072302..27b406a 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -181,7 +181,8 @@
                             // ---- END CHANGES
 
                             params = group.generateLayoutParams(attrs);
-
+                        } catch (RuntimeException ignored) {
+                            // Ignore, just fail over to child attrs.
                         } finally {
                             // ---- START CHANGES
                             sIsInInclude = false;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index eb5f597..59f07a7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -138,8 +138,9 @@
 
     private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
     private SharedPreferences mSharedPreferences;
+    private ClassLoader mClassLoader;
 
-  /**
+    /**
      * @param projectKey An Object identifying the project. This is used for the cache mechanism.
      * @param metrics the {@link DisplayMetrics}.
      * @param renderResources the configured resources (both framework and projects) for this
@@ -462,7 +463,21 @@
 
     @Override
     public ClassLoader getClassLoader() {
-        return this.getClass().getClassLoader();
+        if (mClassLoader == null) {
+            mClassLoader = new ClassLoader(getClass().getClassLoader()) {
+                @Override
+                protected Class<?> findClass(String name) throws ClassNotFoundException {
+                    for (String prefix : BridgeInflater.getClassPrefixList()) {
+                        if (name.startsWith(prefix)) {
+                            // These are framework classes and should not be loaded from the app.
+                            throw new ClassNotFoundException(name + " not found");
+                        }
+                    }
+                    return BridgeContext.this.mLayoutlibCallback.findClass(name);
+                }
+            };
+        }
+        return mClassLoader;
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 2b95488..f3a0d58 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -275,7 +275,6 @@
             mContext.getRenderResources().setLogger(null);
         }
         ParserFactory.setParserFactory(null);
-
     }
 
     public static BridgeContext getCurrentContext() {
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 91be0bd..63115e4 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -124,9 +124,14 @@
         if (platformDir != null) {
             return platformDir;
         }
-        // Test if workingDir is  platform/frameworks/base/tools/layoutlib. That is, root should be
-        // workingDir/../../../../  (4 levels up)
+
+        // Test if workingDir is platform/frameworks/base/tools/layoutlib/bridge.
         File currentDir = workingDir;
+        if (currentDir.getName().equalsIgnoreCase("bridge")) {
+            currentDir = currentDir.getParentFile();
+        }
+        // Test if currentDir is  platform/frameworks/base/tools/layoutlib. That is, root should be
+        // workingDir/../../../../  (4 levels up)
         for (int i = 0; i < 4; i++) {
             if (currentDir != null) {
                 currentDir = currentDir.getParentFile();
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index aa51c46..c8b2b84 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -728,7 +728,7 @@
 
 
                 // Check if method needs to replaced by a call to a different method.
-                if (ReplaceMethodCallsAdapter.isReplacementNeeded(owner, name, desc)) {
+                if (ReplaceMethodCallsAdapter.isReplacementNeeded(owner, name, desc, mOwnerClass)) {
                     mReplaceMethodCallClasses.add(mOwnerClass);
                 }
             }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index bd6f070..f6c2626 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -24,9 +24,11 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -72,6 +74,9 @@
     /** FQCN Names of classes to refactor. All reference to old-FQCN will be updated to new-FQCN.
      * map old-FQCN => new-FQCN */
     private final HashMap<String, String> mRefactorClasses;
+    /** Methods to inject. FQCN of class in which method should be injected => runnable that does
+     * the injection. */
+    private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
 
     /**
      * Creates a new generator that can generate the output JAR with the stubbed classes.
@@ -83,7 +88,23 @@
     public AsmGenerator(Log log, String osDestJar, ICreateInfo createInfo) {
         mLog = log;
         mOsDestJar = osDestJar;
-        mInjectClasses = createInfo.getInjectedClasses();
+        ArrayList<Class<?>> injectedClasses =
+                new ArrayList<Class<?>>(Arrays.asList(createInfo.getInjectedClasses()));
+        // Search for and add anonymous inner classes also.
+        ListIterator<Class<?>> iter = injectedClasses.listIterator();
+        while (iter.hasNext()) {
+            Class<?> clazz = iter.next();
+            try {
+                int i = 1;
+                while(i < 100) {
+                    iter.add(Class.forName(clazz.getName() + "$" + i));
+                    i++;
+                }
+            } catch (ClassNotFoundException ignored) {
+                // Expected.
+            }
+        }
+        mInjectClasses = injectedClasses.toArray(new Class<?>[0]);
         mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods()));
 
         // Create the map/set of methods to change to delegates
@@ -165,6 +186,8 @@
             }
             returnTypes.add(binaryToInternalClassName(className));
         }
+
+        mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
     }
 
     /**
@@ -285,13 +308,7 @@
      * e.g. it returns something like "com/foo/OuterClass$InnerClass1$InnerClass2.class"
      */
     private String classToEntryPath(Class<?> clazz) {
-        String name = "";
-        Class<?> parent;
-        while ((parent = clazz.getEnclosingClass()) != null) {
-            name = "$" + clazz.getSimpleName() + name;
-            clazz = parent;
-        }
-        return classNameToEntryPath(clazz.getCanonicalName() + name);
+        return classNameToEntryPath(clazz.getName());
     }
 
     /**
@@ -337,7 +354,7 @@
         ClassVisitor cv = cw;
 
         if (mReplaceMethodCallsClasses.contains(className)) {
-            cv = new ReplaceMethodCallsAdapter(cv);
+            cv = new ReplaceMethodCallsAdapter(cv, className);
         }
 
         cv = new RefactorClassAdapter(cv, mRefactorClasses);
@@ -345,6 +362,10 @@
             cv = new RenameClassAdapter(cv, className, newName);
         }
 
+        String binaryNewName = newName.replace('/', '.');
+        if (mInjectedMethodsMap.keySet().contains(binaryNewName)) {
+            cv = new InjectMethodsAdapter(cv, mInjectedMethodsMap.get(binaryNewName));
+        }
         cv = new TransformClassAdapter(mLog, mStubMethods, mDeleteReturns.get(className),
                 newName, cv, stubNativesOnly);
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 245cd61..27ab5ea 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -26,7 +26,9 @@
 import com.android.tools.layoutlib.java.UnsafeByteSequence;
 
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -105,6 +107,7 @@
       return JAVA_PKG_CLASSES;
     }
 
+    @Override
     public Set<String> getExcludedClasses() {
         String[] refactoredClasses = getJavaPkgClasses();
         int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length;
@@ -115,6 +118,12 @@
         excludedClasses.addAll(Arrays.asList(EXCLUDED_CLASSES));
         return excludedClasses;
     }
+
+    @Override
+    public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+        return INJECTED_METHODS;
+    }
+
     //-----
 
     /**
@@ -127,6 +136,8 @@
             ICreateInfo.class,
             CreateInfo.class,
             LayoutlibDelegate.class,
+            InjectMethodRunnable.class,
+            InjectMethodRunnables.class,
             /* Java package classes */
             AutoCloseable.class,
             Objects.class,
@@ -286,5 +297,10 @@
     private final static String[] DELETE_RETURNS =
         new String[] {
             null };                         // separator, for next class/methods list.
-}
 
+    private final static Map<String, InjectMethodRunnable> INJECTED_METHODS =
+            new HashMap<String, InjectMethodRunnable>(1) {{
+                put("android.content.Context",
+                        InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER);
+            }};
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index e49a668..54b1fe6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -16,6 +16,9 @@
 
 package com.android.tools.layoutlib.create;
 
+import org.objectweb.asm.ClassVisitor;
+
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -27,33 +30,33 @@
      * Returns the list of class from layoutlib_create to inject in layoutlib.
      * The list can be empty but must not be null.
      */
-    public abstract Class<?>[] getInjectedClasses();
+    Class<?>[] getInjectedClasses();
 
     /**
      * Returns the list of methods to rewrite as delegates.
      * The list can be empty but must not be null.
      */
-    public abstract String[] getDelegateMethods();
+    String[] getDelegateMethods();
 
     /**
      * Returns the list of classes on which to delegate all native methods.
      * The list can be empty but must not be null.
      */
-    public abstract String[] getDelegateClassNatives();
+    String[] getDelegateClassNatives();
 
     /**
      * Returns The list of methods to stub out. Each entry must be in the form
      * "package.package.OuterClass$InnerClass#MethodName".
      * The list can be empty but must not be null.
      */
-    public abstract String[] getOverriddenMethods();
+    String[] getOverriddenMethods();
 
     /**
      * Returns the list of classes to rename, must be an even list: the binary FQCN
      * of class to replace followed by the new FQCN.
      * The list can be empty but must not be null.
      */
-    public abstract String[] getRenamedClasses();
+    String[] getRenamedClasses();
 
     /**
      * Returns the list of classes for which the methods returning them should be deleted.
@@ -62,7 +65,7 @@
      * the methods to delete.
      * The list can be empty but must not be null.
      */
-    public abstract String[] getDeleteReturns();
+    String[] getDeleteReturns();
 
     /**
      * Returns the list of classes to refactor, must be an even list: the
@@ -70,7 +73,24 @@
      * to the old class should be updated to the new class.
      * The list can be empty but must not be null.
      */
-    public abstract String[] getJavaPkgClasses();
+    String[] getJavaPkgClasses();
 
-    public abstract Set<String> getExcludedClasses();
+    Set<String> getExcludedClasses();
+
+    /**
+     * Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be
+     * called to inject methods into a class.
+     * Can be empty but must not be null.
+     */
+    Map<String, InjectMethodRunnable> getInjectedMethodsMap();
+
+    abstract class InjectMethodRunnable {
+        /**
+         * @param cv Must be {@link ClassVisitor}. However, the param type is object so that when
+         * loading the class, ClassVisitor is not loaded. This is because when injecting
+         * CreateInfo in LayoutLib (see {@link #getInjectedClasses()}, we don't want to inject
+         * asm classes also, but still keep CreateInfo loadable.
+         */
+        public abstract void generateMethods(Object cv);
+    }
 }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java
new file mode 100644
index 0000000..37fc096
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.create.ICreateInfo.InjectMethodRunnable;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ARETURN;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+
+public class InjectMethodRunnables {
+    public static final ICreateInfo.InjectMethodRunnable CONTEXT_GET_FRAMEWORK_CLASS_LOADER
+            = new InjectMethodRunnable() {
+        @Override
+        public void generateMethods(Object classVisitor) {
+            assert classVisitor instanceof ClassVisitor;
+            ClassVisitor cv = (ClassVisitor) classVisitor;
+            // generated by compiling the class:
+            // class foo { public ClassLoader getFrameworkClassLoader() { return getClass().getClassLoader(); } }
+            // and then running ASMifier on it:
+            // java -classpath asm-debug-all-5.0.2.jar:. org.objectweb.asm.util.ASMifier foo
+            MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "getFrameworkClassLoader",
+                    "()Ljava/lang/ClassLoader;", null, null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass",
+                    "()Ljava/lang/Class;");
+            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader",
+                    "()Ljava/lang/ClassLoader;");
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(1, 1);
+            mv.visitEnd();
+            // generated code ends.
+        }
+    };
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java
new file mode 100644
index 0000000..ea2b9c9
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 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.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.create.ICreateInfo.InjectMethodRunnable;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Injects methods into some classes.
+ */
+public class InjectMethodsAdapter extends ClassVisitor {
+
+    private final ICreateInfo.InjectMethodRunnable mRunnable;
+
+    public InjectMethodsAdapter(ClassVisitor cv, InjectMethodRunnable runnable) {
+        super(Opcodes.ASM4, cv);
+        mRunnable = runnable;
+    }
+
+    @Override
+    public void visitEnd() {
+        mRunnable.generateMethods(this);
+        super.visitEnd();
+    }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
index 384d8ca..4369148 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
@@ -62,14 +62,13 @@
         // Case 1: java.lang.System.arraycopy()
         METHOD_REPLACERS.add(new MethodReplacer() {
             @Override
-            public boolean isNeeded(String owner, String name, String desc) {
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
                 return JAVA_LANG_SYSTEM.equals(owner) && "arraycopy".equals(name) &&
                         ARRAYCOPY_DESCRIPTORS.contains(desc);
             }
 
             @Override
             public void replace(MethodInformation mi) {
-                assert isNeeded(mi.owner, mi.name, mi.desc);
                 mi.desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
             }
         });
@@ -81,14 +80,13 @@
                     Type.getMethodDescriptor(STRING, Type.getType(Locale.class));
 
             @Override
-            public boolean isNeeded(String owner, String name, String desc) {
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
                 return JAVA_LOCALE_CLASS.equals(owner) && "()Ljava/lang/String;".equals(desc) &&
                         ("toLanguageTag".equals(name) || "getScript".equals(name));
             }
 
             @Override
             public void replace(MethodInformation mi) {
-                assert isNeeded(mi.owner, mi.name, mi.desc);
                 mi.opcode = Opcodes.INVOKESTATIC;
                 mi.owner = ANDROID_LOCALE_CLASS;
                 mi.desc = LOCALE_TO_STRING;
@@ -103,7 +101,7 @@
                     Type.getType(Locale.class), STRING);
 
             @Override
-            public boolean isNeeded(String owner, String name, String desc) {
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
                 return JAVA_LOCALE_CLASS.equals(owner) &&
                         ("adjustLanguageCode".equals(name) && desc.equals(STRING_TO_STRING) ||
                         "forLanguageTag".equals(name) && desc.equals(STRING_TO_LOCALE));
@@ -111,7 +109,6 @@
 
             @Override
             public void replace(MethodInformation mi) {
-                assert isNeeded(mi.owner, mi.name, mi.desc);
                 mi.owner = ANDROID_LOCALE_CLASS;
             }
         });
@@ -119,14 +116,13 @@
         // Case 4: java.lang.System.log?()
         METHOD_REPLACERS.add(new MethodReplacer() {
             @Override
-            public boolean isNeeded(String owner, String name, String desc) {
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
                 return JAVA_LANG_SYSTEM.equals(owner) && name.length() == 4
                         && name.startsWith("log");
             }
 
             @Override
             public void replace(MethodInformation mi) {
-                assert isNeeded(mi.owner, mi.name, mi.desc);
                 assert mi.desc.equals("(Ljava/lang/String;Ljava/lang/Throwable;)V")
                         || mi.desc.equals("(Ljava/lang/String;)V");
                 mi.name = "log";
@@ -142,7 +138,7 @@
             private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class);
 
             @Override
-            public boolean isNeeded(String owner, String name, String desc) {
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
                 return LINKED_HASH_MAP.equals(owner) &&
                         "eldest".equals(name) &&
                         VOID_TO_MAP_ENTRY.equals(desc);
@@ -150,26 +146,64 @@
 
             @Override
             public void replace(MethodInformation mi) {
-                assert isNeeded(mi.owner, mi.name, mi.desc);
                 mi.opcode = Opcodes.INVOKESTATIC;
                 mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class);
                 mi.desc = Type.getMethodDescriptor(
                         Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class));
             }
         });
+
+        // Case 6: android.content.Context.getClassLoader() in LayoutInflater
+        METHOD_REPLACERS.add(new MethodReplacer() {
+            // When LayoutInflater asks for a class loader, we must return the class loader that
+            // cannot return app's custom views/classes. This is so that in case of any failure
+            // or exception when instantiating the views, the IDE can replace it with a mock view
+            // and have proper error handling. However, if a custom view asks for the class
+            // loader, we must return a class loader that can find app's custom views as well.
+            // Thus, we rewrite the call to get class loader in LayoutInflater to
+            // getFrameworkClassLoader and inject a new method in Context. This leaves the normal
+            // method: Context.getClassLoader() free to be used by the apps.
+            private final String VOID_TO_CLASS_LOADER =
+                    Type.getMethodDescriptor(Type.getType(ClassLoader.class));
+
+            @Override
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+                return owner.equals("android/content/Context") &&
+                        sourceClass.equals("android/view/LayoutInflater") &&
+                        name.equals("getClassLoader") &&
+                        desc.equals(VOID_TO_CLASS_LOADER);
+            }
+
+            @Override
+            public void replace(MethodInformation mi) {
+                mi.name = "getFrameworkClassLoader";
+            }
+        });
     }
 
-    public static boolean isReplacementNeeded(String owner, String name, String desc) {
+    /**
+     * If a method some.package.Class.Method(args) is called from some.other.Class,
+     * @param owner some/package/Class
+     * @param name Method
+     * @param desc (args)returnType
+     * @param sourceClass some/other/Class
+     * @return if the method invocation needs to be replaced by some other class.
+     */
+    public static boolean isReplacementNeeded(String owner, String name, String desc,
+            String sourceClass) {
         for (MethodReplacer replacer : METHOD_REPLACERS) {
-            if (replacer.isNeeded(owner, name, desc)) {
+            if (replacer.isNeeded(owner, name, desc, sourceClass)) {
                 return true;
             }
         }
         return false;
     }
 
-    public ReplaceMethodCallsAdapter(ClassVisitor cv) {
+    private final String mOriginalClassName;
+
+    public ReplaceMethodCallsAdapter(ClassVisitor cv, String originalClassName) {
         super(Opcodes.ASM4, cv);
+        mOriginalClassName = originalClassName;
     }
 
     @Override
@@ -187,7 +221,7 @@
         @Override
         public void visitMethodInsn(int opcode, String owner, String name, String desc) {
             for (MethodReplacer replacer : METHOD_REPLACERS) {
-                if (replacer.isNeeded(owner, name, desc)) {
+                if (replacer.isNeeded(owner, name, desc, mOriginalClassName)) {
                     MethodInformation mi = new MethodInformation(opcode, owner, name, desc);
                     replacer.replace(mi);
                     opcode = mi.opcode;
@@ -216,13 +250,12 @@
     }
 
     private interface MethodReplacer {
-        public boolean isNeeded(String owner, String name, String desc);
+        boolean isNeeded(String owner, String name, String desc, String sourceClass);
 
         /**
          * Updates the MethodInformation with the new values of the method attributes -
          * opcode, owner, name and desc.
-         *
          */
-        public void replace(MethodInformation mi);
+        void replace(MethodInformation mi);
     }
 }
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index cf91386..2c21470 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -19,7 +19,9 @@
 
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
@@ -32,13 +34,17 @@
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
@@ -130,6 +136,11 @@
                  // methods deleted from their return type.
                 return new String[0];
             }
+
+            @Override
+            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+                return new HashMap<String, InjectMethodRunnable>(0);
+            }
         };
 
         AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -200,6 +211,11 @@
                  // methods deleted from their return type.
                 return new String[0];
             }
+
+            @Override
+            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+                return new HashMap<String, InjectMethodRunnable>(0);
+            }
         };
 
         AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -278,6 +294,11 @@
                 // methods deleted from their return type.
                 return new String[0];
             }
+
+            @Override
+            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+                return new HashMap<String, InjectMethodRunnable>(0);
+            }
         };
 
         AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -303,6 +324,118 @@
                 filesFound.keySet().toArray());
     }
 
+    @Test
+    public void testMethodInjection() throws IOException, LogAbortException,
+            ClassNotFoundException, IllegalAccessException, InstantiationException,
+            NoSuchMethodException, InvocationTargetException {
+        ICreateInfo ci = new ICreateInfo() {
+            @Override
+            public Class<?>[] getInjectedClasses() {
+                return new Class<?>[0];
+            }
+
+            @Override
+            public String[] getDelegateMethods() {
+                return new String[0];
+            }
+
+            @Override
+            public String[] getDelegateClassNatives() {
+                return new String[0];
+            }
+
+            @Override
+            public String[] getOverriddenMethods() {
+                // methods to force override
+                return new String[0];
+            }
+
+            @Override
+            public String[] getRenamedClasses() {
+                // classes to rename (so that we can replace them)
+                return new String[0];
+            }
+
+            @Override
+            public String[] getJavaPkgClasses() {
+                // classes to refactor (so that we can replace them)
+                return new String[0];
+            }
+
+            @Override
+            public Set<String> getExcludedClasses() {
+                return new HashSet<String>(0);
+            }
+
+            @Override
+            public String[] getDeleteReturns() {
+                // methods deleted from their return type.
+                return new String[0];
+            }
+
+            @Override
+            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+                HashMap<String, InjectMethodRunnable> map =
+                        new HashMap<String, InjectMethodRunnable>(1);
+                map.put("mock_android.util.EmptyArray",
+                        InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER);
+                return map;
+            }
+        };
+
+        AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
+        AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
+                null,                 // derived from
+                new String[] {        // include classes
+                        "**"
+                },
+                ci.getExcludedClasses(),
+                new String[] {        /* include files */
+                        "mock_android/data/data*"
+                });
+        aa.analyze();
+        agen.generate();
+        Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
+        Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+        parseZip(mOsDestJar, output, filesFound);
+        final String modifiedClass = "mock_android.util.EmptyArray";
+        final String modifiedClassPath = modifiedClass.replace('.', '/').concat(".class");
+        ZipFile zipFile = new ZipFile(mOsDestJar);
+        ZipEntry entry = zipFile.getEntry(modifiedClassPath);
+        assertNotNull(entry);
+        final byte[] bytes;
+        final InputStream inputStream = zipFile.getInputStream(entry);
+        try {
+            bytes = getByteArray(inputStream);
+        } finally {
+            inputStream.close();
+        }
+        ClassLoader classLoader = new ClassLoader(getClass().getClassLoader()) {
+            @Override
+            protected Class<?> findClass(String name) throws ClassNotFoundException {
+                if (name.equals(modifiedClass)) {
+                    return defineClass(null, bytes, 0, bytes.length);
+                }
+                throw new ClassNotFoundException(name + " not found.");
+            }
+        };
+        Class<?> emptyArrayClass = classLoader.loadClass(modifiedClass);
+        Object emptyArrayInstance = emptyArrayClass.newInstance();
+        Method method = emptyArrayClass.getMethod("getFrameworkClassLoader");
+        Object cl = method.invoke(emptyArrayInstance);
+        assertEquals(classLoader, cl);
+    }
+
+    private static byte[] getByteArray(InputStream stream) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int read;
+        while ((read = stream.read(buffer, 0, buffer.length)) > -1) {
+            bos.write(buffer, 0, read);
+        }
+        return bos.toByteArray();
+    }
+
     private void parseZip(String jarPath,
             Map<String, ClassReader> classes,
             Map<String, InputStream> filesFound) throws IOException {