diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 4d4a87e186645..72c7dadac2714 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -1261,30 +1261,45 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
private static boolean isLayoutCompatibleWithLanguageTag(KeyboardLayout layout,
@NonNull String languageTag) {
- final int[] scriptsFromLanguageTag = UScript.getCode(Locale.forLanguageTag(languageTag));
- if (scriptsFromLanguageTag.length == 0) {
- // If no scripts inferred from languageTag then allowing the layout
- return true;
- }
- LocaleList locales = layout.getLocales();
- if (locales.isEmpty()) {
+ LocaleList layoutLocales = layout.getLocales();
+ if (layoutLocales.isEmpty()) {
// KCM file doesn't have an associated language tag. This can be from
// a 3rd party app so need to include it as a potential layout.
return true;
}
- for (int i = 0; i < locales.size(); i++) {
- final Locale locale = locales.get(i);
- if (locale == null) {
- continue;
- }
- int[] scripts = UScript.getCode(locale);
- if (scripts != null && haveCommonValue(scripts, scriptsFromLanguageTag)) {
+ // Match derived Script codes
+ final int[] scriptsFromLanguageTag = getScriptCodes(Locale.forLanguageTag(languageTag));
+ if (scriptsFromLanguageTag.length == 0) {
+ // If no scripts inferred from languageTag then allowing the layout
+ return true;
+ }
+ for (int i = 0; i < layoutLocales.size(); i++) {
+ final Locale locale = layoutLocales.get(i);
+ int[] scripts = getScriptCodes(locale);
+ if (haveCommonValue(scripts, scriptsFromLanguageTag)) {
return true;
}
}
return false;
}
+ private static int[] getScriptCodes(@Nullable Locale locale) {
+ if (locale == null) {
+ return new int[0];
+ }
+ if (!TextUtils.isEmpty(locale.getScript())) {
+ int scriptCode = UScript.getCodeFromName(locale.getScript());
+ if (scriptCode != UScript.INVALID_CODE) {
+ return new int[]{scriptCode};
+ }
+ }
+ int[] scripts = UScript.getCode(locale);
+ if (scripts != null) {
+ return scripts;
+ }
+ return new int[0];
+ }
+
private static boolean haveCommonValue(int[] arr1, int[] arr2) {
for (int a1 : arr1) {
for (int a2 : arr2) {
diff --git a/services/tests/servicestests/res/xml/keyboard_layouts.xml b/services/tests/servicestests/res/xml/keyboard_layouts.xml
index b5a05fcaff173..5f3fcd6eaed07 100644
--- a/services/tests/servicestests/res/xml/keyboard_layouts.xml
+++ b/services/tests/servicestests/res/xml/keyboard_layouts.xml
@@ -72,10 +72,18 @@
android:keyboardLayout="@raw/dummy_keyboard_layout"
android:keyboardLocale="ru-Cyrl" />
+
+
+
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index b660926f13946..7729fa29667b8 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -26,7 +26,6 @@ import android.content.pm.ServiceInfo
import android.hardware.input.IInputManager
import android.hardware.input.InputManager
import android.hardware.input.KeyboardLayout
-import android.icu.lang.UScript
import android.icu.util.ULocale
import android.os.Bundle
import android.os.test.TestLooper
@@ -52,7 +51,6 @@ import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
-import java.util.Locale
private fun createKeyboard(
deviceId: Int,
@@ -553,24 +551,17 @@ class KeyboardLayoutManagerTests {
0,
keyboardLayouts.size
)
-
- val englishScripts = UScript.getCode(Locale.forLanguageTag("hi-Latn"))
- for (kl in keyboardLayouts) {
- var isCompatible = false
- for (i in 0 until kl.locales.size()) {
- val locale: Locale = kl.locales.get(i) ?: continue
- val scripts = UScript.getCode(locale)
- if (scripts != null && areScriptsCompatible(scripts, englishScripts)) {
- isCompatible = true
- break
- }
- }
- assertTrue(
- "New UI: getKeyboardLayoutListForInputDevice API should only return " +
- "compatible layouts but found " + kl.descriptor,
- isCompatible
+ assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(US) layout for hi-Latn",
+ containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
+ assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(No script code) layout for hi-Latn",
+ containsLayout(
+ keyboardLayouts,
+ createLayoutDescriptor("keyboard_layout_english_without_script_code")
)
- }
+ )
// Check Layouts for "hi" which by default uses 'Deva' script.
keyboardLayouts =
@@ -600,6 +591,46 @@ class KeyboardLayoutManagerTests {
1,
keyboardLayouts.size
)
+
+ // Special case Japanese: UScript ignores provided script code for certain language tags
+ // Should manually match provided script codes and then rely on Uscript to derive
+ // script from language tags and match those.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTag("ja-Latn-JP")
+ )
+ assertNotEquals(
+ "New UI: getKeyboardLayoutListForInputDevice API should return the list of " +
+ "supported layouts with matching script code for ja-Latn-JP",
+ 0,
+ keyboardLayouts.size
+ )
+ assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(US) layout for ja-Latn-JP",
+ containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
+ )
+ assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
+ "containing English(No script code) layout for ja-Latn-JP",
+ containsLayout(
+ keyboardLayouts,
+ createLayoutDescriptor("keyboard_layout_english_without_script_code")
+ )
+ )
+
+ // If script code not explicitly provided for Japanese should rely on Uscript to find
+ // derived script code and hence no suitable layout will be found.
+ keyboardLayouts =
+ keyboardLayoutManager.getKeyboardLayoutListForInputDevice(
+ keyboardDevice.identifier, USER_ID, imeInfo,
+ createImeSubtypeForLanguageTag("ja-JP")
+ )
+ assertEquals(
+ "New UI: getKeyboardLayoutListForInputDevice API should return empty list of " +
+ "supported layouts with matching script code for ja-JP",
+ 0,
+ keyboardLayouts.size
+ )
}
}
@@ -779,10 +810,10 @@ class KeyboardLayoutManagerTests {
private fun createLayoutDescriptor(keyboardName: String): String =
"$PACKAGE_NAME/$RECEIVER_NAME/$keyboardName"
- private fun areScriptsCompatible(scriptList1: IntArray, scriptList2: IntArray): Boolean {
- for (s1 in scriptList1) {
- for (s2 in scriptList2) {
- if (s1 == s2) return true
+ private fun containsLayout(layoutList: Array, layoutDesc: String): Boolean {
+ for (kl in layoutList) {
+ if (kl.descriptor.equals(layoutDesc)) {
+ return true
}
}
return false