Merge "media: use blocks number to find closest size" into mnc-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 65214b8..37b1d7b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -141,6 +141,7 @@
     field public static final java.lang.String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
     field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
+    field public static final java.lang.String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
     field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
     field public static final java.lang.String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
     field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index 3e4a66d..9c401c7f 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -138,7 +138,9 @@
                     new AccountAuthenticatorResponse(response),
                         accountType, authTokenType, features, options);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "addAccount: result " + AccountManager.sanitizeResult(result));
                 }
                 if (result != null) {
@@ -160,7 +162,9 @@
                 final Bundle result = AbstractAccountAuthenticator.this.confirmCredentials(
                     new AccountAuthenticatorResponse(response), account, options);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "confirmCredentials: result "
                             + AccountManager.sanitizeResult(result));
                 }
@@ -185,7 +189,9 @@
                 result.putString(AccountManager.KEY_AUTH_TOKEN_LABEL,
                         AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "getAuthTokenLabel: result "
                             + AccountManager.sanitizeResult(result));
                 }
@@ -209,7 +215,9 @@
                         new AccountAuthenticatorResponse(response), account,
                         authTokenType, loginOptions);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "getAuthToken: result " + AccountManager.sanitizeResult(result));
                 }
                 if (result != null) {
@@ -234,7 +242,10 @@
                     new AccountAuthenticatorResponse(response), account,
                         authTokenType, loginOptions);
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                    result.keySet(); // force it to be unparcelled
+                    // Result may be null.
+                    if (result != null) {
+                        result.keySet(); // force it to be unparcelled
+                    }
                     Log.v(TAG, "updateCredentials: result "
                             + AccountManager.sanitizeResult(result));
                 }
@@ -490,7 +501,7 @@
      * <ul>
      * <li> {@link AccountManager#KEY_INTENT}, or
      * <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
-     * the account that was added, or
+     * the account whose credentials were updated, or
      * <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
      * indicate an error
      * </ul>
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 9394d2c..8c84b4d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -333,7 +333,7 @@
         try {
             return mService.getPassword(account);
         } catch (RemoteException e) {
-            // will never happen
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
@@ -362,7 +362,7 @@
         try {
             return mService.getUserData(account, key);
         } catch (RemoteException e) {
-            // will never happen
+            // won't ever happen
             throw new RuntimeException(e);
         }
     }
@@ -415,8 +415,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * @return An array of {@link Account}, one for each account.  Empty
      *     (never null) if no accounts have been added.
@@ -438,8 +440,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * @return An array of {@link Account}, one for each account.  Empty
      *     (never null) if no accounts have been added.
@@ -466,7 +470,7 @@
         try {
             return mService.getAccountsForPackage(packageName, uid);
         } catch (RemoteException re) {
-            // possible security exception
+            // won't ever happen
             throw new RuntimeException(re);
         }
     }
@@ -483,7 +487,7 @@
         try {
             return mService.getAccountsByTypeForPackage(type, packageName);
         } catch (RemoteException re) {
-            // possible security exception
+            // won't ever happen
             throw new RuntimeException(re);
         }
     }
@@ -497,9 +501,10 @@
      *
      * <p>It is safe to call this method from the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
-     * authenticator that owns the account type.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
      * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
@@ -585,7 +590,8 @@
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
      * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
+     * match with the AbstractAccountAuthenticator that manages the account.
      *
      * @param account The {@link Account} to test
      * @param features An array of the account features to check
@@ -628,9 +634,10 @@
      * <p>This method may be called from any thread, but the returned
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
-     * authenticator that owns the account type.
+     * <p>Clients of this method that have not been granted the
+     * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
+     * will only see those accounts managed by AbstractAccountAuthenticators whose
+     * signature matches the client.
      *
      * @param type The type of accounts to return, must not be null
      * @param features An array of the account features to require,
@@ -701,7 +708,7 @@
         try {
             return mService.addAccountExplicitly(account, password, userdata);
         } catch (RemoteException e) {
-            // won't ever happen
+            // Can happen if there was a SecurityException was thrown.
             throw new RuntimeException(e);
         }
     }
@@ -966,7 +973,7 @@
         try {
             return mService.removeAccountExplicitly(account);
         } catch (RemoteException e) {
-            // won't ever happen
+            // May happen if the caller doesn't match the signature of the authenticator.
             throw new RuntimeException(e);
         }
     }
@@ -1114,7 +1121,7 @@
         try {
             mService.setUserData(account, key, value);
         } catch (RemoteException e) {
-            // won't ever happen
+            // Will happen if there is not signature match.
             throw new RuntimeException(e);
         }
     }
@@ -1733,7 +1740,7 @@
      *     with these fields if an activity was supplied and the account
      *     credentials were successfully updated:
      * <ul>
-     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
+     * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
      * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
      * </ul>
      *
@@ -2501,10 +2508,12 @@
      * listeners are added in an Activity or Service's {@link Activity#onCreate}
      * and removed in {@link Activity#onDestroy}.
      *
-     * <p>It is safe to call this method from the main thread.
+     * <p>The listener will only be informed of accounts that would be returned
+     * to the caller via {@link #getAccounts()}. Typically this means that to
+     * get any accounts, the caller will need to be grated the GET_ACCOUNTS
+     * permission.
      *
-     * <p>This method requires the caller to hold the permission
-     * {@link android.Manifest.permission#GET_ACCOUNTS}.
+     * <p>It is safe to call this method from the main thread.
      *
      * @param listener The listener to send notifications to
      * @param handler {@link Handler} identifying the thread to use
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ecb7f5a..80169a9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2615,7 +2615,9 @@
                 getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000,
                 powerSaveModeEnabledTime / 1000, connChanges, deviceIdleModeEnabledTime / 1000,
                 getDeviceIdleModeEnabledCount(which), deviceIdlingTime / 1000,
-                getDeviceIdlingCount(which));
+                getDeviceIdlingCount(which),
+                getMobileRadioActiveCount(which),
+                getMobileRadioActiveUnknownTime(which) / 1000);
         
         // Dump screen brightness stats
         Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1f49929..1f47ce3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -961,9 +961,7 @@
         android:label="@string/permlab_changeWimaxState"
         android:protectionLevel="normal" />
 
-    <!--@SystemApi Allows applications to the the local WiFi and Bluetooth MAC address.
-        @hide
-    -->
+    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
     <permission android:name="android.permission.SCORE_NETWORKS"
         android:protectionLevel="signature|privileged" />
 
@@ -2583,10 +2581,16 @@
     <permission android:name="android.permission.KILL_UID"
                 android:protectionLevel="signature|installer" />
 
-    <!-- Allows applications to act as network scorers. @hide @SystemApi-->
+    <!-- @SystemApi Allows applications to read the local WiFi and Bluetooth MAC address.
+        @hide -->
     <permission android:name="android.permission.LOCAL_MAC_ADDRESS"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
+        @hide -->
+    <permission android:name="android.permission.PEERS_MAC_ADDRESS"
+                android:protectionLevel="signature" />
+
     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
         can use this permission to ensure incoming Nfc messages are from the Nfc stack
         and not simulated by another application.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 94ed8b4..56cc44c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -18,16 +18,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.IBinder;
 import android.security.KeyStore;
-import android.security.KeyStoreException;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
 import java.security.AlgorithmParameters;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
@@ -103,91 +98,6 @@
         protected final int getAdditionalEntropyAmountForFinish() {
             return 0;
         }
-
-        @Override
-        @NonNull
-        protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
-                KeyStore keyStore, IBinder operationToken) {
-            if (isEncrypting()) {
-                // KeyStore's RSA encryption without padding expects the input to be of the same
-                // length as the modulus. We thus have to buffer all input to pad it with leading
-                // zeros.
-                return new ZeroPaddingEncryptionStreamer(
-                        super.createMainDataStreamer(keyStore, operationToken),
-                        getModulusSizeBytes());
-            } else {
-                return super.createMainDataStreamer(keyStore, operationToken);
-            }
-        }
-
-        /**
-         * Streamer which buffers all plaintext input, then pads it with leading zeros to match
-         * modulus size, and then sends it into KeyStore to obtain ciphertext.
-         */
-        private static class ZeroPaddingEncryptionStreamer
-                implements KeyStoreCryptoOperationStreamer {
-
-            private final KeyStoreCryptoOperationStreamer mDelegate;
-            private final int mModulusSizeBytes;
-            private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
-            private long mConsumedInputSizeBytes;
-
-            private ZeroPaddingEncryptionStreamer(
-                    KeyStoreCryptoOperationStreamer delegate,
-                    int modulusSizeBytes) {
-                mDelegate = delegate;
-                mModulusSizeBytes = modulusSizeBytes;
-            }
-
-            @Override
-            public byte[] update(byte[] input, int inputOffset, int inputLength)
-                    throws KeyStoreException {
-                if (inputLength > 0) {
-                    mInputBuffer.write(input, inputOffset, inputLength);
-                    mConsumedInputSizeBytes += inputLength;
-                }
-                return EmptyArray.BYTE;
-            }
-
-            @Override
-            public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
-                    byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
-                if (inputLength > 0) {
-                    mConsumedInputSizeBytes += inputLength;
-                    mInputBuffer.write(input, inputOffset, inputLength);
-                }
-                byte[] bufferedInput = mInputBuffer.toByteArray();
-                mInputBuffer.reset();
-                byte[] paddedInput;
-                if (bufferedInput.length < mModulusSizeBytes) {
-                    // Pad input with leading zeros
-                    paddedInput = new byte[mModulusSizeBytes];
-                    System.arraycopy(
-                            bufferedInput, 0,
-                            paddedInput,
-                            paddedInput.length - bufferedInput.length,
-                            bufferedInput.length);
-                } else {
-                    // RI throws BadPaddingException in this scenario. INVALID_ARGUMENT below will
-                    // be translated into BadPaddingException.
-                    throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT,
-                            "Message size (" + bufferedInput.length + " bytes) must be smaller than"
-                            + " modulus (" + mModulusSizeBytes + " bytes)");
-                }
-                return mDelegate.doFinal(paddedInput, 0, paddedInput.length, signature,
-                        additionalEntropy);
-            }
-
-            @Override
-            public long getConsumedInputSizeBytes() {
-                return mConsumedInputSizeBytes;
-            }
-
-            @Override
-            public long getProducedOutputSizeBytes() {
-                return mDelegate.getProducedOutputSizeBytes();
-            }
-        }
     }
 
     /**
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index 92a057d..319cfe4 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -60,8 +60,14 @@
 }
 
 void Stencil::clear() {
+    glStencilMask(0xff);
     glClearStencil(0);
     glClear(GL_STENCIL_BUFFER_BIT);
+
+    if (mState == kTest) {
+        // reset to test state, with immutable stencil
+        glStencilMask(0);
+    }
 }
 
 void Stencil::enableTest(int incrementThreshold) {
@@ -104,17 +110,17 @@
     // We only want to test, let's keep everything
     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
     mState = kTest;
+    glStencilMask(0);
 }
 
 void Stencil::enableDebugWrite() {
-    if (mState != kWrite) {
-        enable();
-        glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
-        // The test always passes so the first two values are meaningless
-        glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
-        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-        mState = kWrite;
-    }
+    enable();
+    glStencilFunc(GL_ALWAYS, 0x1, 0xffffffff);
+    // The test always passes so the first two values are meaningless
+    glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
+    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+    mState = kWrite;
+    glStencilMask(0xff);
 }
 
 void Stencil::enable() {
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index 93fb6d2..e1990cd 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -113,8 +113,13 @@
     /**
      * Called to open a {@link MidiInputPort} for the specified port number.
      *
+     * An input port can only be used by one sender at a time.
+     * Opening an input port will fail if another application has already opened it for use.
+     * A {@link MidiDeviceStatus} can be used to determine if an input port is already open.
+     *
      * @param portNumber the number of the input port to open
-     * @return the {@link MidiInputPort}
+     * @return the {@link MidiInputPort} if the open is successful,
+     *         or null in case of failure.
      */
     public MidiInputPort openInputPort(int portNumber) {
         try {
@@ -133,8 +138,11 @@
     /**
      * Called to open a {@link MidiOutputPort} for the specified port number.
      *
+     * An output port may be opened by multiple applications.
+     *
      * @param portNumber the number of the output port to open
-     * @return the {@link MidiOutputPort}
+     * @return the {@link MidiOutputPort} if the open is successful,
+     *         or null in case of failure.
      */
     public MidiOutputPort openOutputPort(int portNumber) {
         try {
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 673c4ba..7baa5bc 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -31,7 +31,7 @@
   <li> Timestamps to avoid jitter.</li>
   <li> Support creation of <em>virtual MIDI devices</em> that can be connected to other devices.
   An example might be a synthesizer app that can be controlled by a composing app.</li>
-  <li> Support direction connection or &ldquo;patching&rdquo; of devices for lower latency.</li>
+  <li> Support direct connection or &ldquo;patching&rdquo; of devices for lower latency.</li>
 </ul>
 
 <h2 id=transports_supported>Transports Supported</h2>
@@ -75,6 +75,18 @@
 &lt;uses-feature android:name="android.software.midi" android:required="true"/>
 </pre>
 
+<h2 id=check_feature>Check for Feature Support</h2>
+
+<p>An app can also check at run-time whether the MIDI feature is supported on a platform.
+This is particularly useful during development when you install apps directly on a device.
+</p>
+
+<pre class=prettyprint>
+if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+    // do MIDI stuff
+}
+</pre>
+
 <h2 id=the_midimanager>The MidiManager</h2>
 
 
@@ -338,5 +350,54 @@
     }
 }
 </pre>
+
+<h1 id=using_midi_btle>Using MIDI Over Bluetooth LE</h1>
+
+<p>MIDI devices can be connected to Android using Bluetooth LE.</p>
+
+<p>Before using the device, the app must scan for available BTLE devices and then allow
+the user to connect. An example program
+will be provided so look for it on the Android developer website.</p>
+
+<h2 id=btle_location_permissions>Request Location Permission for BTLE</h2>
+
+<p>Applications that scan for Bluetooth devices must request permission in the
+manifest file. This LOCATION permission is required because it may be possible to
+guess the location of an Android device by seeing which BTLE devices are nearby.</p>
+
+<pre class=prettyprint>
+&lt;uses-permission android:name="android.permission.BLUETOOTH"/>
+&lt;uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+&lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+</pre>
+
+<p>Apps must also request location permission from the user at run-time.
+See the documentation for <code>Activity.requestPermissions()</code> for details and an example.
+</p>
+
+<h2 id=btle_scan_devices>Scan for MIDI Devices</h2>
+
+<p>The app will only want to see MIDI devices and not mice or other non-MIDI devices.
+So construct a ScanFilter using the UUID for standard MIDI over BTLE.</p>
+
+<pre class=prettyprint>
+MIDI over BTLE UUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700"
+</pre>
+
+<h2 id=btle_open_device>Open a MIDI Bluetooth Device</h2>
+
+<p>See the documentation for <code>android.bluetooth.le.BluetoothLeScanner.startScan()</code>
+method for details. When the user selects a MIDI/BTLE device then you can open it
+using the MidiManager.</p>
+
+<pre class=prettyprint>
+m.openBluetoothDevice(bluetoothDevice, callback, handler);
+</pre>
+
+<p>Once the MIDI/BTLE device has been opened by one app then it will also become available to other
+apps using the
+<a href="#get_list_of_already_plugged_in_entities">MIDI device discovery calls described above</a>.
+</p>
+
 </body>
 </html>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 4f0c6a41..393771a 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -162,7 +162,11 @@
                 if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
                     root.flags |= Root.FLAG_HAS_SETTINGS;
                 }
-                root.visiblePath = volume.getPathForUser(userId);
+                if (volume.isVisibleForRead(userId)) {
+                    root.visiblePath = volume.getPathForUser(userId);
+                } else {
+                    root.visiblePath = null;
+                }
                 root.path = volume.getInternalPathForUser(userId);
                 root.docId = getDocIdForFile(root.path);
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index ea2cc51..bbef259 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -60,7 +60,7 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
-
+    <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
     <!-- Physical hardware -->
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 6d84727..8eef23e 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -49,5 +49,6 @@
 
     <!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
     <item type="id" name="icon_is_grayscale" />
+    <item type="id" name="is_clicked_heads_up_tag" />
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 9c37263..00fa653 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1525,6 +1525,7 @@
                         //
                         // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
                         // become canceled shortly by NoMan, but we can't assume that.
+                        HeadsUpManager.setIsClickedNotification(row, true);
                         mHeadsUpManager.releaseImmediately(notificationKey);
                     }
                     new Thread() {
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 f8bd793..17fd7a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -32,7 +32,6 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 import android.view.accessibility.AccessibilityEvent;
@@ -203,10 +202,12 @@
     private int mPositionMinSideMargin;
     private int mLastOrientation = -1;
     private boolean mClosingWithAlphaFadeOut;
+    private boolean mHeadsUpAnimatingAway;
 
     private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
         @Override
         public void run() {
+            mHeadsUpAnimatingAway = false;
             notifyBarPanelExpansionChanged();
         }
     };
@@ -2292,6 +2293,7 @@
             mHeadsUpExistenceChangedRunnable.run();
             updateNotificationTranslucency();
         } else {
+            mHeadsUpAnimatingAway = true;
             mNotificationStackScroller.runAfterAnimationFinished(
                     mHeadsUpExistenceChangedRunnable);
         }
@@ -2382,4 +2384,8 @@
     public void clearNotificattonEffects() {
         mStatusBar.clearNotificationEffects();
     }
+
+    protected boolean isPanelVisibleBecauseOfHeadsUp() {
+        return mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0d20d52..8b25e08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1009,10 +1009,12 @@
 
     protected void notifyBarPanelExpansionChanged() {
         mBar.panelExpansionChanged(this, mExpandedFraction, mExpandedFraction > 0f || mPeekPending
-                || mPeekAnimator != null || mInstantExpanding || mHeadsUpManager.hasPinnedHeadsUp()
+                || mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
                 || mTracking || mHeightAnimator != null);
     }
 
+    protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
+
     /**
      * Gets called when the user performs a click anywhere in the empty area of the panel.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 63f5711..ed9b123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -51,6 +51,7 @@
     private static final String TAG = "HeadsUpManager";
     private static final boolean DEBUG = false;
     private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
+    private static final int TAG_CLICKED_NOTIFICATION = R.id.is_clicked_heads_up_tag;
 
     private final int mHeadsUpNotificationDecay;
     private final int mMinimumDisplayTime;
@@ -452,8 +453,8 @@
             for (NotificationData.Entry entry : mEntriesToRemoveAfterExpand) {
                 removeHeadsUpEntry(entry);
             }
-            mEntriesToRemoveAfterExpand.clear();
         }
+        mEntriesToRemoveAfterExpand.clear();
     }
 
     public void setTrackingHeadsUp(boolean trackingHeadsUp) {
@@ -526,6 +527,15 @@
         });
     }
 
+    public static void setIsClickedNotification(View child, boolean clicked) {
+        child.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null);
+    }
+
+    public static boolean isClickedHeadsUpNotification(View child) {
+        Boolean clicked = (Boolean) child.getTag(TAG_CLICKED_NOTIFICATION);
+        return clicked != null && clicked;
+    }
+
     /**
      * This represents a notification and how long it is in a heads up mode. It also manages its
      * lifecycle automatically when created.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 0d89b21..23d9b9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -222,6 +222,7 @@
     private int[] mTempInt2 = new int[2];
     private boolean mGenerateChildOrderChangedEvent;
     private HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
+    private HashSet<View> mClearOverlayViewsWhenFinished = new HashSet<>();
     private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
             = new HashSet<>();
     private HeadsUpManager mHeadsUpManager;
@@ -1656,6 +1657,11 @@
             mAddedHeadsUpChildren.remove(child);
             return false;
         }
+        if (isClickedHeadsUp(child)) {
+            // An animation is already running, add it to the Overlay
+            mClearOverlayViewsWhenFinished.add(child);
+            return true;
+        }
         if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
             if (!mChildrenToAddAnimated.contains(child)) {
                 // Generate Animations
@@ -1671,6 +1677,10 @@
         return false;
     }
 
+    private boolean isClickedHeadsUp(View child) {
+        return HeadsUpManager.isClickedHeadsUpNotification(child);
+    }
+
     /**
      * Remove a removed child view from the heads up animations if it was just added there
      *
@@ -2327,6 +2337,13 @@
     public void onChildAnimationFinished() {
         requestChildrenUpdate();
         runAnimationFinishedRunnables();
+        clearViewOverlays();
+    }
+
+    private void clearViewOverlays() {
+        for (View view : mClearOverlayViewsWhenFinished) {
+            getOverlay().remove(view);
+        }
     }
 
     private void runAnimationFinishedRunnables() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 5b8fe89..97c7d30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -670,6 +671,7 @@
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
+                HeadsUpManager.setIsClickedNotification(child, false);
                 child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
                 child.setTag(TAG_START_TRANSLATION_Y, null);
                 child.setTag(TAG_END_TRANSLATION_Y, null);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index b9f62e6..10a4cd1 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -805,6 +805,7 @@
         IBinder mService;
         ComponentName mClassName;
         Intent mIntent;
+        boolean mInvokingProxyCallbacks = false;
 
         ProfileServiceConnections(Intent intent) {
             mService = null;
@@ -871,34 +872,54 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to linkToDeath", e);
             }
-            int n = mProxies.beginBroadcast();
-            for (int i = 0; i < n; i++) {
-                try {
-                    mProxies.getBroadcastItem(i).onServiceConnected(className, service);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Unable to connect to proxy", e);
-                }
+
+            if (mInvokingProxyCallbacks) {
+                Log.e(TAG, "Proxy callbacks already in progress.");
+                return;
             }
-            mProxies.finishBroadcast();
+            mInvokingProxyCallbacks = true;
+
+            final int n = mProxies.beginBroadcast();
+            try {
+                for (int i = 0; i < n; i++) {
+                    try {
+                        mProxies.getBroadcastItem(i).onServiceConnected(className, service);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Unable to connect to proxy", e);
+                    }
+                }
+            } finally {
+                mProxies.finishBroadcast();
+                mInvokingProxyCallbacks = false;
+            }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName className) {
-            if (mService == null) {
-                return;
-            }
+            if (mService == null) return;
             mService.unlinkToDeath(this, 0);
             mService = null;
             mClassName = null;
-            int n = mProxies.beginBroadcast();
-            for (int i = 0; i < n; i++) {
-                try {
-                    mProxies.getBroadcastItem(i).onServiceDisconnected(className);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Unable to disconnect from proxy", e);
-                }
+
+            if (mInvokingProxyCallbacks) {
+                Log.e(TAG, "Proxy callbacks already in progress.");
+                return;
             }
-            mProxies.finishBroadcast();
+            mInvokingProxyCallbacks = true;
+
+            final int n = mProxies.beginBroadcast();
+            try {
+                for (int i = 0; i < n; i++) {
+                    try {
+                        mProxies.getBroadcastItem(i).onServiceDisconnected(className);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Unable to disconnect from proxy", e);
+                    }
+                }
+            } finally {
+                mProxies.finishBroadcast();
+                mInvokingProxyCallbacks = false;
+            }
         }
 
         @Override
@@ -916,16 +937,19 @@
     }
 
     private void sendBluetoothStateCallback(boolean isUp) {
-        int n = mStateChangeCallbacks.beginBroadcast();
-        if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
-        for (int i=0; i <n;i++) {
-            try {
-                mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+        try {
+            int n = mStateChangeCallbacks.beginBroadcast();
+            if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
+            for (int i=0; i <n;i++) {
+                try {
+                    mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
+                }
             }
+        } finally {
+            mStateChangeCallbacks.finishBroadcast();
         }
-        mStateChangeCallbacks.finishBroadcast();
     }
 
     /**
@@ -934,16 +958,19 @@
     private void sendBluetoothServiceUpCallback() {
         if (!mConnection.isGetNameAddressOnly()) {
             if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
-            int n = mCallbacks.beginBroadcast();
-            Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
-            for (int i=0; i <n;i++) {
-                try {
-                    mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
-                }  catch (RemoteException e) {
-                    Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
+            try {
+                int n = mCallbacks.beginBroadcast();
+                Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
+                for (int i=0; i <n;i++) {
+                    try {
+                        mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
+                    }  catch (RemoteException e) {
+                        Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
+                    }
                 }
+            } finally {
+                mCallbacks.finishBroadcast();
             }
-            mCallbacks.finishBroadcast();
         }
     }
     /**
@@ -952,16 +979,19 @@
     private void sendBluetoothServiceDownCallback() {
         if (!mConnection.isGetNameAddressOnly()) {
             if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
-            int n = mCallbacks.beginBroadcast();
-            Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
-            for (int i=0; i <n;i++) {
-                try {
-                    mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
-                }  catch (RemoteException e) {
-                    Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
+            try {
+                int n = mCallbacks.beginBroadcast();
+                Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
+                for (int i=0; i <n;i++) {
+                    try {
+                        mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
+                    }  catch (RemoteException e) {
+                        Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
+                    }
                 }
+            } finally {
+                mCallbacks.finishBroadcast();
             }
-            mCallbacks.finishBroadcast();
         }
     }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a06bb30..19a4851 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -362,10 +362,10 @@
         }
 
         try {
-            mContext.enforceCallingPermission(
+            mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
                     "addOnSubscriptionsChangedListener");
-            // SKIP checking for run-time permission since obtained PRIVILEGED
+            // SKIP checking for run-time permission since caller or self has PRIVILEGED permission
         } catch (SecurityException e) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PHONE_STATE,
@@ -481,9 +481,10 @@
 
             if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
                 try {
-                    mContext.enforceCallingPermission(
+                    mContext.enforceCallingOrSelfPermission(
                             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
-                    // SKIP checking for run-time permission since obtained PRIVILEGED
+                    // SKIP checking for run-time permission since caller or self has PRIVILEGED
+                    // permission
                 } catch (SecurityException e) {
                     if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
                             callingPackage) != AppOpsManager.MODE_ALLOWED) {
@@ -661,10 +662,10 @@
     }
 
     private boolean canReadPhoneState(String callingPackage) {
-        if (mContext.checkCallingPermission(
+        if (mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) ==
                 PackageManager.PERMISSION_GRANTED) {
-            // SKIP checking for run-time permission since obtained PRIVILEGED
+            // SKIP checking for run-time permission since caller or self has PRIVILEGED permission
             return true;
         }
         boolean canReadPhoneState = mContext.checkCallingOrSelfPermission(
@@ -1589,9 +1590,10 @@
 
         if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
             try {
-                mContext.enforceCallingPermission(
+                mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
-                // SKIP checking for run-time permission since obtained PRIVILEGED
+                // SKIP checking for run-time permission since caller or self has PRIVILEGED
+                // permission
             } catch (SecurityException e) {
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.READ_PHONE_STATE, null);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 32fd56a..83e8db0 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -527,14 +527,14 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot get secrets for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -627,14 +627,14 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         if (key == null) throw new IllegalArgumentException("key is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot get user data for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -664,22 +664,32 @@
 
         final long identityToken = clearCallingIdentity();
         try {
-            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
-                    authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
-            AuthenticatorDescription[] types =
-                    new AuthenticatorDescription[authenticatorCollection.size()];
-            int i = 0;
-            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
-                    : authenticatorCollection) {
-                types[i] = authenticator.type;
-                i++;
-            }
-            return types;
+            return getAuthenticatorTypesInternal(userId);
+
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    /**
+     * Should only be called inside of a clearCallingIdentity block.
+     */
+    private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
+        Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
+                authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
+        AuthenticatorDescription[] types =
+                new AuthenticatorDescription[authenticatorCollection.size()];
+        int i = 0;
+        for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
+                : authenticatorCollection) {
+            types[i] = authenticator.type;
+            i++;
+        }
+        return types;
+    }
+
+
+
     private boolean isCrossUser(int callingUid, int userId) {
         return (userId != UserHandle.getCallingUserId()
                 && callingUid != Process.myUid()
@@ -697,7 +707,8 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot explicitly add accounts of type: %s",
                     callingUid,
@@ -713,12 +724,10 @@
          */
 
         // fails if the account already exists
-        int uid = getCallingUid();
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
-            return addAccountInternal(accounts, account, password, extras, false, uid);
+            return addAccountInternal(accounts, account, password, extras, false, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -794,25 +803,26 @@
         if (account == null) {
             throw new IllegalArgumentException("account is null");
         }
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot notify authentication for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = Binder.getCallingUserHandle().getIdentifier();
+
         if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
             return false;
         }
-        int user = UserHandle.getCallingUserId();
+
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(user);
+            UserAccounts accounts = getUserAccounts(userId);
+            return updateLastAuthenticatedTime(account);
         } finally {
             restoreCallingIdentity(identityToken);
         }
-        return updateLastAuthenticatedTime(account);
     }
 
     private boolean updateLastAuthenticatedTime(Account account) {
@@ -985,8 +995,9 @@
         if (response == null) throw new IllegalArgumentException("response is null");
         if (account == null) throw new IllegalArgumentException("account is null");
         if (features == null) throw new IllegalArgumentException("features is null");
-        checkReadAccountsPermitted(callingUid, account.type);
         int userId = UserHandle.getCallingUserId();
+        checkReadAccountsPermitted(callingUid, account.type, userId);
+
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1062,14 +1073,14 @@
                 + ", pid " + Binder.getCallingPid());
         }
         if (accountToRename == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(accountToRename.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot rename accounts of type: %s",
                     callingUid,
                     accountToRename.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1211,14 +1222,15 @@
          * authenticator.  This will let users remove accounts (via Settings in the system) but not
          * arbitrary applications (like competing authenticators).
          */
-        if (!isAccountManagedByCaller(account.type, callingUid) && !isSystemUid(callingUid)) {
+        UserHandle user = new UserHandle(userId);
+        if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
+                && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot remove accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-
         if (!canUserModifyAccounts(userId)) {
             try {
                 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
@@ -1235,10 +1247,7 @@
             }
             return;
         }
-
-        UserHandle user = new UserHandle(userId);
         long identityToken = clearCallingIdentity();
-
         UserAccounts accounts = getUserAccounts(userId);
         cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
         synchronized(accounts.credentialsPermissionNotificationIds) {
@@ -1268,6 +1277,7 @@
                     + ", caller's uid " + callingUid
                     + ", pid " + Binder.getCallingPid());
         }
+        int userId = Binder.getCallingUserHandle().getIdentifier();
         if (account == null) {
             /*
              * Null accounts should result in returning false, as per
@@ -1275,22 +1285,18 @@
              */
             Log.e(TAG, "account is null");
             return false;
-        } else if (!isAccountManagedByCaller(account.type, callingUid)) {
+        } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot explicitly add accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-
         UserAccounts accounts = getUserAccountsForCaller();
-        int userId = Binder.getCallingUserHandle().getIdentifier();
         if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
             return false;
         }
-
         logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
-
         long identityToken = clearCallingIdentity();
         try {
             return removeAccountInternal(accounts, account);
@@ -1524,14 +1530,14 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot peek the authtokens associated with accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1552,14 +1558,14 @@
         }
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot set auth tokens associated with accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1578,14 +1584,14 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot set secrets for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1642,14 +1648,14 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot clear passwords for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1670,14 +1676,14 @@
         }
         if (key == null) throw new IllegalArgumentException("key is null");
         if (account == null) throw new IllegalArgumentException("account is null");
-        if (!isAccountManagedByCaller(account.type, callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
             String msg = String.format(
                     "uid %s cannot set user data for accounts of type: %s",
                     callingUid,
                     account.type);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -1840,8 +1846,8 @@
 
         // skip the check if customTokens
         final int callerUid = Binder.getCallingUid();
-        final boolean permissionGranted = customTokens ||
-            permissionIsGranted(account, authTokenType, callerUid);
+        final boolean permissionGranted =
+                customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
 
         // Get the calling package. We will use it for the purpose of caching.
         final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
@@ -2363,14 +2369,14 @@
         }
         if (response == null) throw new IllegalArgumentException("response is null");
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
-        if (!isAccountManagedByCaller(accountType, callingUid) && !isSystemUid(callingUid)) {
+        int userId = UserHandle.getCallingUserId();
+        if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
             String msg = String.format(
                     "uid %s cannot edit authenticator properites for account type: %s",
                     callingUid,
                     accountType);
             throw new SecurityException(msg);
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts accounts = getUserAccounts(userId);
@@ -2493,20 +2499,22 @@
     }
 
     /**
-     * Returns the accounts for a specific user
+     * Returns the accounts visible to the client within the context of a specific user
      * @hide
      */
     public Account[] getAccounts(int userId) {
         int callingUid = Binder.getCallingUid();
-        if (!isReadAccountsPermitted(callingUid, null)) {
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        if (visibleAccountTypes.isEmpty()) {
             return new Account[0];
         }
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(userId);
-            synchronized (accounts.cacheLock) {
-                return getAccountsFromCacheLocked(accounts, null, callingUid, null);
-            }
+            return getAccountsInternal(
+                    userId,
+                    callingUid,
+                    null,  // packageName
+                    visibleAccountTypes);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -2588,22 +2596,52 @@
             callingUid = packageUid;
         }
 
-        // Authenticators should be able to see their own accounts regardless of permissions.
-        if (TextUtils.isEmpty(type) && !isReadAccountsPermitted(callingUid, type)) {
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        if (visibleAccountTypes.isEmpty()
+                || (type != null && !visibleAccountTypes.contains(type))) {
             return new Account[0];
-        }
+        } else if (visibleAccountTypes.contains(type)) {
+            // Prune the list down to just the requested type.
+            visibleAccountTypes = new ArrayList<>();
+            visibleAccountTypes.add(type);
+        } // else aggregate all the visible accounts (it won't matter if the list is empty).
 
         long identityToken = clearCallingIdentity();
         try {
-            UserAccounts accounts = getUserAccounts(userId);
-            synchronized (accounts.cacheLock) {
-                return getAccountsFromCacheLocked(accounts, type, callingUid, callingPackage);
-            }
+            return getAccountsInternal(
+                    userId,
+                    callingUid,
+                    callingPackage,
+                    visibleAccountTypes);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    private Account[] getAccountsInternal(
+            int userId,
+            int callingUid,
+            String callingPackage,
+            List<String> visibleAccountTypes) {
+        UserAccounts accounts = getUserAccounts(userId);
+        synchronized (accounts.cacheLock) {
+            UserAccounts userAccounts = getUserAccounts(userId);
+            ArrayList<Account> visibleAccounts = new ArrayList<>();
+            for (String visibleType : visibleAccountTypes) {
+                Account[] accountsForType = getAccountsFromCacheLocked(
+                        userAccounts, visibleType, callingUid, callingPackage);
+                if (accountsForType != null) {
+                    visibleAccounts.addAll(Arrays.asList(accountsForType));
+                }
+            }
+            Account[] result = new Account[visibleAccounts.size()];
+            for (int i = 0; i < visibleAccounts.size(); i++) {
+                result[i] = visibleAccounts.get(i);
+            }
+            return result;
+        }
+    }
+
     @Override
     public boolean addSharedAccountAsUser(Account account, int userId) {
         userId = handleIncomingUser(userId);
@@ -2739,8 +2777,12 @@
         }
         if (response == null) throw new IllegalArgumentException("response is null");
         if (type == null) throw new IllegalArgumentException("accountType is null");
-        if (!isReadAccountsPermitted(callingUid, type)) {
+        int userId = UserHandle.getCallingUserId();
+
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        if (!visibleAccountTypes.contains(type)) {
             Bundle result = new Bundle();
+            // Need to return just the accounts that are from matching signatures.
             result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
             try {
                 response.onResult(result);
@@ -2749,7 +2791,6 @@
             }
             return;
         }
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             UserAccounts userAccounts = getUserAccounts(userId);
@@ -2763,7 +2804,11 @@
                 onResult(response, result);
                 return;
             }
-            new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features,
+            new GetAccountsByTypeAndFeatureSession(
+                    userAccounts,
+                    response,
+                    type,
+                    features,
                     callingUid).bind();
         } finally {
             restoreCallingIdentity(identityToken);
@@ -3696,10 +3741,11 @@
         return false;
     }
 
-    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
+    private boolean permissionIsGranted(
+            Account account, String authTokenType, int callerUid, int userId) {
         final boolean isPrivileged = isPrivileged(callerUid);
         final boolean fromAuthenticator = account != null
-                && isAccountManagedByCaller(account.type, callerUid);
+                && isAccountManagedByCaller(account.type, callerUid, userId);
         final boolean hasExplicitGrants = account != null
                 && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -3711,23 +3757,45 @@
         return fromAuthenticator || hasExplicitGrants || isPrivileged;
     }
 
-    private boolean isAccountManagedByCaller(String accountType, int callingUid) {
+    private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId) {
         if (accountType == null) {
             return false;
+        } else {
+            return getTypesVisibleToCaller(callingUid, userId).contains(accountType);
         }
-        final int callingUserId = UserHandle.getUserId(callingUid);
+    }
+
+    private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
+        if (accountType == null) {
+            return false;
+        } else {
+            return getTypesManagedByCaller(callingUid, userId).contains(accountType);
+        }
+    }
+
+    private List<String> getTypesVisibleToCaller(int callingUid, int userId) {
+        boolean isPermitted =
+                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
+                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+        Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
+        return getTypesForCaller(callingUid, userId, isPermitted);
+    }
+
+    private List<String> getTypesManagedByCaller(int callingUid, int userId) {
+        return getTypesForCaller(callingUid, userId, false);
+    }
+
+    private List<String> getTypesForCaller(
+            int callingUid, int userId, boolean isOtherwisePermitted) {
+        List<String> managedAccountTypes = new ArrayList<>();
         for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
-                mAuthenticatorCache.getAllServices(callingUserId)) {
-            if (serviceInfo.type.type.equals(accountType)) {
-                /*
-                 * We can't simply compare uids because uids can be recycled before the
-                 * authenticator cache is updated.
-                 */
-                final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
-                return sigChk == PackageManager.SIGNATURE_MATCH;
+                mAuthenticatorCache.getAllServices(userId)) {
+            final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+            if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
+                managedAccountTypes.add(serviceInfo.type.type);
             }
         }
-        return false;
+        return managedAccountTypes;
     }
 
     private boolean isAccountPresentForCaller(String accountName, String accountType) {
@@ -3792,28 +3860,12 @@
         return false;
     }
 
-    private boolean isReadAccountsPermitted(int callingUid, String accountType) {
-        /*
-         * Settings app (which is in the same uid as AcocuntManagerService), apps with the
-         * GET_ACCOUNTS permission or authenticators that own the account type should be able to
-         * access accounts of the specified account.
-         */
-        boolean isPermitted =
-                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
-                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
-        boolean isAccountManagedByCaller = isAccountManagedByCaller(accountType, callingUid);
-        Log.w(TAG, String.format(
-                "isReadAccountPermitted: isPermitted: %s, isAM: %s",
-                isPermitted,
-                isAccountManagedByCaller));
-        return isPermitted || isAccountManagedByCaller;
-    }
-
     /** Succeeds if any of the specified permissions are granted. */
     private void checkReadAccountsPermitted(
             int callingUid,
-            String accountType) {
-        if (!isReadAccountsPermitted(callingUid, accountType)) {
+            String accountType,
+            int userId) {
+        if (!isAccountVisibleToCaller(accountType, callingUid, userId)) {
             String msg = String.format(
                     "caller uid %s cannot access %s accounts",
                     callingUid,
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index cd982d3..46bda8c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1668,8 +1668,9 @@
     public NetworkPolicy[] getNetworkPolicies(String callingPackage) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
         try {
-            mContext.enforceCallingPermission(READ_PRIVILEGED_PHONE_STATE, TAG);
-            // SKIP checking run-time OP_READ_PHONE_STATE since using PRIVILEGED
+            mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, TAG);
+            // SKIP checking run-time OP_READ_PHONE_STATE since caller or self has PRIVILEGED
+            // permission
         } catch (SecurityException e) {
             mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, TAG);
 
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 6278371..669b8e5 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -634,6 +634,7 @@
                     && doesPackageSupportRuntimePermissions(carrierPackage)) {
                 grantRuntimePermissionsLPw(carrierPackage, PHONE_PERMISSIONS, userId);
                 grantRuntimePermissionsLPw(carrierPackage, LOCATION_PERMISSIONS, userId);
+                grantRuntimePermissionsLPw(carrierPackage, SMS_PERMISSIONS, userId);
             }
         }
     }
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 97bf505..38ede87 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -128,7 +128,7 @@
             mReceiver = receiver;
         }
     }
-    
+
     public static UsbMidiDevice create(Context context, Bundle properties, int card, int device) {
         // FIXME - support devices with different number of input and output ports
         int subDeviceCount = nativeGetSubdeviceCount(card, device);
@@ -203,6 +203,8 @@
                 byte[] buffer = new byte[BUFFER_SIZE];
                 try {
                     while (true) {
+                        // Record time of event immediately after waking.
+                        long timestamp = System.nanoTime();
                         synchronized (mLock) {
                             if (!mIsOpen) break;
 
@@ -215,14 +217,14 @@
                                 } else if ((pfd.revents & OsConstants.POLLIN) != 0) {
                                     // clear readable flag
                                     pfd.revents = 0;
-                                    
+
                                     if (index == mInputStreams.length - 1) {
                                         // last file descriptor is used only for unblocking Os.poll()
                                         break;
                                     }
 
                                     int count = mInputStreams[index].read(buffer);
-                                    outputReceivers[index].send(buffer, 0, count);
+                                    outputReceivers[index].send(buffer, 0, count, timestamp);
                                 }
                             }
                         }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index e64fdf7..81642fa 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4466,6 +4466,37 @@
     return 0;
 }
 
+static bool shouldGenerateVersionedResource(const sp<ResourceTable::ConfigList>& configList,
+                                            const ConfigDescription& sourceConfig,
+                                            const int sdkVersionToGenerate) {
+    assert(sdkVersionToGenerate > sourceConfig.sdkVersion);
+    const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& entries
+            = configList->getEntries();
+    ssize_t idx = entries.indexOfKey(sourceConfig);
+
+    // The source config came from this list, so it should be here.
+    assert(idx >= 0);
+
+    idx += 1;
+    if (static_cast<size_t>(idx) >= entries.size()) {
+        // This is the last configuration, so we should generate a versioned resource.
+        return true;
+    }
+
+    const ConfigDescription& nextConfig = entries.keyAt(idx);
+
+    // Build a configuration that is the same as the source config,
+    // but with the SDK level of the next config. If they are the same,
+    // then they only differ in SDK level. If the next configs SDK level is
+    // higher than the one we want to generate, we must generate it.
+    ConfigDescription tempConfig(sourceConfig);
+    tempConfig.sdkVersion = nextConfig.sdkVersion;
+    if (nextConfig == tempConfig) {
+        return sdkVersionToGenerate < nextConfig.sdkVersion;
+    }
+    return false;
+}
+
 /**
  * Modifies the entries in the resource table to account for compatibility
  * issues with older versions of Android.
@@ -4574,6 +4605,11 @@
                     for (size_t i = 0; i < sdkCount; i++) {
                         const int sdkLevel = attributesToRemove.keyAt(i);
 
+                        if (!shouldGenerateVersionedResource(c, config, sdkLevel)) {
+                            // There is a style that will override this generated one.
+                            continue;
+                        }
+
                         // Duplicate the entry under the same configuration
                         // but with sdkVersion == sdkLevel.
                         ConfigDescription newConfig(config);
@@ -4610,13 +4646,7 @@
 
                 const size_t entriesToAddCount = entriesToAdd.size();
                 for (size_t i = 0; i < entriesToAddCount; i++) {
-                    if (entries.indexOfKey(entriesToAdd[i].key) >= 0) {
-                        // An entry already exists for this config.
-                        // That means that any attributes that were
-                        // defined in L in the original bag will be overriden
-                        // anyways on L devices, so we do nothing.
-                        continue;
-                    }
+                    assert(entries.indexOfKey(entriesToAdd[i].key) < 0);
 
                     if (bundle->getVerbose()) {
                         entriesToAdd[i].value->getPos()
@@ -4662,8 +4692,7 @@
     }
 
     sp<XMLNode> newRoot = NULL;
-    ConfigDescription newConfig(target->getGroupEntry().toParams());
-    newConfig.sdkVersion = SDK_LOLLIPOP_MR1;
+    int sdkVersionToGenerate = SDK_LOLLIPOP_MR1;
 
     Vector<sp<XMLNode> > nodesToVisit;
     nodesToVisit.push(root);
@@ -4689,9 +4718,7 @@
                 // Find the smallest sdk version that we need to synthesize for
                 // and do that one. Subsequent versions will be processed on
                 // the next pass.
-                if (sdkLevel < newConfig.sdkVersion) {
-                    newConfig.sdkVersion = sdkLevel;
-                }
+                sdkVersionToGenerate = std::min(sdkLevel, sdkVersionToGenerate);
 
                 if (bundle->getVerbose()) {
                     SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
@@ -4721,8 +4748,10 @@
     // Look to see if we already have an overriding v21 configuration.
     sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
             String16(target->getResourceType()), resourceName);
-    if (cl->getEntries().indexOfKey(newConfig) < 0) {
+    if (shouldGenerateVersionedResource(cl, config, sdkVersionToGenerate)) {
         // We don't have an overriding entry for v21, so we must duplicate this one.
+        ConfigDescription newConfig(config);
+        newConfig.sdkVersion = sdkVersionToGenerate;
         sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
                 AaptGroupEntry(newConfig), target->getResourceType());
         String8 resPath = String8::format("res/%s/%s",
@@ -4760,7 +4789,8 @@
     return NO_ERROR;
 }
 
-void ResourceTable::getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) {
+void ResourceTable::getDensityVaryingResources(
+        KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) {
     const ConfigDescription nullConfig;
 
     const size_t packageCount = mOrderedPackages.size();
@@ -4771,19 +4801,23 @@
             const Vector<sp<ConfigList> >& configs = types[t]->getOrderedConfigs();
             const size_t configCount = configs.size();
             for (size_t c = 0; c < configCount; c++) {
-                const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries = configs[c]->getEntries();
+                const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries
+                        = configs[c]->getEntries();
                 const size_t configEntryCount = configEntries.size();
                 for (size_t ce = 0; ce < configEntryCount; ce++) {
                     const ConfigDescription& config = configEntries.keyAt(ce);
                     if (AaptConfig::isDensityOnly(config)) {
                         // This configuration only varies with regards to density.
-                        const Symbol symbol(mOrderedPackages[p]->getName(),
+                        const Symbol symbol(
+                                mOrderedPackages[p]->getName(),
                                 types[t]->getName(),
                                 configs[c]->getName(),
-                                getResId(mOrderedPackages[p], types[t], configs[c]->getEntryIndex()));
+                                getResId(mOrderedPackages[p], types[t],
+                                         configs[c]->getEntryIndex()));
 
                         const sp<Entry>& entry = configEntries.valueAt(ce);
-                        AaptUtil::appendValue(resources, symbol, SymbolDefinition(symbol, config, entry->getPos()));
+                        AaptUtil::appendValue(resources, symbol,
+                                              SymbolDefinition(symbol, config, entry->getPos()));
                     }
                 }
             }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 776398f..34d0985 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -21,6 +21,7 @@
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
+import android.annotation.NonNull;
 import android.graphics.Path.Direction;
 import android.graphics.Path.FillType;
 
@@ -30,10 +31,12 @@
 import java.awt.geom.Area;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.RoundRectangle2D;
+import java.util.ArrayList;
 
 /**
  * Delegate implementing the native methods of android.graphics.Path
@@ -56,7 +59,7 @@
 
     // ---- delegate data ----
     private FillType mFillType = FillType.WINDING;
-    private GeneralPath mPath = new GeneralPath();
+    private Path2D mPath = new Path2D.Double();
 
     private float mLastX = 0;
     private float mLastY = 0;
@@ -486,8 +489,54 @@
 
     @LayoutlibDelegate
     /*package*/ static float[] native_approximate(long nPath, float error) {
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.approximate() not supported", null);
-        return new float[0];
+        Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED, "Path.approximate() not fully supported",
+                null);
+        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+        if (pathDelegate == null) {
+            return null;
+        }
+        PathIterator pathIterator = pathDelegate.mPath.getPathIterator(null);
+        float[] tmp = new float[6];
+        float[] coords = new float[6];
+        boolean isFirstPoint = true;
+        while (!pathIterator.isDone()) {
+            int type = pathIterator.currentSegment(tmp);
+            switch (type) {
+                case PathIterator.SEG_MOVETO:
+                case PathIterator.SEG_LINETO:
+                    store(coords, tmp, 1, isFirstPoint);
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    store(coords, tmp, 2, isFirstPoint);
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    store(coords, tmp, 3, isFirstPoint);
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    // No points returned.
+            }
+            isFirstPoint = false;
+            pathIterator.next();
+        }
+        if (isFirstPoint) {
+            // No points found
+            return new float[0];
+        } else {
+            return coords;
+        }
+    }
+
+    private static void store(float[] src, float[] dst, int count, boolean isFirst) {
+        if (isFirst) {
+            dst[0] = 0;
+            dst[1] = src[0];
+            dst[2] = src[1];
+        }
+        if (count > 1 || !isFirst) {
+            dst[3] = 1;
+            dst[4] = src[2 * count];
+            dst[5] = src[2 * count + 1];
+        }
     }
 
     // ---- Private helper methods ----
@@ -522,6 +571,7 @@
         throw new IllegalArgumentException();
     }
 
+    @NonNull
     private static Direction getDirection(int direction) {
         for (Direction d : Direction.values()) {
             if (direction == d.nativeInt) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index 4a9f718..44a9aad 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -30,6 +30,10 @@
  */
 public class MockView extends TextView {
 
+    public MockView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
     public MockView(Context context, AttributeSet attrs, int defStyle) {
         this(context, attrs, defStyle, 0);
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
index 0426907..aa873a6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
@@ -18,14 +18,12 @@
 
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.view.View;
 
-import java.lang.reflect.Method;
-
-import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
 
@@ -53,10 +51,7 @@
             return;
         }
         try {
-            Method setTitle = getMethod(view.getClass(), "setTitle", CharSequence.class);
-            if (setTitle != null) {
-                invoke(setTitle, view, title);
-            }
+            invoke(getMethod(view.getClass(), "setTitle", CharSequence.class), view, title);
         } catch (ReflectionException e) {
             Bridge.getLog().warning(LayoutLog.TAG_INFO,
                     "Error occurred while trying to set title.", e);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index d14c80b..d432120 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -21,16 +21,13 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.RenderParamsFlags;
-import com.android.layoutlib.bridge.util.ReflectionUtils;
+import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.view.View;
 
-import java.lang.reflect.Method;
-
-import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
 import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
@@ -98,8 +95,7 @@
 
     @Nullable
     private static Object getLayoutManager(View recyclerView) throws ReflectionException {
-        Method getLayoutManager = getMethod(recyclerView.getClass(), "getLayoutManager");
-        return getLayoutManager != null ? invoke(getLayoutManager, recyclerView) : null;
+        return invoke(getMethod(recyclerView.getClass(), "getLayoutManager"), recyclerView);
     }
 
     @Nullable
@@ -127,10 +123,7 @@
     private static void setProperty(@NonNull Object object, @NonNull Class<?> propertyClass,
             @Nullable Object propertyValue, @NonNull String propertySetter)
             throws ReflectionException {
-        Method setter = getMethod(object.getClass(), propertySetter, propertyClass);
-        if (setter != null) {
-            invoke(setter, object, propertyValue);
-        }
+        invoke(getMethod(object.getClass(), propertySetter, propertyClass), object, propertyValue);
     }
 
     /**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index dc89d0c..645634f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -74,8 +74,8 @@
     }
 
     public static String getTime(int platformVersion) {
-        if (isGreaterOrEqual(platformVersion, LOLLIPOP_MR1)) {
-            return "5:10";
+        if (isGreaterOrEqual(platformVersion, MNC)) {
+            return "6:00";
         }
         if (platformVersion < GINGERBREAD) {
             return "2:20";
@@ -95,6 +95,9 @@
         if (platformVersion < LOLLIPOP_MR1) {
             return "5:00";
         }
+        if (platformVersion < MNC) {
+            return "5:10";
+        }
         // Should never happen.
         return "4:04";
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 145a03a..b76ec17 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -16,6 +16,7 @@
 
 package com.android.layoutlib.bridge.bars;
 
+import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
@@ -258,8 +259,21 @@
         ResourceValue resource = renderResources.findItemInTheme(attr, true);
         // Form @color/bar to the #AARRGGBB
         resource = renderResources.resolveResValue(resource);
-        if (resource != null && ResourceType.COLOR.equals(resource.getResourceType())) {
-            return ResourceHelper.getColor(resource.getValue());
+        if (resource != null) {
+            ResourceType type = resource.getResourceType();
+            if (type == null || type == ResourceType.COLOR) {
+                // if no type is specified, the value may have been specified directly in the style
+                // file, rather than referencing a color resource value.
+                try {
+                    return ResourceHelper.getColor(resource.getValue());
+                } catch (NumberFormatException e) {
+                    // Conversion failed.
+                    Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+                            "Theme attribute @android:" + attr +
+                                    " does not reference a color, instead is '" +
+                                    resource.getValue() + "'.", resource);
+                }
+            }
         }
         return 0;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
index 89d8319..8c7ea8a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
@@ -45,6 +45,7 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.widget.LinearLayout.VERTICAL;
+import static com.android.layoutlib.bridge.impl.ResourceHelper.getBooleanThemeValue;
 
 /**
  * The Layout used to create the system decor.
@@ -165,13 +166,13 @@
         FrameLayout contentRoot = new FrameLayout(getContext());
         LayoutParams params = createLayoutParams(MATCH_PARENT, MATCH_PARENT);
         int rule = mBuilder.isNavBarVertical() ? START_OF : ABOVE;
-        if (mBuilder.solidBars()) {
+        if (mBuilder.hasNavBar() && mBuilder.solidBars()) {
             params.addRule(rule, getId(ID_NAV_BAR));
         }
         int below = -1;
         if (mBuilder.mActionBarSize <= 0 && mBuilder.mTitleBarSize > 0) {
             below = getId(ID_TITLE_BAR);
-        } else if (mBuilder.solidBars()) {
+        } else if (mBuilder.hasStatusBar() && mBuilder.solidBars()) {
             below = getId(ID_STATUS_BAR);
         }
         if (below != -1) {
@@ -238,10 +239,10 @@
         }
         LayoutParams layoutParams = createLayoutParams(MATCH_PARENT, MATCH_PARENT);
         int rule = mBuilder.isNavBarVertical() ? START_OF : ABOVE;
-        if (mBuilder.solidBars()) {
+        if (mBuilder.hasNavBar() && mBuilder.solidBars()) {
             layoutParams.addRule(rule, getId(ID_NAV_BAR));
         }
-        if (mBuilder.solidBars()) {
+        if (mBuilder.hasStatusBar() && mBuilder.solidBars()) {
             layoutParams.addRule(BELOW, getId(ID_STATUS_BAR));
         }
         actionBar.getRootView().setLayoutParams(layoutParams);
@@ -254,7 +255,7 @@
             int simulatedPlatformVersion) {
         TitleBar titleBar = new TitleBar(context, title, simulatedPlatformVersion);
         LayoutParams params = createLayoutParams(MATCH_PARENT, mBuilder.mTitleBarSize);
-        if (mBuilder.solidBars()) {
+        if (mBuilder.hasStatusBar() && mBuilder.solidBars()) {
             params.addRule(BELOW, getId(ID_STATUS_BAR));
         }
         if (mBuilder.isNavBarVertical() && mBuilder.solidBars()) {
@@ -325,7 +326,7 @@
             mParams = params;
             mContext = context;
             mResources = mParams.getResources();
-            mWindowIsFloating = ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_FLOATING, true, true);
+            mWindowIsFloating = getBooleanThemeValue(mResources, ATTR_WINDOW_FLOATING, true, true);
             
             findBackground();
             findStatusBar();
@@ -333,10 +334,6 @@
             findNavBar();
         }
 
-        public boolean isNavBarVertical() {
-            return mNavBarOrientation == VERTICAL;
-        }
-
         private void findBackground() {
             if (!mParams.isBgColorOverridden()) {
                 mWindowBackground = mResources.findItemInTheme(ATTR_WINDOW_BACKGROUND, true);
@@ -346,11 +343,11 @@
 
         private void findStatusBar() {
             boolean windowFullScreen =
-                    ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_FULL_SCREEN, true, false);
+                    getBooleanThemeValue(mResources, ATTR_WINDOW_FULL_SCREEN, true, false);
             if (!windowFullScreen && !mWindowIsFloating) {
                 mStatusBarSize =
                         getDimension(ATTR_STATUS_BAR_HEIGHT, true, DEFAULT_STATUS_BAR_HEIGHT);
-                mTranslucentStatus = ResourceHelper.getBooleanThemeValue(mResources,
+                mTranslucentStatus = getBooleanThemeValue(mResources,
                         ATTR_WINDOW_TRANSLUCENT_STATUS, true, false);
             }
         }
@@ -360,14 +357,14 @@
                 return;
             }
             // Check if an actionbar is needed
-            boolean windowActionBar = ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_ACTION_BAR,
+            boolean windowActionBar = getBooleanThemeValue(mResources, ATTR_WINDOW_ACTION_BAR,
                     !isThemeAppCompat(), true);
             if (windowActionBar) {
                 mActionBarSize = getDimension(ATTR_ACTION_BAR_SIZE, true, DEFAULT_TITLE_BAR_HEIGHT);
             } else {
                 // Maybe the gingerbread era title bar is needed
                 boolean windowNoTitle =
-                        ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_NO_TITLE, true, false);
+                        getBooleanThemeValue(mResources, ATTR_WINDOW_NO_TITLE, true, false);
                 if (!windowNoTitle) {
                     mTitleBarSize =
                             getDimension(ATTR_WINDOW_TITLE_SIZE, true, DEFAULT_TITLE_BAR_HEIGHT);
@@ -395,7 +392,7 @@
                 mNavBarOrientation = barOnBottom ? LinearLayout.HORIZONTAL : VERTICAL;
                 mNavBarSize = getDimension(barOnBottom ? ATTR_NAV_BAR_HEIGHT : ATTR_NAV_BAR_WIDTH,
                         true, DEFAULT_NAV_BAR_SIZE);
-                mTranslucentNav = ResourceHelper.getBooleanThemeValue(mResources,
+                mTranslucentNav = getBooleanThemeValue(mResources,
                         ATTR_WINDOW_TRANSLUCENT_NAV, true, false);
             }
         }
@@ -444,16 +441,27 @@
         }
 
         /**
-         * Return if both status bar and nav bar are solid (content doesn't overlap with these
-         * bars).
+         * Return true if the status bar or nav bar are present, they are not translucent (i.e
+         * content doesn't overlap with them).
          */
         private boolean solidBars() {
-            return hasNavBar() && !mTranslucentNav && !mTranslucentStatus && mStatusBarSize > 0;
+            return !(hasNavBar() && mTranslucentNav) && !(hasStatusBar() && mTranslucentStatus);
         }
 
         private boolean hasNavBar() {
             return Config.showOnScreenNavBar(mParams.getSimulatedPlatformVersion()) &&
                     hasSoftwareButtons() && mNavBarSize > 0;
         }
+
+        private boolean hasStatusBar() {
+            return mStatusBarSize > 0;
+        }
+
+        /**
+         * Return true if the nav bar is present and is vertical.
+         */
+        private boolean isNavBarVertical() {
+            return hasNavBar() && mNavBarOrientation == VERTICAL;
+        }
     }
 }
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 b2909c9..ee448ca 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
@@ -285,7 +285,7 @@
                 ConfigGenerator.getEnumMap(attrs), getLayoutLog());
     }
 
-    /** Text activity.xml */
+    /** Test activity.xml */
     @Test
     public void testActivity() throws ClassNotFoundException {
         renderAndVerify("activity.xml", "activity.png");
@@ -404,7 +404,7 @@
         ResourceResolver resourceResolver =
                 ResourceResolver.create(sProjectResources.getConfiguredResources(config),
                         sFrameworkRepo.getConfiguredResources(config),
-                        themeName, true);
+                        themeName, false);
 
         return new SessionParams(
                 layoutParser,
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 2951edb..383168f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -119,6 +119,7 @@
                         "android.icu.**",                   // needed by LayoutLib
                         "android.annotation.NonNull",       // annotations
                         "android.annotation.Nullable",      // annotations
+                        "com.android.internal.transition.EpicenterTranslateClipReveal",
                     },
                     excludeClasses,
                     new String[] {