19879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka/* 29879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project 39879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * 49879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 59879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * you may not use this file except in compliance with the License. 69879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * You may obtain a copy of the License at 79879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * 89879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 99879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * 109879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 119879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 129879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * See the License for the specific language governing permissions and 149879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka * limitations under the License. 159879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka */ 169879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka 17e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasapackage com.android.inputmethod.latin.utils; 189879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka 199879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaokaimport android.content.res.Resources; 2092821614fd80112527e133f069e31ee48250314fTadashi G. Takaokaimport android.content.res.TypedArray; 219879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaokaimport android.os.Build; 22d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaokaimport android.text.TextUtils; 233897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaokaimport android.util.DisplayMetrics; 24fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaokaimport android.util.Log; 2592821614fd80112527e133f069e31ee48250314fTadashi G. Takaokaimport android.util.TypedValue; 269879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka 27d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting; 283897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaokaimport com.android.inputmethod.latin.R; 29bb9400aebc4cb0291b4f0208ecbc9ddc01dc79e1Andy Wangimport com.android.inputmethod.latin.settings.SettingsValues; 30d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka 31d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaokaimport java.util.ArrayList; 329879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaokaimport java.util.HashMap; 334c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaokaimport java.util.regex.PatternSyntaxException; 349879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka 351e11c44d1b5f9ddf593c5407cb14c458be0056f2Tadashi G. Takaokapublic final class ResourceUtils { 36fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka private static final String TAG = ResourceUtils.class.getSimpleName(); 37fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka 3892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka public static final float UNDEFINED_RATIO = -1.0f; 3992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka public static final int UNDEFINED_DIMENSION = -1; 4092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 419879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka private ResourceUtils() { 429879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka // This utility class is not publicly instantiable. 439879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka } 449879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka 45a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka private static final HashMap<String, String> sDeviceOverrideValueMap = new HashMap<>(); 469879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka 47d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka private static final String[] BUILD_KEYS_AND_VALUES = { 48d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka "HARDWARE", Build.HARDWARE, 49d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka "MODEL", Build.MODEL, 50b5f67e7faf498eac634be0cfd2b8d4ac7e9a3b76Tadashi G. Takaoka "BRAND", Build.BRAND, 51d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka "MANUFACTURER", Build.MANUFACTURER 52d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka }; 53d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka private static final HashMap<String, String> sBuildKeyValues; 54d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka private static final String sBuildKeyValuesDebugString; 55d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka 56d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka static { 57a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka sBuildKeyValues = new HashMap<>(); 58a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka final ArrayList<String> keyValuePairs = new ArrayList<>(); 59d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final int keyCount = BUILD_KEYS_AND_VALUES.length / 2; 60d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka for (int i = 0; i < keyCount; i++) { 61d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final int index = i * 2; 62d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String key = BUILD_KEYS_AND_VALUES[index]; 63d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String value = BUILD_KEYS_AND_VALUES[index + 1]; 64d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka sBuildKeyValues.put(key, value); 65d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka keyValuePairs.add(key + '=' + value); 66d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 67d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka sBuildKeyValuesDebugString = "[" + TextUtils.join(" ", keyValuePairs) + "]"; 68d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 69d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka 70bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka public static String getDeviceOverrideValue(final Resources res, final int overrideResId, 71bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka final String defaultValue) { 729879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka final int orientation = res.getConfiguration().orientation; 739879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka final String key = overrideResId + "-" + orientation; 74fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka if (sDeviceOverrideValueMap.containsKey(key)) { 75fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka return sDeviceOverrideValueMap.get(key); 76fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka } 77fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka 78fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka final String[] overrideArray = res.getStringArray(overrideResId); 79d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String overrideValue = findConstantForKeyValuePairs(sBuildKeyValues, overrideArray); 80fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka // The overrideValue might be an empty string. 81fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka if (overrideValue != null) { 82b5f67e7faf498eac634be0cfd2b8d4ac7e9a3b76Tadashi G. Takaoka Log.i(TAG, "Find override value:" 83b5f67e7faf498eac634be0cfd2b8d4ac7e9a3b76Tadashi G. Takaoka + " resource="+ res.getResourceEntryName(overrideResId) 84b5f67e7faf498eac634be0cfd2b8d4ac7e9a3b76Tadashi G. Takaoka + " build=" + sBuildKeyValuesDebugString 85b5f67e7faf498eac634be0cfd2b8d4ac7e9a3b76Tadashi G. Takaoka + " override=" + overrideValue); 869879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka sDeviceOverrideValueMap.put(key, overrideValue); 87fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka return overrideValue; 88fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka } 89fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka 90fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka sDeviceOverrideValueMap.put(key, defaultValue); 91fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka return defaultValue; 929879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka } 9392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 944c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka @SuppressWarnings("serial") 954c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka static class DeviceOverridePatternSyntaxError extends Exception { 964c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka public DeviceOverridePatternSyntaxError(final String message, final String expression) { 974c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka this(message, expression, null); 984c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } 994c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka 1004c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka public DeviceOverridePatternSyntaxError(final String message, final String expression, 1014c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka final Throwable throwable) { 1024c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka super(message + ": " + expression, throwable); 1034c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } 1044c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } 1054c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka 106d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka /** 107d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * Find the condition that fulfills specified key value pairs from an array of 108d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * "condition,constant", and return the corresponding string constant. A condition is 10918184eacb149f1b12b859ff8631340a9f73bf8acTadashi G. Takaoka * "pattern1[:pattern2...] (or an empty string for the default). A pattern is 11018184eacb149f1b12b859ff8631340a9f73bf8acTadashi G. Takaoka * "key=regexp_value" string. The condition matches only if all patterns of the condition 11118184eacb149f1b12b859ff8631340a9f73bf8acTadashi G. Takaoka * are true for the specified key value pairs. 112d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * 113d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * For example, "condition,constant" has the following format. 114d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * - HARDWARE=mako,constantForNexus4 115d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * - MODEL=Nexus 4:MANUFACTURER=LGE,constantForNexus4 116d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * - ,defaultConstant 117d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * 118d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * @param keyValuePairs attributes to be used to look for a matched condition. 119d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * @param conditionConstantArray an array of "condition,constant" elements to be searched. 120d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * @return the constant part of the matched "condition,constant" element. Returns null if no 121d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka * condition matches. 122d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka * @see com.android.inputmethod.latin.utils.ResourceUtilsTests#testFindConstantForKeyValuePairsRegexp() 123d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka */ 124d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka @UsedForTesting 125d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka static String findConstantForKeyValuePairs(final HashMap<String, String> keyValuePairs, 126d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String[] conditionConstantArray) { 127d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka if (conditionConstantArray == null || keyValuePairs == null) { 128d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka return null; 129d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 1304c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka String foundValue = null; 131d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka for (final String conditionConstant : conditionConstantArray) { 132d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final int posComma = conditionConstant.indexOf(','); 133d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka if (posComma < 0) { 1344c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka Log.w(TAG, "Array element has no comma: " + conditionConstant); 1354c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka continue; 136d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 137d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String condition = conditionConstant.substring(0, posComma); 138d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka if (condition.isEmpty()) { 139bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka Log.w(TAG, "Array element has no condition: " + conditionConstant); 140d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka continue; 141d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 1424c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka try { 1434c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka if (fulfillsCondition(keyValuePairs, condition)) { 1444c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka // Take first match 1454c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka if (foundValue == null) { 1464c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka foundValue = conditionConstant.substring(posComma + 1); 1474c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } 1484c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka // And continue walking through all conditions. 1494c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } 1504c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } catch (final DeviceOverridePatternSyntaxError e) { 1514c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka Log.w(TAG, "Syntax error, ignored", e); 152d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 153d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 1544c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka return foundValue; 155d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 156d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka 157d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka private static boolean fulfillsCondition(final HashMap<String,String> keyValuePairs, 1584c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka final String condition) throws DeviceOverridePatternSyntaxError { 159d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String[] patterns = condition.split(":"); 160d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka // Check all patterns in a condition are true 1614c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka boolean matchedAll = true; 162d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka for (final String pattern : patterns) { 163d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final int posEqual = pattern.indexOf('='); 164d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka if (posEqual < 0) { 1654c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka throw new DeviceOverridePatternSyntaxError("Pattern has no '='", condition); 166d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 167d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String key = pattern.substring(0, posEqual); 168d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka final String value = keyValuePairs.get(key); 169d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka if (value == null) { 1704c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka throw new DeviceOverridePatternSyntaxError("Unknown key", condition); 171d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 17218184eacb149f1b12b859ff8631340a9f73bf8acTadashi G. Takaoka final String patternRegexpValue = pattern.substring(posEqual + 1); 1734c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka try { 1744c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka if (!value.matches(patternRegexpValue)) { 1754c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka matchedAll = false; 1764c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka // And continue walking through all patterns. 1774c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } 1784c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka } catch (final PatternSyntaxException e) { 1794c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka throw new DeviceOverridePatternSyntaxError("Syntax error", condition, e); 180d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 181d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 1824c75ea858ab3d1175daaa03744d9693dcc15dd8dTadashi G. Takaoka return matchedAll; 183d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka } 184d69fa0a09af7e9a524751dac1522c951abd92530Tadashi G. Takaoka 185be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka public static int getDefaultKeyboardWidth(final Resources res) { 1863897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka final DisplayMetrics dm = res.getDisplayMetrics(); 1873897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka return dm.widthPixels; 1883897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka } 1893897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka 190bb9400aebc4cb0291b4f0208ecbc9ddc01dc79e1Andy Wang public static int getKeyboardHeight(final Resources res, final SettingsValues settingsValues) { 191be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka final int defaultKeyboardHeight = getDefaultKeyboardHeight(res); 192bb9400aebc4cb0291b4f0208ecbc9ddc01dc79e1Andy Wang if (settingsValues.mHasKeyboardResize) { 193be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka // mKeyboardHeightScale Ranges from [.5,1.2], from xml/prefs_screen_debug.xml 194be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka return (int)(defaultKeyboardHeight * settingsValues.mKeyboardHeightScale); 195bb9400aebc4cb0291b4f0208ecbc9ddc01dc79e1Andy Wang } 196be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka return defaultKeyboardHeight; 197bb9400aebc4cb0291b4f0208ecbc9ddc01dc79e1Andy Wang } 198bb9400aebc4cb0291b4f0208ecbc9ddc01dc79e1Andy Wang 1993897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka public static int getDefaultKeyboardHeight(final Resources res) { 2003897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka final DisplayMetrics dm = res.getDisplayMetrics(); 201bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka final String keyboardHeightInDp = getDeviceOverrideValue( 202bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka res, R.array.keyboard_heights, null /* defaultValue */); 2033897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka final float keyboardHeight; 204bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka if (TextUtils.isEmpty(keyboardHeightInDp)) { 2052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa keyboardHeight = res.getDimension(R.dimen.config_default_keyboard_height); 2063897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka } else { 207bd9887a57485c602e66a8f0eaebe40313ffa89cdTadashi G. Takaoka keyboardHeight = Float.parseFloat(keyboardHeightInDp) * dm.density; 2083897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka } 2093897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka final float maxKeyboardHeight = res.getFraction( 2102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.fraction.config_max_keyboard_height, dm.heightPixels, dm.heightPixels); 2113897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka float minKeyboardHeight = res.getFraction( 2122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.fraction.config_min_keyboard_height, dm.heightPixels, dm.heightPixels); 2133897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka if (minKeyboardHeight < 0.0f) { 2143897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka // Specified fraction was negative, so it should be calculated against display 2153897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka // width. 2163897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka minKeyboardHeight = -res.getFraction( 2172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa R.fraction.config_min_keyboard_height, dm.widthPixels, dm.widthPixels); 2183897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka } 2193897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka // Keyboard height will not exceed maxKeyboardHeight and will not be less than 2203897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka // minKeyboardHeight. 2213897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka return (int)Math.max(Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight); 2223897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka } 2233897a43940eca9c400e542c76d2c790f2c48eb8cTadashi G. Takaoka 22492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka public static boolean isValidFraction(final float fraction) { 22592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return fraction >= 0.0f; 22692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 22792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 22861bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka // {@link Resources#getDimensionPixelSize(int)} returns at least one pixel size. 22961bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka public static boolean isValidDimensionPixelSize(final int dimension) { 23061bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka return dimension > 0; 23161bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka } 23261bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka 23361bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka // {@link Resources#getDimensionPixelOffset(int)} may return zero pixel offset. 23461bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka public static boolean isValidDimensionPixelOffset(final int dimension) { 23561bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka return dimension >= 0; 23661bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka } 23761bc66b324f94a7b29b5388101cb622bf243d19eTadashi G. Takaoka 238276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka public static float getFloatFromFraction(final Resources res, final int fractionResId) { 239276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka return res.getFraction(fractionResId, 1, 1); 240276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka } 241276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka 24292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka public static float getFraction(final TypedArray a, final int index, final float defValue) { 24392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final TypedValue value = a.peekValue(index); 24492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka if (value == null || !isFractionValue(value)) { 24592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return defValue; 24692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 24792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return a.getFraction(index, 1, 1, defValue); 24892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 24992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 25092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka public static float getFraction(final TypedArray a, final int index) { 25192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return getFraction(a, index, UNDEFINED_RATIO); 25292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 25392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 25492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka public static int getDimensionPixelSize(final TypedArray a, final int index) { 25592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final TypedValue value = a.peekValue(index); 25692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka if (value == null || !isDimensionValue(value)) { 25792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return ResourceUtils.UNDEFINED_DIMENSION; 25892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 25992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return a.getDimensionPixelSize(index, ResourceUtils.UNDEFINED_DIMENSION); 26092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 26192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 262fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka public static float getDimensionOrFraction(final TypedArray a, final int index, final int base, 263fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka final float defValue) { 26492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final TypedValue value = a.peekValue(index); 26592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka if (value == null) { 26692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return defValue; 26792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 26892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka if (isFractionValue(value)) { 26992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return a.getFraction(index, base, base, defValue); 27092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } else if (isDimensionValue(value)) { 27192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return a.getDimension(index, defValue); 27292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 27392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return defValue; 27492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 27592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 276fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka public static int getEnumValue(final TypedArray a, final int index, final int defValue) { 27792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final TypedValue value = a.peekValue(index); 27892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka if (value == null) { 27992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return defValue; 28092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 28192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka if (isIntegerValue(value)) { 28292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return a.getInt(index, defValue); 28392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 28492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return defValue; 28592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 28692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 287fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka public static boolean isFractionValue(final TypedValue v) { 28892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return v.type == TypedValue.TYPE_FRACTION; 28992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 29092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 291fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka public static boolean isDimensionValue(final TypedValue v) { 29292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return v.type == TypedValue.TYPE_DIMENSION; 29392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 29492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 295fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka public static boolean isIntegerValue(final TypedValue v) { 29692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; 29792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 29892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka 299fa7f08b37327c825baf0a6455d6f7fdf8b37da57Tadashi G. Takaoka public static boolean isStringValue(final TypedValue v) { 30092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka return v.type == TypedValue.TYPE_STRING; 30192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka } 3029879f65651a748e4c0a45715eb7d5663652f1127Tadashi G. Takaoka} 303