Merge cherrypicks of ['googleplex-android-review.googlesource.com/26385510', 'googleplex-android-review.googlesource.com/26561927'] into 24Q2-release.

Change-Id: I9906d2bd5eb7b4410e363a26f1e9855ae785eea9
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 55c48af..ef93ba7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4478,8 +4478,14 @@
     <!-- Summary for the modifier key picker dialog page [CHAR LIMIT=35] -->
     <string name="modifier_keys_picker_summary">Choose a new key for <xliff:g id="modifier_key_default_name">%1$s</xliff:g>:</string>
 
+    <!-- Title text for per IME subtype keyboard layout. [CHAR LIMIT=35] -->
+    <string name="ime_label_title"><xliff:g id="ime_label" example="Gboard">%s</xliff:g> layout</string>
     <!-- Summary text for keyboards when no layout has been selected. [CHAR LIMIT=35] -->
     <string name="default_keyboard_layout">Default</string>
+    <!-- Summary text for keyboards when a layout is automatically selected. [CHAR LIMIT=35] -->
+    <string name="automatic_keyboard_layout_label">Automatic: <xliff:g id="layout_label" example="English(US)">%s</xliff:g></string>
+    <!-- Summary text for keyboards when a layout is user selected. [CHAR LIMIT=35] -->
+    <string name="user_selected_keyboard_layout_label">User selected: <xliff:g id="layout_label" example="English(US)">%s</xliff:g></string>
 
     <!-- Title for the 'Speech' preference category. [CHAR LIMIT=45] -->
     <string name="speech_category_title">Speech</string>
diff --git a/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java b/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java
index 58aa0cc..21800b9 100644
--- a/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java
+++ b/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceController.java
@@ -22,6 +22,7 @@
 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
 
 import android.app.settings.SettingsEnums;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
@@ -159,8 +160,11 @@
     }
 
     private boolean updateKeyboardVibrationSetting(boolean enable) {
-        final boolean success = Settings.System.putInt(mContext.getContentResolver(),
-                    KEYBOARD_VIBRATION_ENABLED, enable ? ON : OFF);
+        final ContentResolver contentResolver = mContext.getContentResolver();
+        final boolean success = Settings.System.putInt(contentResolver,
+                KEYBOARD_VIBRATION_ENABLED, enable ? ON : OFF);
+        contentResolver.notifyChange(Settings.System.getUriFor(KEYBOARD_VIBRATION_ENABLED),
+                null /* observer */, ContentResolver.NOTIFY_NO_DELAY);
         if (!success) {
             Log.w(TAG, "Update settings database error!");
         }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
index 05dc5be..2bbb567 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java
@@ -21,6 +21,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.KeyboardLayout;
+import android.hardware.input.KeyboardLayoutSelectionResult;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -180,7 +181,7 @@
                     mapLanguageWithLayout(info, subtype);
                 }
             }
-            updatePreferenceLayout(preferenceScreen, info);
+            updatePreferenceLayout(preferenceScreen, info, infoList.size() > 1);
         }
     }
 
@@ -189,14 +190,15 @@
         KeyboardLayout[] keyboardLayouts =
                 NewKeyboardSettingsUtils.getKeyboardLayouts(
                         mIm, mUserId, mInputDeviceIdentifier, info, subtype);
-        String layout = NewKeyboardSettingsUtils.getKeyboardLayout(
+        KeyboardLayoutSelectionResult result = NewKeyboardSettingsUtils.getKeyboardLayout(
                 mIm, mUserId, mInputDeviceIdentifier, info, subtype);
-        if (layout != null) {
+        if (result.getLayoutDescriptor() != null) {
             for (int i = 0; i < keyboardLayouts.length; i++) {
-                if (keyboardLayouts[i].getDescriptor().equals(layout)) {
+                if (keyboardLayouts[i].getDescriptor().equals(result.getLayoutDescriptor())) {
                     KeyboardInfo keyboardInfo = new KeyboardInfo(
                             subtypeLabel,
                             keyboardLayouts[i].getLabel(),
+                            result.getSelectionCriteria(),
                             info,
                             subtype);
                     mKeyboardInfoList.add(keyboardInfo);
@@ -208,18 +210,22 @@
             KeyboardInfo keyboardInfo = new KeyboardInfo(
                     subtypeLabel,
                     mContext.getString(R.string.keyboard_default_layout),
+                    KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_UNSPECIFIED,
                     info,
                     subtype);
             mKeyboardInfoList.add(keyboardInfo);
         }
     }
 
-    private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info) {
+    private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info,
+            boolean hasMultipleImes) {
         if (mKeyboardInfoList.isEmpty()) {
             return;
         }
         PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
-        preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()));
+        preferenceCategory.setTitle(hasMultipleImes ? mContext.getString(R.string.ime_label_title,
+                info.loadLabel(mContext.getPackageManager()))
+                : mContext.getString(R.string.enabled_locales_keyboard_layout));
         preferenceCategory.setKey(info.getPackageName());
         preferenceScreen.addPreference(preferenceCategory);
         Collections.sort(mKeyboardInfoList, new Comparator<KeyboardInfo>() {
@@ -234,7 +240,7 @@
             final Preference pref = new Preference(mContext);
             pref.setKey(keyboardInfo.getPrefId());
             pref.setTitle(keyboardInfo.getSubtypeLabel());
-            pref.setSummary(keyboardInfo.getLayout());
+            pref.setSummary(keyboardInfo.getLayoutSummaryText(mContext));
             pref.setOnPreferenceClickListener(
                     preference -> {
                         showKeyboardLayoutPicker(
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
index ac8037f..ec727e8 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -21,6 +21,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.KeyboardLayout;
+import android.hardware.input.KeyboardLayoutSelectionResult;
 import android.os.Bundle;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
@@ -201,13 +202,13 @@
 
     private String getSelectedLayoutLabel() {
         String label = mContext.getString(R.string.keyboard_default_layout);
-        String layout = NewKeyboardSettingsUtils.getKeyboardLayout(
+        KeyboardLayoutSelectionResult result = NewKeyboardSettingsUtils.getKeyboardLayout(
                 mIm, mUserId, mInputDeviceIdentifier, mInputMethodInfo, mInputMethodSubtype);
         KeyboardLayout[] keyboardLayouts = NewKeyboardSettingsUtils.getKeyboardLayouts(
                 mIm, mUserId, mInputDeviceIdentifier, mInputMethodInfo, mInputMethodSubtype);
-        if (layout != null) {
+        if (result.getLayoutDescriptor() != null) {
             for (KeyboardLayout keyboardLayout : keyboardLayouts) {
-                if (keyboardLayout.getDescriptor().equals(layout)) {
+                if (keyboardLayout.getDescriptor().equals(result.getLayoutDescriptor())) {
                     label = keyboardLayout.getLabel();
                     break;
                 }
diff --git a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
index a927165..8f1e5c8 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java
@@ -16,20 +16,30 @@
 
 package com.android.settings.inputmethod;
 
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE;
+import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
 import android.content.Context;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.KeyboardLayout;
+import android.hardware.input.KeyboardLayoutSelectionResult;
+import android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria;
 import android.os.UserHandle;
 import android.view.InputDevice;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
 
-import java.util.ArrayList;
+import com.android.settings.R;
+
 import java.util.Arrays;
 import java.util.Comparator;
-import java.util.List;
 
 /**
  * Utilities of keyboard settings
@@ -56,36 +66,47 @@
         return false;
     }
 
-    static List<String> getSuitableImeLabels(Context context, InputMethodManager imm, int userId) {
-        List<String> suitableInputMethodInfoLabels = new ArrayList<>();
-        List<InputMethodInfo> infoList = imm.getEnabledInputMethodListAsUser(UserHandle.of(userId));
-        for (InputMethodInfo info : infoList) {
-            List<InputMethodSubtype> subtypes =
-                    imm.getEnabledInputMethodSubtypeList(info, true);
-            for (InputMethodSubtype subtype : subtypes) {
-                if (subtype.isSuitableForPhysicalKeyboardLayoutMapping()) {
-                    suitableInputMethodInfoLabels.add(
-                            info.loadLabel(context.getPackageManager()).toString());
-                    break;
+    @SuppressLint("MissingPermission")
+    @Nullable
+    static String getSelectedKeyboardLayoutLabelForUser(Context context, @UserIdInt int userId,
+            InputDeviceIdentifier inputDeviceIdentifier) {
+        InputMethodManager imm = context.getSystemService(InputMethodManager.class);
+        InputManager im = context.getSystemService(InputManager.class);
+        if (imm == null || im == null) {
+            return null;
+        }
+        InputMethodInfo imeInfo = imm.getCurrentInputMethodInfoAsUser(UserHandle.of(userId));
+        InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
+        KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(im, userId, inputDeviceIdentifier,
+                imeInfo, subtype);
+        KeyboardLayoutSelectionResult result = getKeyboardLayout(im, userId, inputDeviceIdentifier,
+                imeInfo, subtype);
+        if (result != null) {
+            for (KeyboardLayout keyboardLayout : keyboardLayouts) {
+                if (keyboardLayout.getDescriptor().equals(result.getLayoutDescriptor())) {
+                    return keyboardLayout.getLabel();
                 }
             }
         }
-        return suitableInputMethodInfoLabels;
+        return null;
     }
 
     static class KeyboardInfo {
         CharSequence mSubtypeLabel;
         String mLayout;
+        @LayoutSelectionCriteria int mSelectionCriteria;
         InputMethodInfo mInputMethodInfo;
         InputMethodSubtype mInputMethodSubtype;
 
         KeyboardInfo(
                 CharSequence subtypeLabel,
                 String layout,
+                @LayoutSelectionCriteria int selectionCriteria,
                 InputMethodInfo inputMethodInfo,
                 InputMethodSubtype inputMethodSubtype) {
             mSubtypeLabel = subtypeLabel;
             mLayout = layout;
+            mSelectionCriteria = selectionCriteria;
             mInputMethodInfo = inputMethodInfo;
             mInputMethodSubtype = inputMethodSubtype;
         }
@@ -102,6 +123,17 @@
             return mLayout;
         }
 
+        String getLayoutSummaryText(Context context) {
+            if (isAutomaticSelection(mSelectionCriteria)) {
+                return context.getResources().getString(R.string.automatic_keyboard_layout_label,
+                        mLayout);
+            } else if (isUserSelection(mSelectionCriteria)) {
+                return context.getResources().getString(
+                        R.string.user_selected_keyboard_layout_label, mLayout);
+            }
+            return mLayout;
+        }
+
         InputMethodInfo getInputMethodInfo() {
             return mInputMethodInfo;
         }
@@ -121,11 +153,21 @@
         return inputManager.getKeyboardLayoutListForInputDevice(identifier, userId, info, subtype);
     }
 
-    static String getKeyboardLayout(InputManager inputManager, int userId,
+    @NonNull
+    static KeyboardLayoutSelectionResult getKeyboardLayout(InputManager inputManager, int userId,
             InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) {
         return inputManager.getKeyboardLayoutForInputDevice(identifier, userId, info, subtype);
     }
 
+    static boolean isAutomaticSelection(@LayoutSelectionCriteria int criteria) {
+        return criteria == LAYOUT_SELECTION_CRITERIA_DEVICE
+                || criteria == LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD;
+    }
+
+    static boolean isUserSelection(@LayoutSelectionCriteria int criteria) {
+        return criteria == LAYOUT_SELECTION_CRITERIA_USER;
+    }
+
     static void sortKeyboardLayoutsByLabel(KeyboardLayout[] keyboardLayouts) {
         Arrays.sort(
                 keyboardLayouts,
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index f2ac550..e102241 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -288,19 +288,11 @@
             final Preference pref = new Preference(getPrefContext());
             pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
             if (mIsNewKeyboardSettings) {
-                List<String> suitableImes = new ArrayList<>();
-                suitableImes.addAll(
-                        NewKeyboardSettingsUtils.getSuitableImeLabels(
-                                getContext(), mImm, UserHandle.myUserId()));
-                if (!suitableImes.isEmpty()) {
-                    String summary = suitableImes.get(0);
-                    StringBuilder result = new StringBuilder(summary);
-                    for (int i = 1; i < suitableImes.size(); i++) {
-                        result.append(", ").append(suitableImes.get(i));
-                    }
-                    pref.setSummary(result.toString());
-                } else {
-                    pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
+                String currentLayout =
+                        NewKeyboardSettingsUtils.getSelectedKeyboardLayoutLabelForUser(getContext(),
+                                UserHandle.myUserId(), hardKeyboardDeviceInfo.mDeviceIdentifier);
+                if (currentLayout != null) {
+                    pref.setSummary(currentLayout);
                 }
                 pref.setOnPreferenceClickListener(
                         preference -> {
diff --git a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java
index 2d5905e..832a313 100644
--- a/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/KeyboardVibrationTogglePreferenceControllerTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.settings.SettingsEnums;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.vibrator.Flags;
@@ -60,6 +61,9 @@
     @Mock
     private PreferenceScreen mPreferenceScreen;
 
+    @Mock
+    private ContentResolver mContentResolver;
+
     private Context mContext;
     private Resources mResources;
     private KeyboardVibrationTogglePreferenceController mController;
@@ -72,6 +76,7 @@
         mContext = spy(ApplicationProvider.getApplicationContext());
         mResources = spy(mContext.getResources());
         when(mContext.getResources()).thenReturn(mResources);
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
         mFeatureFactory = FakeFeatureFactory.setupForTest();
         mController = new KeyboardVibrationTogglePreferenceController(mContext, "preferenceKey");
         mPreference = new SwitchPreference(mContext);