blob: e2625b1611fafbed4772d3981d03f8926f35131b [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package org.mozc.android.inputmethod.japanese.preference;
import org.mozc.android.inputmethod.japanese.MozcLog;
import org.mozc.android.inputmethod.japanese.MozcUtil;
import org.mozc.android.inputmethod.japanese.preference.ClientSidePreference.KeyboardLayout;
import org.mozc.android.inputmethod.japanese.resources.R;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import java.util.HashSet;
import java.util.Set;
/**
* Utilities for Mozc preferences.
*
*/
public class PreferenceUtil {
/** Simple {@code PreferenceManager} wrapper for testing purpose. */
interface PreferenceManagerInterface {
public Preference findPreference(CharSequence key);
}
/** Simple {@code PreferenceManager} wrapper for testing purpose.
* This interface wraps static method so no constructor is required.
*/
public interface PreferenceManagerStaticInterface {
public void setDefaultValues(Context context, int id, boolean readAgain);
}
static class PreferenceManagerInterfaceImpl implements PreferenceManagerInterface {
private final PreferenceManager preferenceManager;
PreferenceManagerInterfaceImpl(PreferenceManager preferenceManager) {
this.preferenceManager = preferenceManager;
}
@Override
public Preference findPreference(CharSequence key) {
return preferenceManager.findPreference(key);
}
}
private static Optional<PreferenceManagerStaticInterface> defaultPreferenceManagerStatic =
Optional.absent();
public static PreferenceManagerStaticInterface getDefaultPreferenceManagerStatic() {
// As construction cost of defaultPrereferenceManagerStatic is cheap and it is invariant,
// no lock mechanism is employed here.
if (!defaultPreferenceManagerStatic.isPresent()) {
defaultPreferenceManagerStatic = Optional.<PreferenceManagerStaticInterface>of(
new PreferenceManagerStaticInterface() {
@Override
public void setDefaultValues(Context context, int id, boolean readAgain) {
PreferenceManager.setDefaultValues(context, id, readAgain);
}
});
}
return defaultPreferenceManagerStatic.get();
}
static class CurrentKeyboardLayoutPreferenceChangeListener implements OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (!(newValue instanceof KeyboardLayout)) {
return false;
}
// Write back to with the appropriate preference key.
SharedPreferences sharedPreferences = preference.getSharedPreferences();
boolean isLandscapeKeyboardSettingActive = isLandscapeKeyboardSettingActive(
sharedPreferences, preference.getContext().getResources().getConfiguration().orientation);
sharedPreferences.edit()
.putString(
isLandscapeKeyboardSettingActive
? PREF_LANDSCAPE_KEYBOARD_LAYOUT_KEY
: PREF_PORTRAIT_KEYBOARD_LAYOUT_KEY,
KeyboardLayout.class.cast(newValue).name())
.commit();
return true;
}
}
// Keys for Keyboard Layout.
public static final String PREF_CURRENT_KEYBOARD_LAYOUT_KEY =
"pref_current_keyboard_layout_key";
public static final String PREF_SOFTWARE_KEYBOARD_ADVANED_PORTRAIT_KEY =
"pref_software_keyboard_advanced_portrait_key";
public static final String PREF_PORTRAIT_KEYBOARD_LAYOUT_KEY =
"pref_portrait_keyboard_layout_key";
public static final String PREF_PORTRAIT_INPUT_STYLE_KEY =
"pref_portrait_input_style_key";
public static final String PREF_PORTRAIT_QWERTY_LAYOUT_FOR_ALPHABET_KEY =
"pref_portrait_qwerty_layout_for_alphabet_key";
public static final String PREF_PORTRAIT_FLICK_SENSITIVITY_KEY =
"pref_portrait_flick_sensitivity_key";
public static final String PREF_PORTRAIT_LAYOUT_ADJUSTMENT_KEY =
"pref_portrait_layout_adjustment_key";
public static final String PREF_PORTRAIT_KEYBOARD_HEIGHT_RATIO_KEY =
"pref_portrait_keyboard_height_ratio_key";
public static final String PREF_SOFTWARE_KEYBOARD_ADVANED_LANDSCAPE_KEY =
"pref_software_keyboard_advanced_landscape_key";
public static final String PREF_LANDSCAPE_KEYBOARD_LAYOUT_KEY =
"pref_landscape_keyboard_layout_key";
public static final String PREF_LANDSCAPE_INPUT_STYLE_KEY =
"pref_landscape_input_style_key";
public static final String PREF_LANDSCAPE_QWERTY_LAYOUT_FOR_ALPHABET_KEY =
"pref_landscape_qwerty_layout_for_alphabet_key";
public static final String PREF_LANDSCAPE_FLICK_SENSITIVITY_KEY =
"pref_landscape_flick_sensitivity_key";
public static final String PREF_LANDSCAPE_LAYOUT_ADJUSTMENT_KEY =
"pref_landscape_layout_adjustment_key";
public static final String PREF_LANDSCAPE_KEYBOARD_HEIGHT_RATIO_KEY =
"pref_landscape_keyboard_height_ratio_key";
public static final String PREF_USE_PORTRAIT_KEYBOARD_SETTINGS_FOR_LANDSCAPE_KEY =
"pref_use_portrait_keyboard_settings_for_landscape_key";
// Full screen keys.
public static final String PREF_PORTRAIT_FULLSCREEN_KEY =
"pref_portrait_fullscreen_key";
public static final String PREF_LANDSCAPE_FULLSCREEN_KEY =
"pref_landscape_fullscreen_key";
// Keys for generic preferences.
public static final String PREF_HARDWARE_KEYMAP = "pref_hardware_keymap";
public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key";
public static final String PREF_HAPTIC_FEEDBACK_KEY = "pref_haptic_feedback_key";
public static final String PREF_HAPTIC_FEEDBACK_DURATION_KEY =
"pref_haptic_feedback_duration_key";
public static final String PREF_SOUND_FEEDBACK_KEY = "pref_sound_feedback_key";
public static final String PREF_SOUND_FEEDBACK_VOLUME_KEY =
"pref_sound_feedback_volume_key";
public static final String PREF_POPUP_FEEDBACK_KEY = "pref_popup_feedback_key";
public static final String PREF_SPACE_CHARACTER_FORM_KEY =
"pref_space_character_form_key";
public static final String PREF_KANA_MODIFIER_INSENSITIVE_CONVERSION_KEY =
"pref_kana_modifier_insensitive_conversion";
public static final String PREF_TYPING_CORRECTION_KEY =
"pref_typing_correction";
public static final String PREF_EMOJI_PROVIDER_TYPE =
"pref_emoji_provider_type";
public static final String PREF_DICTIONARY_PERSONALIZATION_KEY =
"pref_dictionary_personalization_key";
public static final String PREF_DICTIONARY_USER_DICTIONARY_TOOL_KEY =
"pref_dictionary_user_dictionary_tool_key";
public static final String PREF_OTHER_INCOGNITO_MODE_KEY = "pref_other_anonimous_mode_key";
public static final String PREF_OTHER_USAGE_STATS_KEY = "pref_other_usage_stats_key";
public static final String PREF_ABOUT_VERSION = "pref_about_version";
public static final String PREF_LAUNCHER_ICON_VISIBILITY_KEY = "pref_launcher_icon_visibility";
// Application lifecycle
public static final String PREF_LAST_LAUNCH_ABI_INDEPENDENT_VERSION_CODE =
"pref_last_launch_abi_independent_version_code";
private static final OnPreferenceChangeListener
CURRENT_KEYBOARD_LAYOUT_PREFERENCE_CHANGE_LISTENER =
new CurrentKeyboardLayoutPreferenceChangeListener();
// Disallow instantiation.
private PreferenceUtil() {
}
public static boolean isLandscapeKeyboardSettingActive(
SharedPreferences sharedPreferences, int deviceOrientation) {
Preconditions.checkNotNull(sharedPreferences);
if (sharedPreferences.getBoolean(PREF_USE_PORTRAIT_KEYBOARD_SETTINGS_FOR_LANDSCAPE_KEY, true)) {
// Always use portrait configuration.
return false;
}
return deviceOrientation == Configuration.ORIENTATION_LANDSCAPE;
}
/**
* Initializes some preferences which need special initialization.
*/
static void initializeSpecialPreferences(PreferenceManager preferenceManager) {
if (preferenceManager == null) {
return;
}
initializeSpecialPreferencesInternal(new PreferenceManagerInterfaceImpl(preferenceManager));
}
static void initializeSpecialPreferencesInternal(PreferenceManagerInterface preferenceManager) {
initializeCurrentKeyboardLayoutPreference(
preferenceManager.findPreference(PREF_CURRENT_KEYBOARD_LAYOUT_KEY));
initializeUsageStatsPreference(preferenceManager.findPreference(PREF_OTHER_USAGE_STATS_KEY));
initializeVersionPreference(preferenceManager.findPreference(PREF_ABOUT_VERSION));
initializeLayoutAdjustmentPreference(preferenceManager);
}
private static void initializeCurrentKeyboardLayoutPreference(Preference preference) {
if (!(preference instanceof KeyboardLayoutPreference)) {
return;
}
// Initialize the value based on the current orientation.
SharedPreferences sharedPreferences = preference.getSharedPreferences();
boolean isLandscapeKeyboardSettingActive = isLandscapeKeyboardSettingActive(
sharedPreferences, preference.getContext().getResources().getConfiguration().orientation);
KeyboardLayoutPreference.class.cast(preference).setValue(
getKeyboardLayout(sharedPreferences,
isLandscapeKeyboardSettingActive
? PREF_LANDSCAPE_KEYBOARD_LAYOUT_KEY
: PREF_PORTRAIT_KEYBOARD_LAYOUT_KEY));
preference.setOnPreferenceChangeListener(CURRENT_KEYBOARD_LAYOUT_PREFERENCE_CHANGE_LISTENER);
}
/**
* Returns parsed {@link KeyboardLayout} instance, or TWELVE_KEYS if any error is found.
*/
private static KeyboardLayout getKeyboardLayout(SharedPreferences sharedPreferences, String key) {
if (sharedPreferences == null || key == null) {
return KeyboardLayout.TWELVE_KEYS;
}
String value = sharedPreferences.getString(key, null);
if (value == null) {
return KeyboardLayout.TWELVE_KEYS;
}
try {
return KeyboardLayout.valueOf(value);
} catch (IllegalArgumentException e) {
MozcLog.e("Invalid KeyboardLayout: " + value);
}
return KeyboardLayout.TWELVE_KEYS;
}
private static void initializeUsageStatsPreference(Preference preference) {
if (preference == null) {
return;
}
Context context = preference.getContext();
Resources resources = context.getResources();
preference.setSummary(
resources.getString(R.string.pref_other_usage_stats_description,
resources.getString(R.string.developer_organization)));
// Disable (always on to send usage stats) for dev-channel build.
preference.setEnabled(!MozcUtil.isDevChannel(context));
}
private static void initializeVersionPreference(Preference preference) {
if (preference == null) {
return;
}
preference.setSummary(MozcUtil.getVersionName(preference.getContext()));
}
static boolean shouldRemoveLayoutAdjustmentPreferences(
PreferenceManagerInterface preferenceManager) {
Preference preference = preferenceManager.findPreference(
PREF_SOFTWARE_KEYBOARD_ADVANED_PORTRAIT_KEY);
if (preference == null) {
return false;
}
Resources resouces = preference.getContext().getResources();
int smallestWidth = resouces.getDimensionPixelSize(R.dimen.ime_window_partial_width)
+ resouces.getDimensionPixelSize(R.dimen.side_frame_width);
DisplayMetrics displayMetrics = resouces.getDisplayMetrics();
return displayMetrics.widthPixels < smallestWidth
|| displayMetrics.heightPixels < smallestWidth;
}
static void removePreference(PreferenceManagerInterface preferenceManager, CharSequence key) {
CharSequence parentKey;
if (key == PREF_PORTRAIT_LAYOUT_ADJUSTMENT_KEY) {
parentKey = PREF_SOFTWARE_KEYBOARD_ADVANED_PORTRAIT_KEY;
} else if (key == PREF_LANDSCAPE_LAYOUT_ADJUSTMENT_KEY) {
parentKey = PREF_SOFTWARE_KEYBOARD_ADVANED_LANDSCAPE_KEY;
} else {
return;
}
Preference preference = preferenceManager.findPreference(key);
PreferenceGroup parentPreference = PreferenceGroup.class.cast(preferenceManager
.findPreference(parentKey));
if (preference == null || parentPreference == null) {
return;
}
parentPreference.removePreference(preference);
}
static void initializeLayoutAdjustmentPreference(PreferenceManagerInterface preferenceManager) {
if (shouldRemoveLayoutAdjustmentPreferences(preferenceManager)) {
removePreference(preferenceManager, PREF_PORTRAIT_LAYOUT_ADJUSTMENT_KEY);
removePreference(preferenceManager, PREF_LANDSCAPE_LAYOUT_ADJUSTMENT_KEY);
}
}
/**
* Gets an enum value in the SharedPreference.
*
* @param sharedPreference a {@link SharedPreferences} to be loaded.
* @param key a key name
* @param type a class of enum value
* @param defaultValue default value if the {@link SharedPreferences} doesn't have corresponding
* entry.
* @param conversionRecoveryValue default value if unknown value is stored.
* For example, if the value is "ALPHA" and {@code type} doesn't have "ALPHA" entry,
* this argument is returned.
*/
public static <T extends Enum<T>> T getEnum(
SharedPreferences sharedPreference, String key, Class<T> type,
T defaultValue, T conversionRecoveryValue) {
if (sharedPreference == null) {
return defaultValue;
}
String name = sharedPreference.getString(key, null);
if (name != null) {
try {
return Enum.valueOf(type, name);
} catch (IllegalArgumentException e) {
return conversionRecoveryValue;
}
}
return defaultValue;
}
/**
* Same as {@link getEnum}.
*
* {@code defaultValue} is used as {@code conversionRecoveryValue}
*/
@SuppressWarnings("javadoc")
public static <T extends Enum<T>> T getEnum(
SharedPreferences sharedPreference, String key, Class<T> type, T defaultValue) {
return getEnum(sharedPreference, key, type, defaultValue, defaultValue);
}
public static void setDefaultValues(PreferenceManagerStaticInterface preferenceManager,
Context context, boolean isDebug, boolean useUsageStats) {
Preconditions.checkNotNull(preferenceManager);
Preconditions.checkNotNull(context);
Set<Integer> preferenceResources = new HashSet<Integer>();
// Collect all the preferences resource ids from possible preference pages,
// removing duplication.
for (PreferencePage page : PreferencePage.values()) {
for (int id : PreferencePage.getResourceIdList(page, isDebug, useUsageStats)) {
preferenceResources.add(id);
}
}
for (int id : preferenceResources) {
// 'true' here means the preferences which have not set yet are *always* set here.
// This doesn't mean *Reset all the preferences*.
// (if 'false' the process will be done once on the first launch
// so even if new preferences are added their default values will not be set here)
preferenceManager.setDefaultValues(context, id, true);
}
}
}