blob: 476a4a8fb4fa7a3bbc46536225523a7f3ed2c381 [file] [log] [blame]
/*
* Copyright (C) 2017 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.tv.settings.inputmethod;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
import android.view.inputmethod.InputMethodInfo;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.applications.DefaultAppInfo;
import com.android.tv.settings.R;
import com.android.tv.settings.SettingsPreferenceFragment;
import com.android.tv.settings.autofill.AutofillHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Fragment for managing IMEs and Autofills
*/
@Keep
public class KeyboardFragment extends SettingsPreferenceFragment {
private static final String TAG = "KeyboardFragment";
// Order of input methods, make sure they are inserted between 1 (currentKeyboard) and
// 3 (manageKeyboards).
private static final int INPUT_METHOD_PREFERENCE_ORDER = 2;
@VisibleForTesting
static final String KEY_KEYBOARD_CATEGORY = "keyboardCategory";
@VisibleForTesting
static final String KEY_CURRENT_KEYBOARD = "currentKeyboard";
private static final String KEY_KEYBOARD_SETTINGS_PREFIX = "keyboardSettings:";
@VisibleForTesting
static final String KEY_AUTOFILL_CATEGORY = "autofillCategory";
@VisibleForTesting
static final String KEY_CURRENT_AUTOFILL = "currentAutofill";
private static final String KEY_AUTOFILL_SETTINGS_PREFIX = "autofillSettings:";
private PackageManager mPm;
/**
* @return New fragment instance
*/
public static KeyboardFragment newInstance() {
return new KeyboardFragment();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPm = context.getPackageManager();
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.keyboard, null);
findPreference(KEY_CURRENT_KEYBOARD).setOnPreferenceChangeListener(
(preference, newValue) -> {
InputMethodHelper.setDefaultInputMethodId(getContext(), (String) newValue);
return true;
});
updateUi();
}
@Override
public void onResume() {
super.onResume();
updateUi();
}
@VisibleForTesting
void updateUi() {
updateAutofill();
updateKeyboards();
}
private void updateKeyboards() {
updateCurrentKeyboardPreference((ListPreference) findPreference(KEY_CURRENT_KEYBOARD));
updateKeyboardsSettings();
}
private void updateCurrentKeyboardPreference(ListPreference currentKeyboardPref) {
final PackageManager packageManager = getContext().getPackageManager();
List<InputMethodInfo> enabledInputMethodInfos = InputMethodHelper
.getEnabledSystemInputMethodList(getContext());
final List<CharSequence> entries = new ArrayList<>(enabledInputMethodInfos.size());
final List<CharSequence> values = new ArrayList<>(enabledInputMethodInfos.size());
int defaultIndex = 0;
final String defaultId = InputMethodHelper.getDefaultInputMethodId(getContext());
for (final InputMethodInfo info : enabledInputMethodInfos) {
entries.add(info.loadLabel(packageManager));
final String id = info.getId();
values.add(id);
if (TextUtils.equals(id, defaultId)) {
defaultIndex = values.size() - 1;
}
}
currentKeyboardPref.setEntries(entries.toArray(new CharSequence[entries.size()]));
currentKeyboardPref.setEntryValues(values.toArray(new CharSequence[values.size()]));
if (entries.size() > 0) {
currentKeyboardPref.setValueIndex(defaultIndex);
}
}
Context getPreferenceContext() {
return getPreferenceManager().getContext();
}
private void updateKeyboardsSettings() {
final Context preferenceContext = getPreferenceContext();
final PackageManager packageManager = getContext().getPackageManager();
List<InputMethodInfo> enabledInputMethodInfos = InputMethodHelper
.getEnabledSystemInputMethodList(getContext());
PreferenceScreen preferenceScreen = getPreferenceScreen();
final Set<String> enabledInputMethodKeys = new ArraySet<>(enabledInputMethodInfos.size());
// Add per-IME settings
for (final InputMethodInfo info : enabledInputMethodInfos) {
final Intent settingsIntent = InputMethodHelper.getInputMethodSettingsIntent(info);
if (settingsIntent == null) {
continue;
}
final String key = KEY_KEYBOARD_SETTINGS_PREFIX + info.getId();
Preference preference = preferenceScreen.findPreference(key);
if (preference == null) {
preference = new Preference(preferenceContext);
preference.setOrder(INPUT_METHOD_PREFERENCE_ORDER);
preferenceScreen.addPreference(preference);
}
preference.setTitle(getContext().getString(R.string.title_settings,
info.loadLabel(packageManager)));
preference.setKey(key);
preference.setIntent(settingsIntent);
enabledInputMethodKeys.add(key);
}
for (int i = 0; i < preferenceScreen.getPreferenceCount();) {
final Preference preference = preferenceScreen.getPreference(i);
final String key = preference.getKey();
if (!TextUtils.isEmpty(key)
&& key.startsWith(KEY_KEYBOARD_SETTINGS_PREFIX)
&& !enabledInputMethodKeys.contains(key)) {
preferenceScreen.removePreference(preference);
} else {
i++;
}
}
}
/**
* Update autofill related preferences.
*/
private void updateAutofill() {
final PreferenceCategory autofillCategory = (PreferenceCategory)
findPreference(KEY_AUTOFILL_CATEGORY);
List<DefaultAppInfo> candidates = getAutofillCandidates();
if (candidates.isEmpty()) {
// No need to show keyboard category and autofill category.
// Keyboard only preference screen:
findPreference(KEY_KEYBOARD_CATEGORY).setVisible(false);
autofillCategory.setVisible(false);
getPreferenceScreen().setTitle(R.string.system_keyboard);
} else {
// Show both keyboard category and autofill category in keyboard & autofill screen.
findPreference(KEY_KEYBOARD_CATEGORY).setVisible(true);
autofillCategory.setVisible(true);
final Preference currentAutofillPref = findPreference(KEY_CURRENT_AUTOFILL);
updateCurrentAutofillPreference(currentAutofillPref, candidates);
updateAutofillSettings(candidates);
getPreferenceScreen().setTitle(R.string.system_keyboard_autofill);
}
}
private List<DefaultAppInfo> getAutofillCandidates() {
return AutofillHelper.getAutofillCandidates(getContext(),
mPm, UserHandle.myUserId());
}
private void updateCurrentAutofillPreference(Preference currentAutofillPref,
List<DefaultAppInfo> candidates) {
DefaultAppInfo app = AutofillHelper.getCurrentAutofill(getContext(), candidates);
CharSequence summary = app == null ? getContext().getString(R.string.autofill_none)
: app.loadLabel();
currentAutofillPref.setSummary(summary);
}
private void updateAutofillSettings(List<DefaultAppInfo> candidates) {
final Context preferenceContext = getPreferenceContext();
final PreferenceCategory autofillCategory = (PreferenceCategory)
findPreference(KEY_AUTOFILL_CATEGORY);
final Set<String> autofillServicesKeys = new ArraySet<>(candidates.size());
for (final DefaultAppInfo info : candidates) {
final Intent settingsIntent = AutofillHelper.getAutofillSettingsIntent(getContext(),
mPm, info);
if (settingsIntent == null) {
continue;
}
final String key = KEY_AUTOFILL_SETTINGS_PREFIX + info.getKey();
Preference preference = findPreference(key);
if (preference == null) {
preference = new Preference(preferenceContext);
autofillCategory.addPreference(preference);
}
preference.setTitle(getContext().getString(R.string.title_settings, info.loadLabel()));
preference.setKey(key);
preference.setIntent(settingsIntent);
autofillServicesKeys.add(key);
}
for (int i = 0; i < autofillCategory.getPreferenceCount();) {
final Preference preference = autofillCategory.getPreference(i);
final String key = preference.getKey();
if (!TextUtils.isEmpty(key)
&& key.startsWith(KEY_AUTOFILL_SETTINGS_PREFIX)
&& !autofillServicesKeys.contains(key)) {
autofillCategory.removePreference(preference);
} else {
i++;
}
}
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.INPUTMETHOD_KEYBOARD;
}
}