Change Input Settings UI flow.

1. Introduces new UI components as per the new flow
2. Temporarily disables components in the old flow that are to be
   replaced by the new flow. This is done so we can neatly revert
   to the old flow if there are issues with the new flow
3. AvailableVirtualKeyboardActivity now responds to
   android.settings.INPUT_METHOD_SETTINGS intents instead of
   InputMethodAndLanguageSettingsActivity

Bug: 25752812
Change-Id: I728d7ee185827ed328c16cb7abce244557a26518
This commit is contained in:
Abodunrinwa Toki
2016-01-20 18:43:20 +00:00
parent f9d330448b
commit 976bb3f459
13 changed files with 625 additions and 26 deletions

View File

@@ -0,0 +1,116 @@
/*
* 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.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v7.preference.PreferenceScreen;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import com.android.settings.R;
import com.android.settings.InstrumentedFragment;
import com.android.settings.SettingsPreferenceFragment;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFragment
implements InputMethodPreference.OnSavePreferenceListener {
private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<>();
private InputMethodSettingValuesWrapper mInputMethodSettingValues;
private InputMethodManager mImm;
private DevicePolicyManager mDpm;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
Activity activity = getActivity();
PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(activity);
screen.setTitle(activity.getString(R.string.available_virtual_keyboard_category));
setPreferenceScreen(screen);
mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(activity);
mImm = activity.getSystemService(InputMethodManager.class);
mDpm = activity.getSystemService(DevicePolicyManager.class);
}
@Override
public void onResume() {
super.onResume();
// Refresh internal states in mInputMethodSettingValues to keep the latest
// "InputMethodInfo"s and "InputMethodSubtype"s
mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
updateInputMethodPreferenceViews();
}
@Override
public void onSaveInputMethodPreference(final InputMethodPreference pref) {
final boolean hasHardwareKeyboard = getResources().getConfiguration().keyboard
== Configuration.KEYBOARD_QWERTY;
InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(this, getContentResolver(),
mImm.getInputMethodList(), hasHardwareKeyboard);
// Update input method settings and preference list.
mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
for (final InputMethodPreference p : mInputMethodPreferenceList) {
p.updatePreferenceViews();
}
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.ENABLE_VIRTUAL_KEYBOARDS;
}
private void updateInputMethodPreferenceViews() {
mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
// Clear existing "InputMethodPreference"s
mInputMethodPreferenceList.clear();
List<String> permittedList = mDpm.getPermittedInputMethodsForCurrentUser();
final Context context = getPrefContext();
final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList();
final int N = (imis == null ? 0 : imis.size());
for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = imis.get(i);
final boolean isAllowedByOrganization = permittedList == null
|| permittedList.contains(imi.getPackageName());
final InputMethodPreference pref = new InputMethodPreference(
context, imi, true, isAllowedByOrganization, this);
mInputMethodPreferenceList.add(pref);
}
final Collator collator = Collator.getInstance();
Collections.sort(mInputMethodPreferenceList, new Comparator<InputMethodPreference>() {
@Override
public int compare(InputMethodPreference lhs, InputMethodPreference rhs) {
return lhs.compareTo(rhs, collator);
}
});
getPreferenceScreen().removeAll();
for (int i = 0; i < N; ++i) {
final InputMethodPreference pref = mInputMethodPreferenceList.get(i);
pref.setOrder(i);
getPreferenceScreen().addPreference(pref);
InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
pref.updatePreferenceViews();
}
}
}

View File

@@ -157,12 +157,16 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
startingIntent.getAction());
if (mShowsOnlyFullImeAndKeyboardList) {
getPreferenceScreen().removeAll();
getPreferenceScreen().addPreference(mHardKeyboardCategory);
if (mHardKeyboardCategory != null) {
getPreferenceScreen().addPreference(mHardKeyboardCategory);
}
if (SHOW_INPUT_METHOD_SWITCHER_SETTINGS) {
getPreferenceScreen().addPreference(mShowInputMethodSelectorPref);
}
mKeyboardSettingsCategory.removeAll();
getPreferenceScreen().addPreference(mKeyboardSettingsCategory);
if (mKeyboardSettingsCategory != null) {
mKeyboardSettingsCategory.removeAll();
getPreferenceScreen().addPreference(mKeyboardSettingsCategory);
}
}
// Build hard keyboard and game controller preference categories.
@@ -376,6 +380,10 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
}
private void updateInputMethodPreferenceViews() {
if (mKeyboardSettingsCategory == null) {
return;
}
synchronized (mInputMethodPreferenceList) {
// Clear existing "InputMethodPreference"s
for (final InputMethodPreference pref : mInputMethodPreferenceList) {
@@ -510,6 +518,10 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
}
private void updateHardKeyboards() {
if (mHardKeyboardCategory == null) {
return;
}
mHardKeyboardPreferenceList.clear();
final int[] devices = InputDevice.getDeviceIds();
for (int i = 0; i < devices.length; i++) {

View File

@@ -301,7 +301,7 @@ public class KeyboardLayoutDialogFragment extends DialogFragment
}
}
private static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> {
static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> {
private final InputDeviceIdentifier mInputDeviceIdentifier;
public KeyboardLayoutLoader(Context context, InputDeviceIdentifier inputDeviceIdentifier) {

View File

@@ -0,0 +1,264 @@
/*
* 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.app.Activity;
import android.app.LoaderManager;
import android.content.Intent;
import android.content.Loader;
import android.database.ContentObserver;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings.Secure;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.PreferenceCategory;
import android.support.v14.preference.SwitchPreference;
import android.util.Pair;
import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.widget.Toast;
import com.android.internal.inputmethod.InputMethodUtils;
import com.android.internal.util.Preconditions;
import com.android.settings.R;
import com.android.settings.InstrumentedFragment;
import com.android.settings.Settings;
import com.android.settings.SettingsPreferenceFragment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
implements LoaderManager.LoaderCallbacks<KeyboardLayoutDialogFragment.Keyboards>,
InputManager.InputDeviceListener {
private static final int USER_SYSTEM = 0;
private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category";
private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch";
private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper";
private final ArrayList<PreferenceCategory> mHardKeyboardPreferenceList = new ArrayList<>();
private final HashMap<Integer, Pair<InputDeviceIdentifier, PreferenceCategory>> mLoaderReference
= new HashMap<>();
private InputManager mIm;
private PreferenceCategory mKeyboardAssistanceCategory;
private SwitchPreference mShowVirtualKeyboardSwitch;
private InputMethodUtils.InputMethodSettings mSettings;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
Activity activity = Preconditions.checkNotNull(getActivity());
addPreferencesFromResource(R.xml.physical_keyboard_settings);
mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
mSettings = new InputMethodUtils.InputMethodSettings(
activity.getResources(),
getContentResolver(),
new HashMap<String, InputMethodInfo>(),
new ArrayList<InputMethodInfo>(),
USER_SYSTEM);
mKeyboardAssistanceCategory = Preconditions.checkNotNull(
(PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY));
mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
(SwitchPreference) mKeyboardAssistanceCategory.findPreference(
SHOW_VIRTUAL_KEYBOARD_SWITCH));
findPreference(KEYBOARD_SHORTCUTS_HELPER).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
toggleKeyboardShortcutsMenu();
return true;
}
});
}
@Override
public void onResume() {
super.onResume();
updateHardKeyboards();
mIm.registerInputDeviceListener(this, null);
mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(
mShowVirtualKeyboardSwitchPreferenceChangeListener);
registerShowVirtualKeyboardSettingsObserver();
}
@Override
public void onPause() {
super.onPause();
clearHardKeyboardsData();
mIm.unregisterInputDeviceListener(this);
mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null);
unregisterShowVirtualKeyboardSettingsObserver();
}
@Override
public Loader<KeyboardLayoutDialogFragment.Keyboards> onCreateLoader(int id, Bundle args) {
InputDeviceIdentifier deviceId = mLoaderReference.get(id).first;
return new KeyboardLayoutDialogFragment.KeyboardLayoutLoader(
getActivity().getBaseContext(), deviceId);
}
@Override
public void onLoadFinished(
final Loader<KeyboardLayoutDialogFragment.Keyboards> loader,
KeyboardLayoutDialogFragment.Keyboards data) {
// TODO: Investigate why this is being called twice.
final InputDeviceIdentifier deviceId = mLoaderReference.get(loader.getId()).first;
final PreferenceCategory category = mLoaderReference.get(loader.getId()).second;
category.removeAll();
for (KeyboardLayout layout : data.keyboardLayouts) {
if (layout != null) {
Preference pref = new Preference(getPrefContext(), null);
pref.setTitle(layout.getLabel());
pref.setSummary(layout.getCollection());
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showKeyboardLayoutScreen(deviceId);
return true;
}
});
category.addPreference(pref);
}
}
}
@Override
public void onLoaderReset(Loader<KeyboardLayoutDialogFragment.Keyboards> loader) {}
@Override
public void onInputDeviceAdded(int deviceId) {
updateHardKeyboards();
}
@Override
public void onInputDeviceRemoved(int deviceId) {
updateHardKeyboards();
}
@Override
public void onInputDeviceChanged(int deviceId) {
updateHardKeyboards();
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.PHYSICAL_KEYBOARDS;
}
private void updateHardKeyboards() {
clearHardKeyboardsData();
final int[] devices = InputDevice.getDeviceIds();
for (int deviceIndex = 0; deviceIndex < devices.length; deviceIndex++) {
InputDevice device = InputDevice.getDevice(devices[deviceIndex]);
if (device != null
&& !device.isVirtual()
&& device.isFullKeyboard()) {
final InputDeviceIdentifier deviceId = device.getIdentifier();
final String keyboardLayoutDescriptor =
mIm.getCurrentKeyboardLayoutForInputDevice(deviceId);
final KeyboardLayout keyboardLayout = keyboardLayoutDescriptor != null ?
mIm.getKeyboardLayout(keyboardLayoutDescriptor) : null;
final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null);
category.setTitle(device.getName());
if (keyboardLayout != null) {
category.setSummary(keyboardLayout.toString());
} else {
category.setSummary(R.string.keyboard_layout_default_label);
}
mLoaderReference.put(deviceIndex, new Pair(deviceId, category));
mHardKeyboardPreferenceList.add(category);
}
}
Collections.sort(mHardKeyboardPreferenceList);
final int count = mHardKeyboardPreferenceList.size();
for (int i = 0; i < count; i++) {
final PreferenceCategory category = mHardKeyboardPreferenceList.get(i);
category.setOrder(i);
getPreferenceScreen().addPreference(category);
}
mKeyboardAssistanceCategory.setOrder(count);
getPreferenceScreen().addPreference(mKeyboardAssistanceCategory);
for (int deviceIndex : mLoaderReference.keySet()) {
getLoaderManager().initLoader(deviceIndex, null, this);
}
updateShowVirtualKeyboardSwitch();
}
private void showKeyboardLayoutScreen(InputDeviceIdentifier inputDeviceIdentifier) {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class);
intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier);
startActivity(intent);
}
private void clearHardKeyboardsData() {
getPreferenceScreen().removeAll();
for (int index = 0; index < mLoaderReference.size(); index++) {
getLoaderManager().destroyLoader(index);
}
mLoaderReference.clear();
mHardKeyboardPreferenceList.clear();
}
private void registerShowVirtualKeyboardSettingsObserver() {
unregisterShowVirtualKeyboardSettingsObserver();
getActivity().getContentResolver().registerContentObserver(
Secure.getUriFor(Secure.SHOW_IME_WITH_HARD_KEYBOARD),
false,
mContentObserver,
USER_SYSTEM);
updateShowVirtualKeyboardSwitch();
}
private void unregisterShowVirtualKeyboardSettingsObserver() {
getActivity().getContentResolver().unregisterContentObserver(mContentObserver);
}
private void updateShowVirtualKeyboardSwitch() {
mShowVirtualKeyboardSwitch.setChecked(mSettings.isShowImeWithHardKeyboardEnabled());
}
private void toggleKeyboardShortcutsMenu() {
// TODO: Implement.
Toast.makeText(getActivity(), "toggleKeyboardShortcutsMenu", Toast.LENGTH_SHORT).show();
}
private final OnPreferenceChangeListener mShowVirtualKeyboardSwitchPreferenceChangeListener =
new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mSettings.setShowImeWithHardKeyboard((Boolean) newValue);
return false;
}
};
private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) {
@Override
public void onChange(boolean selfChange) {
updateShowVirtualKeyboardSwitch();
}
};
}

View File

@@ -0,0 +1,107 @@
/*
* 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.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.util.Preconditions;
import com.android.settings.R;
import com.android.settings.InstrumentedFragment;
import com.android.settings.SettingsPreferenceFragment;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public final class VirtualKeyboardFragment extends SettingsPreferenceFragment {
private static final String ADD_VIRTUAL_KEYBOARD_SCREEN = "add_virtual_keyboard_screen";
private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<>();
private InputMethodManager mImm;
private DevicePolicyManager mDpm;
private Preference mAddVirtualKeyboardScreen;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
Activity activity = Preconditions.checkNotNull(getActivity());
addPreferencesFromResource(R.xml.virtual_keyboard_settings);
mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class));
mDpm = Preconditions.checkNotNull(activity.getSystemService(DevicePolicyManager.class));
mAddVirtualKeyboardScreen = Preconditions.checkNotNull(
findPreference(ADD_VIRTUAL_KEYBOARD_SCREEN));
}
@Override
public void onResume() {
super.onResume();
// Refresh internal states in mInputMethodSettingValues to keep the latest
// "InputMethodInfo"s and "InputMethodSubtype"s
updateInputMethodPreferenceViews();
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.VIRTUAL_KEYBOARDS;
}
private void updateInputMethodPreferenceViews() {
// Clear existing "InputMethodPreference"s
mInputMethodPreferenceList.clear();
List<String> permittedList = mDpm.getPermittedInputMethodsForCurrentUser();
final Context context = getPrefContext();
final List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
final int N = (imis == null ? 0 : imis.size());
for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = imis.get(i);
final boolean isAllowedByOrganization = permittedList == null
|| permittedList.contains(imi.getPackageName());
final InputMethodPreference pref = new InputMethodPreference(
context,
imi,
false, /* isImeEnabler */
isAllowedByOrganization,
null /* this can be null since isImeEnabler is false */);
mInputMethodPreferenceList.add(pref);
}
final Collator collator = Collator.getInstance();
Collections.sort(mInputMethodPreferenceList, new Comparator<InputMethodPreference>() {
@Override
public int compare(InputMethodPreference lhs, InputMethodPreference rhs) {
return lhs.compareTo(rhs, collator);
}
});
getPreferenceScreen().removeAll();
for (int i = 0; i < N; ++i) {
final InputMethodPreference pref = mInputMethodPreferenceList.get(i);
pref.setOrder(i);
getPreferenceScreen().addPreference(pref);
InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
pref.updatePreferenceViews();
}
mAddVirtualKeyboardScreen.setOrder(N);
getPreferenceScreen().addPreference(mAddVirtualKeyboardScreen);
}
}