Merge "Modify Script matching algorithm" into udc-dev am: cbb43d662a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22118578

Change-Id: Iaa1c899e35e83ba6af21693e73c53b1d26beb6a2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Vaibhav Devmurari
2023-03-27 16:10:34 +00:00
committed by Automerger Merge Worker
3 changed files with 91 additions and 37 deletions

View File

@@ -1261,30 +1261,45 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
private static boolean isLayoutCompatibleWithLanguageTag(KeyboardLayout layout, private static boolean isLayoutCompatibleWithLanguageTag(KeyboardLayout layout,
@NonNull String languageTag) { @NonNull String languageTag) {
final int[] scriptsFromLanguageTag = UScript.getCode(Locale.forLanguageTag(languageTag)); LocaleList layoutLocales = layout.getLocales();
if (scriptsFromLanguageTag.length == 0) { if (layoutLocales.isEmpty()) {
// If no scripts inferred from languageTag then allowing the layout
return true;
}
LocaleList locales = layout.getLocales();
if (locales.isEmpty()) {
// KCM file doesn't have an associated language tag. This can be from // 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. // a 3rd party app so need to include it as a potential layout.
return true; return true;
} }
for (int i = 0; i < locales.size(); i++) { // Match derived Script codes
final Locale locale = locales.get(i); final int[] scriptsFromLanguageTag = getScriptCodes(Locale.forLanguageTag(languageTag));
if (locale == null) { if (scriptsFromLanguageTag.length == 0) {
continue; // If no scripts inferred from languageTag then allowing the layout
return true;
} }
int[] scripts = UScript.getCode(locale); for (int i = 0; i < layoutLocales.size(); i++) {
if (scripts != null && haveCommonValue(scripts, scriptsFromLanguageTag)) { final Locale locale = layoutLocales.get(i);
int[] scripts = getScriptCodes(locale);
if (haveCommonValue(scripts, scriptsFromLanguageTag)) {
return true; return true;
} }
} }
return false; 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) { private static boolean haveCommonValue(int[] arr1, int[] arr2) {
for (int a1 : arr1) { for (int a1 : arr1) {
for (int a2 : arr2) { for (int a2 : arr2) {

View File

@@ -72,10 +72,18 @@
android:keyboardLayout="@raw/dummy_keyboard_layout" android:keyboardLayout="@raw/dummy_keyboard_layout"
android:keyboardLocale="ru-Cyrl" /> android:keyboardLocale="ru-Cyrl" />
<keyboard-layout
android:name="keyboard_layout_english_without_script_code"
android:label="English(No script code)"
android:keyboardLayout="@raw/dummy_keyboard_layout"
android:keyboardLocale="en"
android:keyboardLayoutType="qwerty" />
<keyboard-layout <keyboard-layout
android:name="keyboard_layout_vendorId:1,productId:1" android:name="keyboard_layout_vendorId:1,productId:1"
android:label="vendorId:1,productId:1" android:label="vendorId:1,productId:1"
android:keyboardLayout="@raw/dummy_keyboard_layout" android:keyboardLayout="@raw/dummy_keyboard_layout"
androidprv:vendorId="1" androidprv:vendorId="1"
androidprv:productId="1" /> androidprv:productId="1" />
</keyboard-layouts> </keyboard-layouts>

View File

@@ -26,7 +26,6 @@ import android.content.pm.ServiceInfo
import android.hardware.input.IInputManager import android.hardware.input.IInputManager
import android.hardware.input.InputManager import android.hardware.input.InputManager
import android.hardware.input.KeyboardLayout import android.hardware.input.KeyboardLayout
import android.icu.lang.UScript
import android.icu.util.ULocale import android.icu.util.ULocale
import android.os.Bundle import android.os.Bundle
import android.os.test.TestLooper import android.os.test.TestLooper
@@ -52,7 +51,6 @@ import java.io.FileNotFoundException
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.Locale
private fun createKeyboard( private fun createKeyboard(
deviceId: Int, deviceId: Int,
@@ -553,24 +551,17 @@ class KeyboardLayoutManagerTests {
0, 0,
keyboardLayouts.size keyboardLayouts.size
) )
assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
val englishScripts = UScript.getCode(Locale.forLanguageTag("hi-Latn")) "containing English(US) layout for hi-Latn",
for (kl in keyboardLayouts) { containsLayout(keyboardLayouts, ENGLISH_US_LAYOUT_DESCRIPTOR)
var isCompatible = false )
for (i in 0 until kl.locales.size()) { assertTrue("New UI: getKeyboardLayoutListForInputDevice API should return a list " +
val locale: Locale = kl.locales.get(i) ?: continue "containing English(No script code) layout for hi-Latn",
val scripts = UScript.getCode(locale) containsLayout(
if (scripts != null && areScriptsCompatible(scripts, englishScripts)) { keyboardLayouts,
isCompatible = true createLayoutDescriptor("keyboard_layout_english_without_script_code")
break )
}
}
assertTrue(
"New UI: getKeyboardLayoutListForInputDevice API should only return " +
"compatible layouts but found " + kl.descriptor,
isCompatible
) )
}
// Check Layouts for "hi" which by default uses 'Deva' script. // Check Layouts for "hi" which by default uses 'Deva' script.
keyboardLayouts = keyboardLayouts =
@@ -600,6 +591,46 @@ class KeyboardLayoutManagerTests {
1, 1,
keyboardLayouts.size 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 = private fun createLayoutDescriptor(keyboardName: String): String =
"$PACKAGE_NAME/$RECEIVER_NAME/$keyboardName" "$PACKAGE_NAME/$RECEIVER_NAME/$keyboardName"
private fun areScriptsCompatible(scriptList1: IntArray, scriptList2: IntArray): Boolean { private fun containsLayout(layoutList: Array<KeyboardLayout>, layoutDesc: String): Boolean {
for (s1 in scriptList1) { for (kl in layoutList) {
for (s2 in scriptList2) { if (kl.descriptor.equals(layoutDesc)) {
if (s1 == s2) return true return true
} }
} }
return false return false