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");
- }
- }
}