1d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka/* 2d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * Copyright (C) 2014 The Android Open Source Project 3d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * 4d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * you may not use this file except in compliance with the License. 6d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * You may obtain a copy of the License at 7d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * 8d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * 10d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 11d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * See the License for the specific language governing permissions and 14d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka * limitations under the License. 15d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka */ 16d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka 17d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaokapackage com.android.inputmethod.keyboard; 18d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka 1921eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaokaimport android.content.SharedPreferences; 2059c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaokaimport android.os.Build.VERSION_CODES; 2121eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaokaimport android.util.Log; 2221eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka 23c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting; 2478cff10f8d317641dd3531cce04e74502be8ad44Tadashi G. Takaokaimport com.android.inputmethod.compat.BuildCompatUtils; 25d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaokaimport com.android.inputmethod.latin.R; 2659c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka 2759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaokaimport java.util.Arrays; 28d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka 29c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaokapublic final class KeyboardTheme implements Comparable<KeyboardTheme> { 3021eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka private static final String TAG = KeyboardTheme.class.getSimpleName(); 3121eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka 323b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka static final String KLP_KEYBOARD_THEME_KEY = "pref_keyboard_layout_20110916"; 333b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka static final String LXX_KEYBOARD_THEME_KEY = "pref_keyboard_theme_20140509"; 3459c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka 350af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka // These should be aligned with Keyboard.themeId and Keyboard.Case.keyboardTheme 360af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka // attributes' values in attrs.xml. 37c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka public static final int THEME_ID_ICS = 0; 38c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka public static final int THEME_ID_KLP = 2; 39f9f409530ccdc975ef965b1d1fee44bbd341d718Tadashi G. Takaoka public static final int THEME_ID_LXX_LIGHT = 3; 40f9f409530ccdc975ef965b1d1fee44bbd341d718Tadashi G. Takaoka public static final int THEME_ID_LXX_DARK = 4; 41c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka public static final int DEFAULT_THEME_ID = THEME_ID_KLP; 4221eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka 4321eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka private static final KeyboardTheme[] KEYBOARD_THEMES = { 440af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka new KeyboardTheme(THEME_ID_ICS, "ICS", R.style.KeyboardTheme_ICS, 45c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka // This has never been selected because we support ICS or later. 463b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka VERSION_CODES.BASE), 470af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka new KeyboardTheme(THEME_ID_KLP, "KLP", R.style.KeyboardTheme_KLP, 48c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka // Default theme for ICS, JB, and KLP. 493b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka VERSION_CODES.ICE_CREAM_SANDWICH), 500af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka new KeyboardTheme(THEME_ID_LXX_LIGHT, "LXXLight", R.style.KeyboardTheme_LXX_Light, 51c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka // Default theme for LXX. 5278cff10f8d317641dd3531cce04e74502be8ad44Tadashi G. Takaoka BuildCompatUtils.VERSION_CODES_LXX), 530af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka new KeyboardTheme(THEME_ID_LXX_DARK, "LXXDark", R.style.KeyboardTheme_LXX_Dark, 54f9f409530ccdc975ef965b1d1fee44bbd341d718Tadashi G. Takaoka VERSION_CODES.BASE), 55d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka }; 56c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka 5759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka static { 5859c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka // Sort {@link #KEYBOARD_THEME} by descending order of {@link #mMinApiVersion}. 59c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka Arrays.sort(KEYBOARD_THEMES); 6059c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 61d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka 62d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka public final int mThemeId; 63d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka public final int mStyleId; 640af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka public final String mThemeName; 65c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka private final int mMinApiVersion; 66d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka 67d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka // Note: The themeId should be aligned with "themeId" attribute of Keyboard style 6859c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka // in values/themes-<style>.xml. 690af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka private KeyboardTheme(final int themeId, final String themeName, final int styleId, 700af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka final int minApiVersion) { 71d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka mThemeId = themeId; 720af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka mThemeName = themeName; 73d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka mStyleId = styleId; 7459c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka mMinApiVersion = minApiVersion; 7559c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 7659c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka 7759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka @Override 78c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka public int compareTo(final KeyboardTheme rhs) { 79c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka if (mMinApiVersion > rhs.mMinApiVersion) return -1; 80c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka if (mMinApiVersion < rhs.mMinApiVersion) return 1; 81c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka return 0; 82c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka } 83c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka 84c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka @Override 8559c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka public boolean equals(final Object o) { 8659c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka if (o == this) return true; 8759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return (o instanceof KeyboardTheme) && ((KeyboardTheme)o).mThemeId == mThemeId; 88d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka } 8921eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka 9059c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka @Override 9159c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka public int hashCode() { 9259c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return mThemeId; 9359c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 9459c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka 95c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka @UsedForTesting 96c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka static KeyboardTheme searchKeyboardThemeById(final int themeId) { 9721eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka // TODO: This search algorithm isn't optimal if there are many themes. 9821eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka for (final KeyboardTheme theme : KEYBOARD_THEMES) { 9921eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka if (theme.mThemeId == themeId) { 10021eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka return theme; 10121eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 10221eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 10321eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka return null; 10421eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 10521eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka 106c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka @UsedForTesting 10759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs, 10859c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka final int sdkVersion) { 1093b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka final String klpThemeIdString = prefs.getString(KLP_KEYBOARD_THEME_KEY, null); 1103b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka if (klpThemeIdString != null) { 11159c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka if (sdkVersion <= VERSION_CODES.KITKAT) { 11259c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka try { 1133b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka final int themeId = Integer.parseInt(klpThemeIdString); 11459c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka final KeyboardTheme theme = searchKeyboardThemeById(themeId); 11559c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka if (theme != null) { 11659c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return theme; 11759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 1183b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka Log.w(TAG, "Unknown keyboard theme in KLP preference: " + klpThemeIdString); 11959c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } catch (final NumberFormatException e) { 1203b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka Log.w(TAG, "Illegal keyboard theme in KLP preference: " + klpThemeIdString, e); 12159c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 12259c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 1233b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka // Remove old preference. 1243b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka Log.i(TAG, "Remove KLP keyboard theme preference: " + klpThemeIdString); 1253b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka prefs.edit().remove(KLP_KEYBOARD_THEME_KEY).apply(); 12659c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 12759c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka // TODO: This search algorithm isn't optimal if there are many themes. 12859c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka for (final KeyboardTheme theme : KEYBOARD_THEMES) { 12959c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka if (sdkVersion >= theme.mMinApiVersion) { 13059c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return theme; 13159c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 13259c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 13359c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return searchKeyboardThemeById(DEFAULT_THEME_ID); 13459c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka } 13559c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka 1360af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka public static String getKeyboardThemeName(final int themeId) { 1370af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka final KeyboardTheme theme = searchKeyboardThemeById(themeId); 1380af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka return theme.mThemeName; 1390af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka } 1400af2472a69bf8aad21ce1603e912adab3891667eTadashi G. Takaoka 14159c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka public static void saveKeyboardThemeId(final String themeIdString, 14259c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka final SharedPreferences prefs) { 14378cff10f8d317641dd3531cce04e74502be8ad44Tadashi G. Takaoka saveKeyboardThemeId(themeIdString, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT); 1443b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka } 1453b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka 146c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka @UsedForTesting 1473b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka static String getPreferenceKey(final int sdkVersion) { 1483b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka if (sdkVersion <= VERSION_CODES.KITKAT) { 1493b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka return KLP_KEYBOARD_THEME_KEY; 1503b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka } 1513b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka return LXX_KEYBOARD_THEME_KEY; 1523b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka } 1533b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka 154c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka @UsedForTesting 155c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka static void saveKeyboardThemeId(final String themeIdString, 156c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka final SharedPreferences prefs, final int sdkVersion) { 1573b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka final String prefKey = getPreferenceKey(sdkVersion); 1583b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka prefs.edit().putString(prefKey, themeIdString).apply(); 15921eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 16021eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka 16121eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) { 16278cff10f8d317641dd3531cce04e74502be8ad44Tadashi G. Takaoka return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT); 1633b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka } 1643b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka 165c5dc74067385f9ab6ec3086825d0b369c26a1ea3Tadashi G. Takaoka @UsedForTesting 1663b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs, final int sdkVersion) { 1673b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka final String lxxThemeIdString = prefs.getString(LXX_KEYBOARD_THEME_KEY, null); 1683b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka if (lxxThemeIdString == null) { 16959c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return getDefaultKeyboardTheme(prefs, sdkVersion); 17021eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 17121eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka try { 1723b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka final int themeId = Integer.parseInt(lxxThemeIdString); 17359c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka final KeyboardTheme theme = searchKeyboardThemeById(themeId); 17421eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka if (theme != null) { 17521eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka return theme; 17621eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 1773b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka Log.w(TAG, "Unknown keyboard theme in LXX preference: " + lxxThemeIdString); 17821eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } catch (final NumberFormatException e) { 1793b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka Log.w(TAG, "Illegal keyboard theme in LXX preference: " + lxxThemeIdString, e); 18021eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 1813b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka // Remove preference that contains unknown or illegal theme id. 1823b12718537f40b262e5eeb5c8168d69b2afa6955Tadashi G. Takaoka prefs.edit().remove(LXX_KEYBOARD_THEME_KEY).apply(); 18359c3ef1ff8df23e3c3e3f549c0289c479553c666Tadashi G. Takaoka return getDefaultKeyboardTheme(prefs, sdkVersion); 18421eafd7910182a31372fb92895f057cff28a8480Tadashi G. Takaoka } 185d6aa94e6b5fd7abc25a8d21857211ffd0852b33aTadashi G. Takaoka} 186