Merge "Fix volume change failure in HDMI-CEC system audio mode." into lmp-dev
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 860512b..5e50b69 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -517,6 +517,27 @@
      */
     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
 
+    /**
+     * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
+     * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
+     * @hide
+     */
+    public static final int ACCESS_UNKNOWN = 0;
+
+    /**
+     * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
+     * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
+     * @hide
+     */
+    public static final int ACCESS_ALLOWED = 1;
+
+    /**
+     * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
+     * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
+     * @hide
+     */
+    public static final int ACCESS_REJECTED = 2;
+
      /**
       * No preferrence of physical transport for GATT connections to remote dual-mode devices
       * @hide
@@ -952,39 +973,6 @@
     }
 
     /**
-     * Get trust state of a remote device.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
-     * @hide
-     */
-    public boolean getTrustState() {
-        //TODO(BT)
-        /*
-        try {
-            return sService.getTrustState(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        }*/
-        return false;
-    }
-
-    /**
-     * Set trust state for a remote device.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
-     * @param value the trust state value (true or false)
-     * @hide
-     */
-    public boolean setTrust(boolean value) {
-        //TODO(BT)
-        /*
-        try {
-            return sService.setTrust(this, value);
-        } catch (RemoteException e) {
-            Log.e(TAG, "", e);
-        }*/
-        return false;
-    }
-
-    /**
      * Returns the supported features (UUIDs) of the remote device.
      *
      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
@@ -1135,6 +1123,82 @@
     }
 
     /**
+     * Requires {@link android.Manifest.permission#BLUETOOTH}.
+     * @return Whether the phonebook access is allowed to this device. Can be
+     *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+     * @hide
+     */
+    public int getPhonebookAccessPermission() {
+        if (sService == null) {
+            return ACCESS_UNKNOWN;
+        }
+        try {
+            return sService.getPhonebookAccessPermission(this);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    /**
+     * Sets whether the phonebook access is allowed to this device.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
+     *              {@link #ACCESS_REJECTED}.
+     * @return Whether the value has been successfully set.
+     * @hide
+     */
+    public boolean setPhonebookAccessPermission(int value) {
+        if (sService == null) {
+            return false;
+        }
+        try {
+            return sService.setPhonebookAccessPermission(this, value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return false;
+    }
+
+    /**
+     * Requires {@link android.Manifest.permission#BLUETOOTH}.
+     * @return Whether the message access is allowed to this device. Can be
+     *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
+     * @hide
+     */
+    public int getMessageAccessPermission() {
+        if (sService == null) {
+            return ACCESS_UNKNOWN;
+        }
+        try {
+            return sService.getMessageAccessPermission(this);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    /**
+     * Sets whether the message access is allowed to this device.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
+     * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
+     *              {@link #ACCESS_REJECTED}.
+     * @return Whether the value has been successfully set.
+     * @hide
+     */
+    public boolean setMessageAccessPermission(int value) {
+        if (sService == null) {
+            return false;
+        }
+        try {
+            return sService.setMessageAccessPermission(this, value);
+        } catch (RemoteException e) {
+            Log.e(TAG, "", e);
+        }
+        return false;
+    }
+
+    /**
      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
      * outgoing connection to this remote device on given channel.
      * <p>The remote device will be authenticated and communication on this
@@ -1343,5 +1407,4 @@
         } catch (RemoteException e) {Log.e(TAG, "", e);}
         return null;
     }
-
 }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 19c600c..cf2a343 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -75,6 +75,11 @@
     passkey);
     boolean setPairingConfirmation(in BluetoothDevice device, boolean accept);
 
+    int getPhonebookAccessPermission(in BluetoothDevice device);
+    boolean setPhonebookAccessPermission(in BluetoothDevice device, int value);
+    int getMessageAccessPermission(in BluetoothDevice device);
+    boolean setMessageAccessPermission(in BluetoothDevice device, int value);
+
     void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
 
     void registerCallback(in IBluetoothCallback callback);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index f917fdc..1dc5533 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -578,6 +578,9 @@
             mFrameNumberRequestPairs.add(
                     new SimpleEntry<Long, Integer>(lastFrameNumber,
                             requestId));
+            // It is possible that the last frame has already arrived, so we need to check
+            // for sequence completion right away
+            checkAndFireSequenceComplete();
         }
     }
 
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index 42fe897..7c6475d 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -45,6 +45,7 @@
     private static final String TAG = "LegacyRequestMapper";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
+    /** Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality */
     private static final byte DEFAULT_JPEG_QUALITY = 85;
 
     /**
@@ -410,8 +411,8 @@
 
         // jpeg.thumbnailQuality
         {
-            params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_THUMBNAIL_QUALITY,
-                    DEFAULT_JPEG_QUALITY));
+            params.setJpegThumbnailQuality(0xFF & ParamsUtils.getOrDefault(request,
+                    JPEG_THUMBNAIL_QUALITY, DEFAULT_JPEG_QUALITY));
         }
 
         // jpeg.thumbnailSize
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 6eb9471..f90a9fe 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -173,11 +173,10 @@
             mDrawableTintList = a.getColorStateList(R.styleable.ImageView_tint);
             mHasDrawableTint = true;
 
-            // Prior to L, the tint mode was always SRC_ATOP.
-            if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.L) {
-                mDrawableTintMode = PorterDuff.Mode.SRC_ATOP;
-                mHasDrawableTintMode = true;
-            }
+            // Prior to L, this attribute would always set a color filter with
+            // blending mode SRC_ATOP. Preserve that default behavior.
+            mDrawableTintMode = PorterDuff.Mode.SRC_ATOP;
+            mHasDrawableTintMode = true;
         }
 
         if (a.hasValue(R.styleable.ImageView_tintMode)) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f25cf9b..7160724 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -27,11 +27,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
@@ -499,7 +501,19 @@
      * @return true if lock screen is can be disabled
      */
     public boolean isLockScreenDisabled() {
-        return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
+        if (!isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0) {
+            // Check if the number of switchable users forces the lockscreen.
+            final List<UserInfo> users = UserManager.get(mContext).getUsers(true);
+            final int userCount = users.size();
+            int switchableUsers = 0;
+            for (int i = 0; i < userCount; i++) {
+                if (users.get(i).supportsSwitchTo()) {
+                    switchableUsers++;
+                }
+            }
+            return switchableUsers < 2;
+        }
+        return false;
     }
 
     /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index bf2d09b..03a5e23 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -864,7 +864,8 @@
         android:description="@string/permdesc_bluetoothAdmin"
         android:label="@string/permlab_bluetoothAdmin" />
 
-    <!-- @SystemApi Allows applications to pair bluetooth devices without user interaction.
+    <!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to
+         allow or disallow phonebook access or message access.
          This is not available to third party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
         android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 12fc291..85c1072 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3446,7 +3446,7 @@
         <!-- An optional argument to supply a maximum height for this view.
              See {see android.widget.ImageView#setMaxHeight} for details. -->
         <attr name="maxHeight" format="dimension" />
-        <!-- Set a tinting color for the image. -->
+        <!-- Set a tinting color for the image. By default, the tint will blend using SRC_ATOP mode. -->
         <attr name="tint" format="color" />
         <!-- If true, the image view will be baseline aligned with based on its
              bottom edge. -->
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 6f95f91..864e119 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -139,6 +139,10 @@
         clampStartingPosition();
     }
 
+    public boolean isHardwareAnimating() {
+        return mHardwareAnimating;
+    }
+
     private void clampStartingPosition() {
         final float cX = mBounds.exactCenterX();
         final float cY = mBounds.exactCenterY();
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index bc6f5fb..4e709b5 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -122,6 +122,10 @@
         mDensity = density;
     }
 
+    public boolean isHardwareAnimating() {
+        return mHardwareAnimating;
+    }
+
     public void onHotspotBoundsChanged() {
         if (!mHasMaxRadius) {
             final float halfWidth = mBounds.width() / 2.0f;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index b13669b..4fd98b7 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -202,24 +202,31 @@
     public void jumpToCurrentState() {
         super.jumpToCurrentState();
 
+        boolean needsDraw = false;
+
         if (mRipple != null) {
+            needsDraw |= mRipple.isHardwareAnimating();
             mRipple.jump();
         }
 
         if (mBackground != null) {
+            needsDraw |= mBackground.isHardwareAnimating();
             mBackground.jump();
         }
 
-        cancelExitingRipples();
+        needsDraw |= cancelExitingRipples();
 
-        mNeedsDraw = true;
+        mNeedsDraw = needsDraw;
         invalidateSelf();
     }
 
-    private void cancelExitingRipples() {
+    private boolean cancelExitingRipples() {
+        boolean needsDraw = false;
+
         final int count = mExitingRipplesCount;
         final Ripple[] ripples = mExitingRipples;
         for (int i = 0; i < count; i++) {
+            needsDraw |= ripples[i].isHardwareAnimating();
             ripples[i].cancel();
         }
 
@@ -227,6 +234,8 @@
             Arrays.fill(ripples, 0, count, null);
         }
         mExitingRipplesCount = 0;
+
+        return needsDraw;
     }
 
     @Override
@@ -546,19 +555,23 @@
      * background. Nothing will be drawn after this method is called.
      */
     private void clearHotspots() {
+        boolean needsDraw = false;
+
         if (mRipple != null) {
+            needsDraw |= mRipple.isHardwareAnimating();
             mRipple.cancel();
             mRipple = null;
         }
 
         if (mBackground != null) {
+            needsDraw |= mBackground.isHardwareAnimating();
             mBackground.cancel();
             mBackground = null;
         }
 
-        cancelExitingRipples();
+        needsDraw |= cancelExitingRipples();
 
-        mNeedsDraw = true;
+        mNeedsDraw = needsDraw;
         invalidateSelf();
     }
 
@@ -657,6 +670,10 @@
         // least draw a color so that hardware invalidation works correctly.
         if (contentLayer < 0 && backgroundLayer < 0 && rippleLayer < 0 && mNeedsDraw) {
             canvas.drawColor(Color.TRANSPARENT);
+
+            // Request another draw so we can avoid adding a transparent layer
+            // during the next display list refresh.
+            invalidateSelf();
         }
         mNeedsDraw = false;
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 50ba68e..9af893d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -683,8 +683,7 @@
     }
 
     private void maybeSendUserPresentBroadcast() {
-        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()
-                && !mUserManager.isUserSwitcherEnabled()) {
+        if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()) {
             // Lock screen is disabled because the user has set the preference to "None".
             // In this case, send out ACTION_USER_PRESENT here instead of in
             // handleKeyguardDone()
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0d27669..d87fc2e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12118,14 +12118,14 @@
                 dumpState.setDump(DumpState.DUMP_VERSION);
             } else if ("k".equals(cmd) || "keysets".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_KEYSETS);
+            } else if ("installs".equals(cmd)) {
+                dumpState.setDump(DumpState.DUMP_INSTALLS);
             } else if ("write".equals(cmd)) {
                 synchronized (mPackages) {
                     mSettings.writeLPr();
                     pw.println("Settings written.");
                     return;
                 }
-            } else if ("installs".equals(cmd)) {
-                dumpState.setDump(DumpState.DUMP_INSTALLS);
             }
         }
 
@@ -12357,7 +12357,9 @@
                 mSettings.dumpSharedUsersLPr(pw, packageName, dumpState);
             }
 
-            if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS)) {
+            if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
+                // XXX should handle packageName != null by dumping only install data that
+                // the given package is involved with.
                 if (dumpState.onTitlePrinted()) pw.println();
                 mInstallerService.dump(new IndentingPrintWriter(pw, "  ", 120));
             }