Check all regexp patterns in ResourceUtils.getDeviceOverrideValue

This change also fixes a regexp error of Galaxy S III.

Change-Id: I42a4780bbfd2b083f4e27e61ec513aa875907344
main
Tadashi G. Takaoka 2013-05-23 14:43:12 -07:00
parent a2d8d30f8e
commit 4c75ea858a
3 changed files with 107 additions and 62 deletions

View File

@ -37,7 +37,7 @@
<item>MODEL=(SAMSUNG-)?GT-I(930[05][NT]?|9308):MANUFACTURER=samsung,8</item> <item>MODEL=(SAMSUNG-)?GT-I(930[05][NT]?|9308):MANUFACTURER=samsung,8</item>
<item>MODEL=(SAMSUNG-)?SGH-(T999[V]?|I747[M]?|N064|N035):MANUFACTURER=samsung,8</item> <item>MODEL=(SAMSUNG-)?SGH-(T999[V]?|I747[M]?|N064|N035):MANUFACTURER=samsung,8</item>
<item>MODEL=(SAMSUNG-)?SCH-(J021|R530|I535|I939):MANUFACTURER=samsung,8</item> <item>MODEL=(SAMSUNG-)?SCH-(J021|R530|I535|I939):MANUFACTURER=samsung,8</item>
<item>MODEL=(SAMSUNG-)?(SCL21|SC-06D|SC-03E]):MANUFACTURER=samsung,8</item> <item>MODEL=(SAMSUNG-)?(SCL21|SC-06D|SC-03E):MANUFACTURER=samsung,8</item>
<item>MODEL=(SAMSUNG-)?(SHV-210[KLS]?|SPH-L710):MANUFACTURER=samsung,8</item> <item>MODEL=(SAMSUNG-)?(SHV-210[KLS]?|SPH-L710):MANUFACTURER=samsung,8</item>
<!-- LG Optimus G --> <!-- LG Optimus G -->
<item>MODEL=LG-E97[013]|LS970|L-01E:MANUFACTURER=LGE,15</item> <item>MODEL=LG-E97[013]|LS970|L-01E:MANUFACTURER=LGE,15</item>

View File

@ -27,6 +27,7 @@ import com.android.inputmethod.annotations.UsedForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.regex.PatternSyntaxException;
public final class ResourceUtils { public final class ResourceUtils {
private static final String TAG = ResourceUtils.class.getSimpleName(); private static final String TAG = ResourceUtils.class.getSimpleName();
@ -83,7 +84,9 @@ public final class ResourceUtils {
return overrideValue; return overrideValue;
} }
final String defaultValue = findDefaultConstant(overrideArray); String defaultValue = null;
try {
defaultValue = findDefaultConstant(overrideArray);
// The defaultValue might be an empty string. // The defaultValue might be an empty string.
if (defaultValue == null) { if (defaultValue == null) {
Log.w(TAG, "Couldn't find override value nor default value:" Log.w(TAG, "Couldn't find override value nor default value:"
@ -95,10 +98,25 @@ public final class ResourceUtils {
+ " build=" + sBuildKeyValuesDebugString + " build=" + sBuildKeyValuesDebugString
+ " default=" + defaultValue); + " default=" + defaultValue);
} }
} catch (final DeviceOverridePatternSyntaxError e) {
Log.w(TAG, "Syntax error, ignored", e);
}
sDeviceOverrideValueMap.put(key, defaultValue); sDeviceOverrideValueMap.put(key, defaultValue);
return defaultValue; return defaultValue;
} }
@SuppressWarnings("serial")
static class DeviceOverridePatternSyntaxError extends Exception {
public DeviceOverridePatternSyntaxError(final String message, final String expression) {
this(message, expression, null);
}
public DeviceOverridePatternSyntaxError(final String message, final String expression,
final Throwable throwable) {
super(message + ": " + expression, throwable);
}
}
/** /**
* Find the condition that fulfills specified key value pairs from an array of * Find the condition that fulfills specified key value pairs from an array of
* "condition,constant", and return the corresponding string constant. A condition is * "condition,constant", and return the corresponding string constant. A condition is
@ -123,10 +141,12 @@ public final class ResourceUtils {
if (conditionConstantArray == null || keyValuePairs == null) { if (conditionConstantArray == null || keyValuePairs == null) {
return null; return null;
} }
String foundValue = null;
for (final String conditionConstant : conditionConstantArray) { for (final String conditionConstant : conditionConstantArray) {
final int posComma = conditionConstant.indexOf(','); final int posComma = conditionConstant.indexOf(',');
if (posComma < 0) { if (posComma < 0) {
throw new RuntimeException("Array element has no comma: " + conditionConstant); Log.w(TAG, "Array element has no comma: " + conditionConstant);
continue;
} }
final String condition = conditionConstant.substring(0, posComma); final String condition = conditionConstant.substring(0, posComma);
if (condition.isEmpty()) { if (condition.isEmpty()) {
@ -134,44 +154,59 @@ public final class ResourceUtils {
// {@link #findConstantForDefault(String[])}. // {@link #findConstantForDefault(String[])}.
continue; continue;
} }
try {
if (fulfillsCondition(keyValuePairs, condition)) { if (fulfillsCondition(keyValuePairs, condition)) {
return conditionConstant.substring(posComma + 1); // Take first match
if (foundValue == null) {
foundValue = conditionConstant.substring(posComma + 1);
}
// And continue walking through all conditions.
}
} catch (final DeviceOverridePatternSyntaxError e) {
Log.w(TAG, "Syntax error, ignored", e);
} }
} }
return null; return foundValue;
} }
private static boolean fulfillsCondition(final HashMap<String,String> keyValuePairs, private static boolean fulfillsCondition(final HashMap<String,String> keyValuePairs,
final String condition) { final String condition) throws DeviceOverridePatternSyntaxError {
final String[] patterns = condition.split(":"); final String[] patterns = condition.split(":");
// Check all patterns in a condition are true // Check all patterns in a condition are true
boolean matchedAll = true;
for (final String pattern : patterns) { for (final String pattern : patterns) {
final int posEqual = pattern.indexOf('='); final int posEqual = pattern.indexOf('=');
if (posEqual < 0) { if (posEqual < 0) {
throw new RuntimeException("Pattern has no '=': " + condition); throw new DeviceOverridePatternSyntaxError("Pattern has no '='", condition);
} }
final String key = pattern.substring(0, posEqual); final String key = pattern.substring(0, posEqual);
final String value = keyValuePairs.get(key); final String value = keyValuePairs.get(key);
if (value == null) { if (value == null) {
throw new RuntimeException("Found unknown key: " + condition); throw new DeviceOverridePatternSyntaxError("Unknown key", condition);
} }
final String patternRegexpValue = pattern.substring(posEqual + 1); final String patternRegexpValue = pattern.substring(posEqual + 1);
try {
if (!value.matches(patternRegexpValue)) { if (!value.matches(patternRegexpValue)) {
return false; matchedAll = false;
// And continue walking through all patterns.
}
} catch (final PatternSyntaxException e) {
throw new DeviceOverridePatternSyntaxError("Syntax error", condition, e);
} }
} }
return true; return matchedAll;
} }
@UsedForTesting @UsedForTesting
static String findDefaultConstant(final String[] conditionConstantArray) { static String findDefaultConstant(final String[] conditionConstantArray)
throws DeviceOverridePatternSyntaxError {
if (conditionConstantArray == null) { if (conditionConstantArray == null) {
return null; return null;
} }
for (final String condition : conditionConstantArray) { for (final String condition : conditionConstantArray) {
final int posComma = condition.indexOf(','); final int posComma = condition.indexOf(',');
if (posComma < 0) { if (posComma < 0) {
throw new RuntimeException("Array element has no comma: " + condition); throw new DeviceOverridePatternSyntaxError("Array element has no comma", condition);
} }
if (posComma == 0) { // condition is empty. if (posComma == 0) { // condition is empty.
return condition.substring(posComma + 1); return condition.substring(posComma + 1);

View File

@ -19,17 +19,15 @@ package com.android.inputmethod.latin;
import android.test.AndroidTestCase; import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.latin.ResourceUtils.DeviceOverridePatternSyntaxError;
import java.util.HashMap; import java.util.HashMap;
@SmallTest @SmallTest
public class ResourceUtilsTests extends AndroidTestCase { public class ResourceUtilsTests extends AndroidTestCase {
public void testFindDefaultConstant() { public void testFindDefaultConstant() {
final String[] nullArray = null; final String[] nullArray = null;
assertNull(ResourceUtils.findDefaultConstant(nullArray));
final String[] emptyArray = {}; final String[] emptyArray = {};
assertNull(ResourceUtils.findDefaultConstant(emptyArray));
final String[] array = { final String[] array = {
"HARDWARE=grouper,0.3", "HARDWARE=grouper,0.3",
"HARDWARE=mako,0.4", "HARDWARE=mako,0.4",
@ -37,7 +35,25 @@ public class ResourceUtilsTests extends AndroidTestCase {
"HARDWARE=manta,0.2", "HARDWARE=manta,0.2",
",defaultValue2", ",defaultValue2",
}; };
try {
assertNull(ResourceUtils.findDefaultConstant(nullArray));
assertNull(ResourceUtils.findDefaultConstant(emptyArray));
assertEquals(ResourceUtils.findDefaultConstant(array), "defaultValue1"); assertEquals(ResourceUtils.findDefaultConstant(array), "defaultValue1");
} catch (final DeviceOverridePatternSyntaxError e) {
fail(e.getMessage());
}
final String[] errorArray = {
"HARDWARE=grouper,0.3",
"no_comma"
};
try {
final String defaultValue = ResourceUtils.findDefaultConstant(errorArray);
fail("exception should be thrown: defaultValue=" + defaultValue);
} catch (final DeviceOverridePatternSyntaxError e) {
assertEquals("Array element has no comma: no_comma", e.getMessage());
}
} }
public void testFindConstantForKeyValuePairsSimple() { public void testFindConstantForKeyValuePairsSimple() {
@ -67,33 +83,23 @@ public class ResourceUtilsTests extends AndroidTestCase {
final HashMap<String,String> keyValues = CollectionUtils.newHashMap(); final HashMap<String,String> keyValues = CollectionUtils.newHashMap();
keyValues.put(HARDWARE_KEY, "grouper"); keyValues.put(HARDWARE_KEY, "grouper");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.3"); assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.put(HARDWARE_KEY, "mako"); keyValues.put(HARDWARE_KEY, "mako");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.4"); assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.put(HARDWARE_KEY, "manta"); keyValues.put(HARDWARE_KEY, "manta");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.2"); assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
try {
keyValues.clear(); keyValues.clear();
keyValues.put("hardware", "grouper"); keyValues.put("hardware", "grouper");
final String constant = ResourceUtils.findConstantForKeyValuePairs(keyValues, array); assertNull(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.clear();
keyValues.put(HARDWARE_KEY, "MAKO"); keyValues.put(HARDWARE_KEY, "MAKO");
assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array)); assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.put(HARDWARE_KEY, "mantaray"); keyValues.put(HARDWARE_KEY, "mantaray");
assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array)); assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
try { assertNull(ResourceUtils.findConstantForKeyValuePairs(emptyKeyValue, array));
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() { public void testFindConstantForKeyValuePairsCombined() {
@ -102,6 +108,8 @@ public class ResourceUtilsTests extends AndroidTestCase {
final String MANUFACTURER_KEY = "MANUFACTURER"; final String MANUFACTURER_KEY = "MANUFACTURER";
final String[] array = { final String[] array = {
",defaultValue", ",defaultValue",
"no_comma",
"error_pattern,0.1",
"HARDWARE=grouper:MANUFACTURER=asus,0.3", "HARDWARE=grouper:MANUFACTURER=asus,0.3",
"HARDWARE=mako:MODEL=Nexus 4,0.4", "HARDWARE=mako:MODEL=Nexus 4,0.4",
"HARDWARE=manta:MODEL=Nexus 10:MANUFACTURER=samsung,0.2" "HARDWARE=manta:MODEL=Nexus 10:MANUFACTURER=samsung,0.2"
@ -117,25 +125,25 @@ public class ResourceUtilsTests extends AndroidTestCase {
keyValues.put(HARDWARE_KEY, "grouper"); keyValues.put(HARDWARE_KEY, "grouper");
keyValues.put(MODEL_KEY, "Nexus 7"); keyValues.put(MODEL_KEY, "Nexus 7");
keyValues.put(MANUFACTURER_KEY, "asus"); keyValues.put(MANUFACTURER_KEY, "asus");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.3"); assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray)); assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
keyValues.clear(); keyValues.clear();
keyValues.put(HARDWARE_KEY, "mako"); keyValues.put(HARDWARE_KEY, "mako");
keyValues.put(MODEL_KEY, "Nexus 4"); keyValues.put(MODEL_KEY, "Nexus 4");
keyValues.put(MANUFACTURER_KEY, "LGE"); keyValues.put(MANUFACTURER_KEY, "LGE");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.4"); assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray)); assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
keyValues.clear(); keyValues.clear();
keyValues.put(HARDWARE_KEY, "manta"); keyValues.put(HARDWARE_KEY, "manta");
keyValues.put(MODEL_KEY, "Nexus 10"); keyValues.put(MODEL_KEY, "Nexus 10");
keyValues.put(MANUFACTURER_KEY, "samsung"); keyValues.put(MANUFACTURER_KEY, "samsung");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.2"); assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray)); assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
keyValues.put(HARDWARE_KEY, "mantaray"); keyValues.put(HARDWARE_KEY, "mantaray");
assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array)); assertNull(ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray), "0.2"); assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, failArray));
} }
public void testFindConstantForKeyValuePairsRegexp() { public void testFindConstantForKeyValuePairsRegexp() {
@ -144,6 +152,8 @@ public class ResourceUtilsTests extends AndroidTestCase {
final String MANUFACTURER_KEY = "MANUFACTURER"; final String MANUFACTURER_KEY = "MANUFACTURER";
final String[] array = { final String[] array = {
",defaultValue", ",defaultValue",
"no_comma",
"HARDWARE=error_regexp:MANUFACTURER=error[regexp,0.1",
"HARDWARE=grouper|tilapia:MANUFACTURER=asus,0.3", "HARDWARE=grouper|tilapia:MANUFACTURER=asus,0.3",
"HARDWARE=[mM][aA][kK][oO]:MODEL=Nexus 4,0.4", "HARDWARE=[mM][aA][kK][oO]:MODEL=Nexus 4,0.4",
"HARDWARE=manta.*:MODEL=Nexus 10:MANUFACTURER=samsung,0.2" "HARDWARE=manta.*:MODEL=Nexus 10:MANUFACTURER=samsung,0.2"
@ -153,24 +163,24 @@ public class ResourceUtilsTests extends AndroidTestCase {
keyValues.put(HARDWARE_KEY, "grouper"); keyValues.put(HARDWARE_KEY, "grouper");
keyValues.put(MODEL_KEY, "Nexus 7"); keyValues.put(MODEL_KEY, "Nexus 7");
keyValues.put(MANUFACTURER_KEY, "asus"); keyValues.put(MANUFACTURER_KEY, "asus");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.3"); assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.put(HARDWARE_KEY, "tilapia"); keyValues.put(HARDWARE_KEY, "tilapia");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.3"); assertEquals("0.3", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.clear(); keyValues.clear();
keyValues.put(HARDWARE_KEY, "mako"); keyValues.put(HARDWARE_KEY, "mako");
keyValues.put(MODEL_KEY, "Nexus 4"); keyValues.put(MODEL_KEY, "Nexus 4");
keyValues.put(MANUFACTURER_KEY, "LGE"); keyValues.put(MANUFACTURER_KEY, "LGE");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.4"); assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.put(HARDWARE_KEY, "MAKO"); keyValues.put(HARDWARE_KEY, "MAKO");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.4"); assertEquals("0.4", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.clear(); keyValues.clear();
keyValues.put(HARDWARE_KEY, "manta"); keyValues.put(HARDWARE_KEY, "manta");
keyValues.put(MODEL_KEY, "Nexus 10"); keyValues.put(MODEL_KEY, "Nexus 10");
keyValues.put(MANUFACTURER_KEY, "samsung"); keyValues.put(MANUFACTURER_KEY, "samsung");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.2"); assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
keyValues.put(HARDWARE_KEY, "mantaray"); keyValues.put(HARDWARE_KEY, "mantaray");
assertEquals(ResourceUtils.findConstantForKeyValuePairs(keyValues, array), "0.2"); assertEquals("0.2", ResourceUtils.findConstantForKeyValuePairs(keyValues, array));
} }
} }