From d69fa0a09af7e9a524751dac1522c951abd92530 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Mon, 13 May 2013 10:25:42 +0900 Subject: [PATCH] Support multiple condition for getDeviceOverrideValue Bug: 8556975 Change-Id: I29d3a305b6ac3d8e3620c6d8592d85047d62bf48 --- java/res/values/keyboard-heights.xml | 2 +- .../values/keypress-vibration-durations.xml | 2 +- java/res/values/keypress-volumes.xml | 2 +- .../phantom-sudden-move-event-device-list.xml | 2 +- ...sudden-jumping-touch-event-device-list.xml | 2 +- .../inputmethod/latin/ResourceUtils.java | 120 ++++++++++++++- .../inputmethod/latin/StringUtils.java | 24 --- .../inputmethod/latin/ResourceUtilsTests.java | 140 ++++++++++++++++++ .../inputmethod/latin/StringUtilsTests.java | 61 +------- 9 files changed, 259 insertions(+), 96 deletions(-) create mode 100644 tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java diff --git a/java/res/values/keyboard-heights.xml b/java/res/values/keyboard-heights.xml index 1c0277c2c..c651a89b3 100644 --- a/java/res/values/keyboard-heights.xml +++ b/java/res/values/keyboard-heights.xml @@ -34,6 +34,6 @@ HARDWARE=stingray,283.1337 - DEFAULT, + , diff --git a/java/res/values/keypress-vibration-durations.xml b/java/res/values/keypress-vibration-durations.xml index 45c51e71b..53aad72b7 100644 --- a/java/res/values/keypress-vibration-durations.xml +++ b/java/res/values/keypress-vibration-durations.xml @@ -29,6 +29,6 @@ HARDWARE=manta,16 - DEFAULT,20 + ,20 diff --git a/java/res/values/keypress-volumes.xml b/java/res/values/keypress-volumes.xml index 7061f1310..a096c341b 100644 --- a/java/res/values/keypress-volumes.xml +++ b/java/res/values/keypress-volumes.xml @@ -27,6 +27,6 @@ HARDWARE=mako,0.3f HARDWARE=manta,0.2f - DEFAULT,0.2f + ,0.2f diff --git a/java/res/values/phantom-sudden-move-event-device-list.xml b/java/res/values/phantom-sudden-move-event-device-list.xml index d0895b158..53002b31e 100644 --- a/java/res/values/phantom-sudden-move-event-device-list.xml +++ b/java/res/values/phantom-sudden-move-event-device-list.xml @@ -24,6 +24,6 @@ HARDWARE=stingray,true - DEFAULT,false + ,false diff --git a/java/res/values/sudden-jumping-touch-event-device-list.xml b/java/res/values/sudden-jumping-touch-event-device-list.xml index 73e30c17d..3a9c379a7 100644 --- a/java/res/values/sudden-jumping-touch-event-device-list.xml +++ b/java/res/values/sudden-jumping-touch-event-device-list.xml @@ -26,6 +26,6 @@ HARDWARE=sholes,true - DEFAULT,false + ,false diff --git a/java/src/com/android/inputmethod/latin/ResourceUtils.java b/java/src/com/android/inputmethod/latin/ResourceUtils.java index f0bfe75fe..488a0e313 100644 --- a/java/src/com/android/inputmethod/latin/ResourceUtils.java +++ b/java/src/com/android/inputmethod/latin/ResourceUtils.java @@ -19,9 +19,13 @@ package com.android.inputmethod.latin; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Build; +import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; +import com.android.inputmethod.annotations.UsedForTesting; + +import java.util.ArrayList; import java.util.HashMap; public final class ResourceUtils { @@ -35,10 +39,31 @@ public final class ResourceUtils { // This utility class is not publicly instantiable. } - private static final String DEFAULT_KEY = "DEFAULT"; private static final HashMap sDeviceOverrideValueMap = CollectionUtils.newHashMap(); + private static final String[] BUILD_KEYS_AND_VALUES = { + "HARDWARE", Build.HARDWARE, + "MODEL", Build.MODEL, + "MANUFACTURER", Build.MANUFACTURER + }; + private static final HashMap sBuildKeyValues; + private static final String sBuildKeyValuesDebugString; + + static { + sBuildKeyValues = CollectionUtils.newHashMap(); + final ArrayList keyValuePairs = CollectionUtils.newArrayList(); + final int keyCount = BUILD_KEYS_AND_VALUES.length / 2; + for (int i = 0; i < keyCount; i++) { + final int index = i * 2; + final String key = BUILD_KEYS_AND_VALUES[index]; + final String value = BUILD_KEYS_AND_VALUES[index + 1]; + sBuildKeyValues.put(key, value); + keyValuePairs.add(key + '=' + value); + } + sBuildKeyValuesDebugString = "[" + TextUtils.join(" ", keyValuePairs) + "]"; + } + public static String getDeviceOverrideValue(final Resources res, final int overrideResId) { final int orientation = res.getConfiguration().orientation; final String key = overrideResId + "-" + orientation; @@ -47,34 +72,115 @@ public final class ResourceUtils { } final String[] overrideArray = res.getStringArray(overrideResId); - final String hardwareKey = "HARDWARE=" + Build.HARDWARE; - final String overrideValue = StringUtils.findValueOfKey(hardwareKey, overrideArray); + final String overrideValue = findConstantForKeyValuePairs(sBuildKeyValues, overrideArray); // The overrideValue might be an empty string. if (overrideValue != null) { if (DEBUG) { Log.d(TAG, "Find override value:" + " resource="+ res.getResourceEntryName(overrideResId) - + " " + hardwareKey + " override=" + overrideValue); + + " build=" + sBuildKeyValuesDebugString + + " override=" + overrideValue); } sDeviceOverrideValueMap.put(key, overrideValue); return overrideValue; } - final String defaultValue = StringUtils.findValueOfKey(DEFAULT_KEY, overrideArray); + final String defaultValue = findDefaultConstant(overrideArray); // The defaultValue might be an empty string. if (defaultValue == null) { Log.w(TAG, "Couldn't find override value nor default value:" + " resource="+ res.getResourceEntryName(overrideResId) - + " " + hardwareKey); + + " build=" + sBuildKeyValuesDebugString); } else if (DEBUG) { Log.d(TAG, "Found default value:" + " resource="+ res.getResourceEntryName(overrideResId) - + " " + hardwareKey + " " + DEFAULT_KEY + "=" + defaultValue); + + " build=" + sBuildKeyValuesDebugString + " default=" + defaultValue); } sDeviceOverrideValueMap.put(key, defaultValue); return defaultValue; } + /** + * Find the condition that fulfills specified key value pairs from an array of + * "condition,constant", and return the corresponding string constant. A condition is + * "pattern1[:pattern2...] (or an empty string for the default). A pattern is "key=value" + * string. The condition matches only if all patterns of the condition are true for the + * specified key value pairs. + * + * For example, "condition,constant" has the following format. + * (See {@link ResourceUtilsTests#testFindConstantForKeyValuePairsCombined()}) + * - HARDWARE=mako,constantForNexus4 + * - MODEL=Nexus 4:MANUFACTURER=LGE,constantForNexus4 + * - ,defaultConstant + * + * @param keyValuePairs attributes to be used to look for a matched condition. + * @param conditionConstantArray an array of "condition,constant" elements to be searched. + * @return the constant part of the matched "condition,constant" element. Returns null if no + * condition matches. + */ + @UsedForTesting + static String findConstantForKeyValuePairs(final HashMap keyValuePairs, + final String[] conditionConstantArray) { + if (conditionConstantArray == null || keyValuePairs == null) { + return null; + } + for (final String conditionConstant : conditionConstantArray) { + final int posComma = conditionConstant.indexOf(','); + if (posComma < 0) { + throw new RuntimeException("Array element has no comma: " + conditionConstant); + } + final String condition = conditionConstant.substring(0, posComma); + if (condition.isEmpty()) { + // Default condition. The default condition should be searched by + // {@link #findConstantForDefault(String[])}. + continue; + } + if (fulfillsCondition(keyValuePairs, condition)) { + return conditionConstant.substring(posComma + 1); + } + } + return null; + } + + private static boolean fulfillsCondition(final HashMap keyValuePairs, + final String condition) { + final String[] patterns = condition.split(":"); + // Check all patterns in a condition are true + for (final String pattern : patterns) { + final int posEqual = pattern.indexOf('='); + if (posEqual < 0) { + throw new RuntimeException("Pattern has no '=': " + condition); + } + final String key = pattern.substring(0, posEqual); + final String value = keyValuePairs.get(key); + if (value == null) { + throw new RuntimeException("Found unknown key: " + condition); + } + final String patternValue = pattern.substring(posEqual + 1); + if (!value.equals(patternValue)) { + return false; + } + } + return true; + } + + @UsedForTesting + static String findDefaultConstant(final String[] conditionConstantArray) { + if (conditionConstantArray == null) { + return null; + } + for (final String condition : conditionConstantArray) { + final int posComma = condition.indexOf(','); + if (posComma < 0) { + throw new RuntimeException("Array element has no comma: " + condition); + } + if (posComma == 0) { // condition is empty. + return condition.substring(posComma + 1); + } + } + return null; + } + public static boolean isValidFraction(final float fraction) { return fraction >= 0.0f; } diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 5ff101f7a..ab050d7a3 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -64,30 +64,6 @@ public final class StringUtils { return TextUtils.join(",", result); } - /** - * Find a value that has a specified key from an array of key-comma-value. - * - * @param key a key string to find. - * @param array an array of key-comma-value string to be searched. - * @return the value part of the first string that has a specified key. - * Returns null if it couldn't be found. - */ - public static String findValueOfKey(final String key, final String[] array) { - if (array == null) { - return null; - } - for (final String element : array) { - final int posComma = element.indexOf(','); - if (posComma < 0) { - throw new RuntimeException("Element has no comma: " + element); - } - if (element.substring(0, posComma).equals(key)) { - return element.substring(posComma + 1); - } - } - return null; - } - /** * Remove duplicates from an array of strings. * diff --git a/tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java b/tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java new file mode 100644 index 000000000..fa6df7010 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import java.util.HashMap; + +@SmallTest +public class ResourceUtilsTests extends AndroidTestCase { + public void testFindDefaultConstant() { + final String[] nullArray = null; + assertNull(ResourceUtils.findDefaultConstant(nullArray)); + + final String[] emptyArray = {}; + assertNull(ResourceUtils.findDefaultConstant(emptyArray)); + + final String[] array = { + "HARDWARE=grouper,0.3", + "HARDWARE=mako,0.4", + ",defaultValue1", + "HARDWARE=manta,0.2", + ",defaultValue2", + }; + assertEquals(ResourceUtils.findDefaultConstant(array), "defaultValue1"); + } + + public void testFindConstantForKeyValuePairsSimple() { + final HashMap anyKeyValue = CollectionUtils.newHashMap(); + anyKeyValue.put("anyKey", "anyValue"); + final HashMap nullKeyValue = null; + final HashMap emptyKeyValue = CollectionUtils.newHashMap(); + + final String[] nullArray = null; + assertNull(ResourceUtils.findConstantForKeyValuePairs(anyKeyValue, nullArray)); + assertNull(ResourceUtils.findConstantForKeyValuePairs(emptyKeyValue, nullArray)); + assertNull(ResourceUtils.findConstantForKeyValuePairs(nullKeyValue, nullArray)); + + final String[] emptyArray = {}; + assertNull(ResourceUtils.findConstantForKeyValuePairs(anyKeyValue, emptyArray)); + assertNull(ResourceUtils.findConstantForKeyValuePairs(emptyKeyValue, emptyArray)); + assertNull(ResourceUtils.findConstantForKeyValuePairs(nullKeyValue, emptyArray)); + + final String HARDWARE_KEY = "HARDWARE"; + final String[] array = { + ",defaultValue", + "HARDWARE=grouper,0.3", + "HARDWARE=mako,0.4", + "HARDWARE=manta,0.2", + "HARDWARE=mako,0.5", + }; + + final HashMap keyValues = CollectionUtils.newHashMap(); + keyValues.put(HARDWARE_KEY, "grouper"); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.3"); + keyValues.put(HARDWARE_KEY, "mako"); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.4"); + keyValues.put(HARDWARE_KEY, "manta"); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.2"); + + try { + keyValues.clear(); + keyValues.put("hardware", "grouper"); + final String constant = ResourceUtils.findConstantForKeyValuePairs(keyValues, array); + fail("condition without HARDWARE must fail: constant=" + constant); + } catch (final RuntimeException e) { + assertEquals(e.getMessage(), "Found unknown key: HARDWARE=grouper"); + } + keyValues.clear(); + keyValues.put(HARDWARE_KEY, "MAKO"); + assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array)); + keyValues.put(HARDWARE_KEY, "mantaray"); + assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array)); + + try { + final String constant = ResourceUtils.findConstantForKeyValuePairs( + emptyKeyValue, array); + fail("emptyCondition shouldn't match: constant=" + constant); + } catch (final RuntimeException e) { + assertEquals(e.getMessage(), "Found unknown key: HARDWARE=grouper"); + } + } + + public void testFindConstantForKeyValuePairsCombined() { + final String HARDWARE_KEY = "HARDWARE"; + final String MODEL_KEY = "MODEL"; + final String MANUFACTURER_KEY = "MANUFACTURER"; + final String[] array = { + ",defaultValue", + "HARDWARE=grouper:MANUFACTURER=asus,0.3", + "HARDWARE=mako:MODEL=Nexus 4,0.4", + "HARDWARE=manta:MODEL=Nexus 10:MANUFACTURER=samsung,0.2" + }; + final String[] failArray = { + ",defaultValue", + "HARDWARE=grouper:MANUFACTURER=ASUS,0.3", + "HARDWARE=mako:MODEL=Nexus_4,0.4", + "HARDWARE=mantaray:MODEL=Nexus 10:MANUFACTURER=samsung,0.2" + }; + + final HashMap keyValues = CollectionUtils.newHashMap(); + keyValues.put(HARDWARE_KEY, "grouper"); + keyValues.put(MODEL_KEY, "Nexus 7"); + keyValues.put(MANUFACTURER_KEY, "asus"); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.3"); + assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray)); + + keyValues.clear(); + keyValues.put(HARDWARE_KEY, "mako"); + keyValues.put(MODEL_KEY, "Nexus 4"); + keyValues.put(MANUFACTURER_KEY, "LGE"); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.4"); + assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray)); + + keyValues.clear(); + keyValues.put(HARDWARE_KEY, "manta"); + keyValues.put(MODEL_KEY, "Nexus 10"); + keyValues.put(MANUFACTURER_KEY, "samsung"); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.2"); + assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray)); + keyValues.put(HARDWARE_KEY, "mantaray"); + assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array)); + assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray), "0.2"); + } +} diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java index b6a17a3a3..29e790a7d 100644 --- a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/StringUtilsTests.java @@ -178,7 +178,7 @@ public class StringUtilsTests extends AndroidTestCase { assertTrue(StringUtils.isIdenticalAfterDowncase("")); } - private void checkCapitalize(final String src, final String dst, final String separators, + private static void checkCapitalize(final String src, final String dst, final String separators, final Locale locale) { assertEquals(dst, StringUtils.capitalizeEachWord(src, separators, locale)); assert(src.equals(dst) @@ -237,63 +237,4 @@ public class StringUtilsTests extends AndroidTestCase { // code for now True is acceptable. assertTrue(StringUtils.lastPartLooksLikeURL(".abc/def")); } - - public void testFindValueOfKey() { - final String nullKey = null; - final String emptyKey = ""; - - final String[] nullArray = null; - assertNull(StringUtils.findValueOfKey("anyKey", nullArray)); - assertNull(StringUtils.findValueOfKey(emptyKey, nullArray)); - assertNull(StringUtils.findValueOfKey(nullKey, nullArray)); - - final String[] emptyArray = {}; - assertNull(StringUtils.findValueOfKey("anyKey", emptyArray)); - assertNull(StringUtils.findValueOfKey(emptyKey, emptyArray)); - assertNull(StringUtils.findValueOfKey(nullKey, emptyArray)); - - final String[] array = { - "DEFAULT,defaultValue", - "HARDWARE=grouper,0.3", - "HARDWARE=mako,0.4", - "HARDWARE=manta,0.2" - }; - assertEquals(StringUtils.findValueOfKey("HARDWARE=grouper", array), "0.3"); - assertEquals(StringUtils.findValueOfKey("HARDWARE=mako", array), "0.4"); - assertEquals(StringUtils.findValueOfKey("HARDWARE=manta", array), "0.2"); - assertEquals(StringUtils.findValueOfKey("DEFAULT", array), "defaultValue"); - - assertNull(StringUtils.findValueOfKey("hardware=grouper", array)); - assertNull(StringUtils.findValueOfKey("HARDWARE=MAKO", array)); - assertNull(StringUtils.findValueOfKey("HARDWARE=mantaray", array)); - assertNull(StringUtils.findValueOfKey(emptyKey, array)); - assertNull(StringUtils.findValueOfKey(nullKey, array)); - - final String[] containsNullKey = { - "DEFAULT,defaultValue", - ",emptyValue" - }; - assertEquals(StringUtils.findValueOfKey(emptyKey, containsNullKey), "emptyValue"); - - final String[] containsMultipleSameKeys = { - "key1,value1", - "key2,value2", - "key3,value3", - "key2,value4" - }; - assertEquals(StringUtils.findValueOfKey("key2", containsMultipleSameKeys), "value2"); - - final String[] containNoCommaElement = { - "key1,value1", - "key2-and-value2", - "key3,value3" - }; - assertEquals(StringUtils.findValueOfKey("key1", containNoCommaElement), "value1"); - try { - final String valueOfKey3 = StringUtils.findValueOfKey("key3", containNoCommaElement); - fail("finding valueOfKey3=" + valueOfKey3 + " must fail"); - } catch (final RuntimeException e) { - assertEquals(e.getMessage(), "Element has no comma: key2-and-value2"); - } - } }