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