Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22d42d52 authored by Fan Zhang's avatar Fan Zhang
Browse files

Refactor IMEAndLanguageSettings to use PreferenceController

Bug: 32642706
Bug: 32637613
Bug: 32643833
Test: RunSettingsRoboTests

This change is necessary to test preference controlling logic, as well
as making preferences reusable in other Preference pages in the new
information architecture.

Change-Id: I9e2fd2f6800579f005a5c303ed03ae06477006a6
parent e185c5cc
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -27,11 +27,11 @@
    <!-- Spell checker preference title, summary and fragment will be set programmatically. -->
    <!-- Note: Mark this as persistent="false" to remove unnecessarily saved shared preference.
         See: InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference. -->
    <PreferenceScreen
    <Preference
        android:key="spellcheckers_settings"
        android:title="@string/spellcheckers_settings_title"
            android:persistent="false"
            />
        android:fragment="com.android.settings.inputmethod.SpellCheckersSettings"
        android:persistent="false"/>

    <!-- User dictionary preference title and fragment will be set programmatically. -->
    <PreferenceScreen
+131 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.inputmethod;

import android.content.Context;
import android.hardware.input.InputManager;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.view.InputDevice;

import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnPause;
import com.android.settings.core.lifecycle.events.OnResume;

public class GameControllerPreferenceController extends PreferenceController
        implements InputManager.InputDeviceListener, LifecycleObserver, OnResume, OnPause {

    public static final String PREF_KEY = "vibrate_input_devices";
    private static final String CATEGORY_KEY = "game_controller_settings_category";

    private final InputManager mIm;

    private PreferenceScreen mScreen;
    private Preference mCategory;
    private Preference mPreference;

    public GameControllerPreferenceController(Context context) {
        super(context);
        mIm = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
    }

    @Override
    public void onResume() {
        mIm.registerInputDeviceListener(this, null);
    }

    @Override
    public void onPause() {
        mIm.unregisterInputDeviceListener(this);
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mScreen = screen;
        mCategory = screen.findPreference(CATEGORY_KEY);
        mPreference = screen.findPreference(PREF_KEY);
    }

    @Override
    public boolean isAvailable() {
        final int[] devices = mIm.getInputDeviceIds();
        for (int deviceId : devices) {
            InputDevice device = mIm.getInputDevice(deviceId);
            if (device != null && !device.isVirtual() && device.getVibrator().hasVibrator()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (TextUtils.equals(PREF_KEY, preference.getKey())) {
            Settings.System.putInt(mContext.getContentResolver(),
                    Settings.System.VIBRATE_INPUT_DEVICES,
                    ((SwitchPreference) preference).isChecked() ? 1 : 0);
            return true;
        }
        return false;
    }

    @Override
    public String getPreferenceKey() {
        return CATEGORY_KEY;
    }

    @Override
    public void updateState(Preference preference) {
        if (preference == null) {
            return;
        }
        ((SwitchPreference) preference).setChecked(Settings.System.getInt(
                mContext.getContentResolver(),
                Settings.System.VIBRATE_INPUT_DEVICES, 1) > 0);
    }

    @Override
    public void onInputDeviceAdded(int deviceId) {
        updateGameControllers();
    }

    @Override
    public void onInputDeviceRemoved(int deviceId) {
        updateGameControllers();
    }

    @Override
    public void onInputDeviceChanged(int deviceId) {
        updateGameControllers();
    }

    private void updateGameControllers() {
        if (isAvailable()) {
            mScreen.addPreference(mCategory);
            updateState(mPreference);
        } else {
            if (mCategory != null) {
                mScreen.removePreference(mCategory);
            }
        }
    }
}
+34 −189
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.settings.inputmethod;

import android.app.Activity;
import android.app.Fragment;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -25,52 +24,38 @@ import android.content.pm.ServiceInfo;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
import android.os.Bundle;
import android.provider.Settings;
import android.provider.Settings.System;
import android.speech.tts.TtsEngines;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceCategory;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;

import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Settings.KeyboardLayoutPickerActivity;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.SubSettings;
import com.android.settings.UserDictionarySettings;
import com.android.settings.Utils;
import com.android.settings.VoiceInputOutputSettings;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.language.PhoneLanguagePreferenceController;
import com.android.settings.language.TtsPreferenceController;
import com.android.settings.language.UserDictionaryPreferenceController;
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.drawer.CategoryKey;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
        implements InputManager.InputDeviceListener,
        KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable {
public class InputMethodAndLanguageSettings extends DashboardFragment
        implements KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable {

    private static final String KEY_SPELL_CHECKERS = "spellcheckers_settings";
    private static final String KEY_PHONE_LANGUAGE = "phone_language";
    private static final String KEY_USER_DICTIONARY_SETTINGS = "key_user_dictionary_settings";
    private static final String TAG = "IMEAndLanguageSetting";

    private PreferenceCategory mGameControllerCategory;
    private Preference mLanguagePref;
    private InputManager mIm;
    private Intent mIntentWaitingForResult;

    @Override
@@ -79,137 +64,33 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
    }

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        addPreferencesFromResource(R.xml.language_settings);

        final Activity activity = getActivity();

        if (activity.getAssets().getLocales().length == 1) {
            // No "Select language" pref if there's only one system locale available.
            getPreferenceScreen().removePreference(findPreference(KEY_PHONE_LANGUAGE));
        } else {
            mLanguagePref = findPreference(KEY_PHONE_LANGUAGE);
        }

        new VoiceInputOutputSettings(this).onCreate();

        mGameControllerCategory = (PreferenceCategory)findPreference(
                "game_controller_settings_category");

        // Build hard keyboard and game controller preference categories.
        mIm = (InputManager)activity.getSystemService(Context.INPUT_SERVICE);
        updateInputDevices();

        // Spell Checker
        final Preference spellChecker = findPreference(KEY_SPELL_CHECKERS);
        if (spellChecker != null) {
            // Note: KEY_SPELL_CHECKERS preference is marked as persistent="false" in XML.
            InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(spellChecker);
            final Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.setClass(activity, SubSettings.class);
            intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
                    SpellCheckersSettings.class.getName());
            intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
                    R.string.spellcheckers_settings_title);
            spellChecker.setIntent(intent);
        }
    }

    private void updateUserDictionaryPreference(Preference userDictionaryPreference) {
        final Activity activity = getActivity();
        final TreeSet<String> localeSet = UserDictionaryList.getUserDictionaryLocalesSet(activity);
        if (null == localeSet) {
            // The locale list is null if and only if the user dictionary service is
            // not present or disabled. In this case we need to remove the preference.
            getPreferenceScreen().removePreference(userDictionaryPreference);
        } else {
            userDictionaryPreference.setOnPreferenceClickListener(
                    new OnPreferenceClickListener() {
                        @Override
                        public boolean onPreferenceClick(Preference arg0) {
                            // Redirect to UserDictionarySettings if the user needs only one
                            // language.
                            final Bundle extras = new Bundle();
                            final Class<? extends Fragment> targetFragment;
                            if (localeSet.size() <= 1) {
                                if (!localeSet.isEmpty()) {
                                    // If the size of localeList is 0, we don't set the locale
                                    // parameter in the extras. This will be interpreted by the
                                    // UserDictionarySettings class as meaning
                                    // "the current locale". Note that with the current code for
                                    // UserDictionaryList#getUserDictionaryLocalesSet()
                                    // the locale list always has at least one element, since it
                                    // always includes the current locale explicitly.
                                    // @see UserDictionaryList.getUserDictionaryLocalesSet().
                                    extras.putString("locale", localeSet.first());
                                }
                                targetFragment = UserDictionarySettings.class;
                            } else {
                                targetFragment = UserDictionaryList.class;
                            }
                            startFragment(InputMethodAndLanguageSettings.this,
                                    targetFragment.getCanonicalName(), -1, -1, extras);
                            return true;
                        }
                    });
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        mIm.registerInputDeviceListener(this, null);

        final Preference spellChecker = findPreference(KEY_SPELL_CHECKERS);
        if (spellChecker != null) {
            final TextServicesManager tsm = (TextServicesManager) getSystemService(
                    Context.TEXT_SERVICES_MANAGER_SERVICE);
            if (!tsm.isSpellCheckerEnabled()) {
                spellChecker.setSummary(R.string.switch_off_text);
            } else {
                final SpellCheckerInfo sci = tsm.getCurrentSpellChecker();
                if (sci != null) {
                    spellChecker.setSummary(sci.loadLabel(getPackageManager()));
                } else {
                    spellChecker.setSummary(R.string.spell_checker_not_selected);
                }
            }
        }

        if (mLanguagePref != null) {
            final String localeNames = FeatureFactory.getFactory(getContext())
                    .getLocaleFeatureProvider().getLocaleNames();
            mLanguagePref.setSummary(localeNames);
        }

        updateUserDictionaryPreference(findPreference(KEY_USER_DICTIONARY_SETTINGS));

        updateInputDevices();
    protected String getCategoryKey() {
        return CategoryKey.CATEGORY_SYSTEM_LANGUAGE;
    }

    @Override
    public void onPause() {
        super.onPause();

        mIm.unregisterInputDeviceListener(this);
    protected String getLogTag() {
        return TAG;
    }

    @Override
    public void onInputDeviceAdded(int deviceId) {
        updateInputDevices();
    protected int getPreferenceScreenResId() {
        return R.xml.language_settings;
    }

    @Override
    public void onInputDeviceChanged(int deviceId) {
        updateInputDevices();
    }
    protected List<PreferenceController> getPreferenceControllers(Context context) {
        final GameControllerPreferenceController gameControllerPreferenceController =
                new GameControllerPreferenceController(context);
        getLifecycle().addObserver(gameControllerPreferenceController);

    @Override
    public void onInputDeviceRemoved(int deviceId) {
        updateInputDevices();
        final List<PreferenceController> list = new ArrayList<>();
        list.add(gameControllerPreferenceController);
        list.add(new PhoneLanguagePreferenceController(context));
        list.add(new SpellCheckerPreferenceController(context));
        list.add(new UserDictionaryPreferenceController(context));
        list.add(new TtsPreferenceController(context, new TtsEngines(context)));
        return list;
    }

    @Override
@@ -218,21 +99,9 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
        if (Utils.isMonkeyRunning()) {
            return false;
        }
        if (preference instanceof SwitchPreference) {
            final SwitchPreference pref = (SwitchPreference) preference;
            if (pref == mGameControllerCategory.findPreference("vibrate_input_devices")) {
                System.putInt(getContentResolver(), Settings.System.VIBRATE_INPUT_DEVICES,
                        pref.isChecked() ? 1 : 0);
                return true;
            }
        }
        return super.onPreferenceTreeClick(preference);
    }

    private void updateInputDevices() {
        updateGameControllers();
    }

    private void showKeyboardLayoutDialog(InputDeviceIdentifier inputDeviceIdentifier) {
        KeyboardLayoutDialogFragment fragment = (KeyboardLayoutDialogFragment)
                getFragmentManager().findFragmentByTag("keyboardLayout");
@@ -265,38 +134,12 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
        }
    }

    private void updateGameControllers() {
        if (haveInputDeviceWithVibrator()) {
            getPreferenceScreen().addPreference(mGameControllerCategory);

            SwitchPreference pref = (SwitchPreference)
                    mGameControllerCategory.findPreference("vibrate_input_devices");
            pref.setChecked(System.getInt(getContentResolver(),
                    Settings.System.VIBRATE_INPUT_DEVICES, 1) > 0);
        } else {
            getPreferenceScreen().removePreference(mGameControllerCategory);
        }
    }

    private static boolean haveInputDeviceWithVibrator() {
        final int[] devices = InputDevice.getDeviceIds();
        for (int i = 0; i < devices.length; i++) {
            InputDevice device = InputDevice.getDevice(devices[i]);
            if (device != null && !device.isVirtual() && device.getVibrator().hasVibrator()) {
                return true;
            }
        }
        return false;
    }

    private static class SummaryProvider implements SummaryLoader.SummaryProvider {

        private final Context mContext;
        private final SummaryLoader mSummaryLoader;
        private LocaleFeatureProvider mLocaleFeatureProvider;

        public SummaryProvider(Context context, SummaryLoader summaryLoader) {
            mContext = context;
            mSummaryLoader = summaryLoader;
            mLocaleFeatureProvider = FeatureFactory.getFactory(context).getLocaleFeatureProvider();
        }
@@ -328,11 +171,13 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
            final String screenTitle = context.getString(R.string.language_keyboard_settings_title);

            // Locale picker.
            if (context.getAssets().getLocales().length > 1) {
            final PhoneLanguagePreferenceController mLanguagePrefController =
                    new PhoneLanguagePreferenceController(context);
            if (mLanguagePrefController.isAvailable()) {
                String localeNames = FeatureFactory.getFactory(context).getLocaleFeatureProvider()
                        .getLocaleNames();
                SearchIndexableRaw indexable = new SearchIndexableRaw(context);
                indexable.key = KEY_PHONE_LANGUAGE;
                indexable.key = mLanguagePrefController.getPreferenceKey();
                indexable.title = context.getString(R.string.phone_language);
                indexable.summaryOn = localeNames;
                indexable.summaryOff = localeNames;
@@ -342,7 +187,7 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment

            // Spell checker.
            SearchIndexableRaw indexable = new SearchIndexableRaw(context);
            indexable.key = KEY_SPELL_CHECKERS;
            indexable.key = SpellCheckerPreferenceController.KEY_SPELL_CHECKERS;
            indexable.title = context.getString(R.string.spellcheckers_settings_title);
            indexable.screenTitle = screenTitle;
            indexable.keywords = context.getString(R.string.keywords_spell_checker);
@@ -465,9 +310,9 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
            indexables.add(indexable);

            // Game controllers.
            if (haveInputDeviceWithVibrator()) {
            if (!new GameControllerPreferenceController(context).isAvailable()) {
                indexable = new SearchIndexableRaw(context);
                indexable.key = "vibrate_input_devices";
                indexable.key = GameControllerPreferenceController.PREF_KEY;
                indexable.title = context.getString(R.string.vibrate_input_devices);
                indexable.summaryOn = context.getString(R.string.vibrate_input_devices_summary);
                indexable.summaryOff = context.getString(R.string.vibrate_input_devices_summary);
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.inputmethod;

import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;

import com.android.settings.R;
import com.android.settings.core.PreferenceController;

public class SpellCheckerPreferenceController extends PreferenceController {

    public static final String KEY_SPELL_CHECKERS = "spellcheckers_settings";

    private final TextServicesManager mTextServicesManager;

    public SpellCheckerPreferenceController(Context context) {
        super(context);
        mTextServicesManager = (TextServicesManager) context.getSystemService(
                Context.TEXT_SERVICES_MANAGER_SERVICE);
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        final Preference preference = screen.findPreference(KEY_SPELL_CHECKERS);
        if (preference != null) {
            InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(preference);
        }
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        return false;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_SPELL_CHECKERS;
    }

    @Override
    public void updateState(Preference preference) {
        if (preference == null) {
            return;
        }
        if (!mTextServicesManager.isSpellCheckerEnabled()) {
            preference.setSummary(R.string.switch_off_text);
        } else {
            final SpellCheckerInfo sci = mTextServicesManager.getCurrentSpellChecker();
            if (sci != null) {
                preference.setSummary(sci.loadLabel(mContext.getPackageManager()));
            } else {
                preference.setSummary(R.string.spell_checker_not_selected);
            }
        }
    }
}
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.language;

import android.content.Context;
import android.support.v7.preference.Preference;

import com.android.settings.core.PreferenceController;
import com.android.settings.overlay.FeatureFactory;

public class PhoneLanguagePreferenceController extends PreferenceController {

    private static final String KEY_PHONE_LANGUAGE = "phone_language";

    public PhoneLanguagePreferenceController(Context context) {
        super(context);
    }

    @Override
    public boolean isAvailable() {
        return mContext.getAssets().getLocales().length > 1;
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        return false;
    }

    @Override
    public void updateState(Preference preference) {
        if (preference == null) {
            return;
        }
        final String localeNames = FeatureFactory.getFactory(mContext)
                .getLocaleFeatureProvider().getLocaleNames();
        preference.setSummary(localeNames);
    }

    @Override
    public String getPreferenceKey() {
        return KEY_PHONE_LANGUAGE;
    }
}
Loading