Merge "Add global microphone mute key for keyboard"
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index d6d3a97..5718532 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -133,9 +133,6 @@
     private HandlerThread mHandlerThread;
     private Handler mHandler;
     private FoldStateListener mFoldStateListener;
-    @GuardedBy("mLock")
-    private ArrayList<WeakReference<DeviceStateListener>> mDeviceStateListeners = new ArrayList<>();
-    private boolean mFoldedDeviceState;
 
     /**
      * @hide
@@ -144,31 +141,39 @@
         void onDeviceStateChanged(boolean folded);
     }
 
-    private final class FoldStateListener implements DeviceStateManager.DeviceStateCallback {
+    private static final class FoldStateListener implements DeviceStateManager.DeviceStateCallback {
         private final int[] mFoldedDeviceStates;
 
+        private ArrayList<WeakReference<DeviceStateListener>> mDeviceStateListeners =
+                new ArrayList<>();
+        private boolean mFoldedDeviceState;
+
         public FoldStateListener(Context context) {
             mFoldedDeviceStates = context.getResources().getIntArray(
                     com.android.internal.R.array.config_foldedDeviceStates);
         }
 
-        private void handleStateChange(int state) {
+        private synchronized void handleStateChange(int state) {
             boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state);
-            synchronized (mLock) {
-                mFoldedDeviceState = folded;
-                ArrayList<WeakReference<DeviceStateListener>> invalidListeners = new ArrayList<>();
-                for (WeakReference<DeviceStateListener> listener : mDeviceStateListeners) {
-                    DeviceStateListener callback = listener.get();
-                    if (callback != null) {
-                        callback.onDeviceStateChanged(folded);
-                    } else {
-                        invalidListeners.add(listener);
-                    }
-                }
-                if (!invalidListeners.isEmpty()) {
-                    mDeviceStateListeners.removeAll(invalidListeners);
+
+            mFoldedDeviceState = folded;
+            ArrayList<WeakReference<DeviceStateListener>> invalidListeners = new ArrayList<>();
+            for (WeakReference<DeviceStateListener> listener : mDeviceStateListeners) {
+                DeviceStateListener callback = listener.get();
+                if (callback != null) {
+                    callback.onDeviceStateChanged(folded);
+                } else {
+                    invalidListeners.add(listener);
                 }
             }
+            if (!invalidListeners.isEmpty()) {
+                mDeviceStateListeners.removeAll(invalidListeners);
+            }
+        }
+
+        public synchronized void addDeviceStateListener(DeviceStateListener listener) {
+            listener.onDeviceStateChanged(mFoldedDeviceState);
+            mDeviceStateListeners.add(new WeakReference<>(listener));
         }
 
         @Override
@@ -192,9 +197,8 @@
     public void registerDeviceStateListener(@NonNull CameraCharacteristics chars) {
         synchronized (mLock) {
             DeviceStateListener listener = chars.getDeviceStateListener();
-            listener.onDeviceStateChanged(mFoldedDeviceState);
             if (mFoldStateListener != null) {
-                mDeviceStateListeners.add(new WeakReference<>(listener));
+                mFoldStateListener.addDeviceStateListener(listener);
             }
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index df19c67..42c3d1b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -234,7 +234,7 @@
     /**
      * @return whether high quality audio is enabled or not
      */
-    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
         BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         if (bluetoothDevice == null) {
@@ -286,7 +286,7 @@
      * @param device to get codec label from
      * @return the label associated with the device codec
      */
-    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
         BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 7732da4..46a94fd 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -314,4 +314,7 @@
 
     <!-- Whether tilt to bright is enabled by default. -->
     <bool name="def_wearable_tiltToBrightEnabled">false</bool>
+
+    <!-- Whether vibrate icon is shown in the status bar by default. -->
+    <integer name="def_statusBarVibrateIconEnabled">0</integer>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a6edb0f..19bbcff0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3631,7 +3631,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 210;
+            private static final int SETTINGS_VERSION = 211;
 
             private final int mUserId;
 
@@ -5512,7 +5512,17 @@
                     // removed now that feature is enabled for everyone
                     currentVersion = 210;
                 }
-
+                if (currentVersion == 210) {
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final int defaultValueVibrateIconEnabled = getContext().getResources()
+                            .getInteger(R.integer.def_statusBarVibrateIconEnabled);
+                    secureSettings.insertSettingOverrideableByRestoreLocked(
+                            Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
+                            String.valueOf(defaultValueVibrateIconEnabled),
+                            null /* tag */, true /* makeDefault */,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                    currentVersion = 211;
+                }
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c5c4553..7cc24fa 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2572,33 +2572,39 @@
         if (!checkNotifyPermission("notifyBarringInfo()")) {
             return;
         }
-        if (barringInfo == null) {
-            log("Received null BarringInfo for subId=" + subId + ", phoneId=" + phoneId);
-            mBarringInfo.set(phoneId, new BarringInfo());
+        if (!validatePhoneId(phoneId)) {
+            loge("Received invalid phoneId for BarringInfo = " + phoneId);
             return;
         }
 
         synchronized (mRecords) {
-            if (validatePhoneId(phoneId)) {
-                mBarringInfo.set(phoneId, barringInfo);
-                // Barring info is non-null
-                BarringInfo biNoLocation = barringInfo.createLocationInfoSanitizedCopy();
-                if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
-                for (Record r : mRecords) {
-                    if (r.matchTelephonyCallbackEvent(
-                            TelephonyCallback.EVENT_BARRING_INFO_CHANGED)
-                            && idMatch(r, subId, phoneId)) {
-                        try {
-                            if (DBG_LOC) {
-                                log("notifyBarringInfo: mBarringInfo="
-                                        + barringInfo + " r=" + r);
-                            }
-                            r.callback.onBarringInfoChanged(
-                                    checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
-                                        ? barringInfo : biNoLocation);
-                        } catch (RemoteException ex) {
-                            mRemoveList.add(r.binder);
+            if (barringInfo == null) {
+                loge("Received null BarringInfo for subId=" + subId + ", phoneId=" + phoneId);
+                mBarringInfo.set(phoneId, new BarringInfo());
+                return;
+            }
+            if (barringInfo.equals(mBarringInfo.get(phoneId))) {
+                if (VDBG) log("Ignoring duplicate barring info.");
+                return;
+            }
+            mBarringInfo.set(phoneId, barringInfo);
+            // Barring info is non-null
+            BarringInfo biNoLocation = barringInfo.createLocationInfoSanitizedCopy();
+            if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
+            for (Record r : mRecords) {
+                if (r.matchTelephonyCallbackEvent(
+                        TelephonyCallback.EVENT_BARRING_INFO_CHANGED)
+                        && idMatch(r, subId, phoneId)) {
+                    try {
+                        if (DBG_LOC) {
+                            log("notifyBarringInfo: mBarringInfo="
+                                    + barringInfo + " r=" + r);
                         }
+                        r.callback.onBarringInfoChanged(
+                                checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
+                                    ? barringInfo : biNoLocation);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 715076d..3af6e18 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2947,8 +2947,6 @@
                 if ((metaState & KeyEvent.META_META_MASK) == 0) {
                     return key_not_consumed;
                 }
-                // Share the same behavior with KEYCODE_LANGUAGE_SWITCH.
-            case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
                 if (down && repeatCount == 0) {
                     int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
                     mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
diff --git a/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java b/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java
index 916551a..79a2f1f 100644
--- a/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java
+++ b/tests/RollbackTest/SampleRollbackApp/src/com/android/sample/rollbackapp/MainActivity.java
@@ -75,6 +75,7 @@
                         String rollbackStatus = "FAILED";
                         if (rollbackStatusCode == RollbackManager.STATUS_SUCCESS) {
                             rollbackStatus = "SUCCESS";
+                            mTriggerRollbackButton.setClickable(false);
                         }
                         makeToast("Status for rollback ID " + rollbackId + " is " + rollbackStatus);
                     }}, new IntentFilter(ACTION_NAME), Context.RECEIVER_NOT_EXPORTED);