This is a follow up CL to my previous CL [1], which added a new constructor to InputMethodSettings to support File-Based Encryption (FBE). Settings app is the only remaining package that depends on the previous constructor. To completely deprecate the previous one, this CL lets the caller switch to the new constructor. Note that this CL does not change the initial parameters of InputMethodSettings. In other words this is a mechanical code clean-up. [1] I9c6f9bb3d51174198e5f73588637f87ea0d90e11 5db2f16f15549c490c9541602a96f42bef984acb Bug: 26279466 Change-Id: I09cba4066b95c4a9e89a3e4f83d75b97882502dc
336 lines
13 KiB
Java
336 lines
13 KiB
Java
/*
|
|
* 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.AsyncTaskLoader;
|
|
import android.content.Context;
|
|
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.v14.preference.SwitchPreference;
|
|
import android.support.v7.preference.Preference;
|
|
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
|
|
import android.support.v7.preference.PreferenceCategory;
|
|
import android.util.Pair;
|
|
import android.view.InputDevice;
|
|
import android.view.inputmethod.InputMethodInfo;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import android.view.inputmethod.InputMethodSubtype;
|
|
import com.android.internal.inputmethod.InputMethodUtils;
|
|
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
|
import com.android.internal.util.Preconditions;
|
|
import com.android.settings.R;
|
|
import com.android.settings.Settings;
|
|
import com.android.settings.SettingsPreferenceFragment;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
|
|
implements LoaderManager.LoaderCallbacks<PhysicalKeyboardFragment.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 IM_SUBTYPE_MODE_KEYBOARD = "keyboard";
|
|
|
|
private final HashMap<Integer, Pair<InputDeviceIdentifier, PreferenceCategory>> mLoaderReference
|
|
= new HashMap<>();
|
|
private final Map<InputMethodInfo, List<InputMethodSubtype>> mImiSubtypes = new HashMap<>();
|
|
private InputManager mIm;
|
|
private InputMethodManager mImm;
|
|
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));
|
|
mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class));
|
|
mSettings = new InputMethodUtils.InputMethodSettings(
|
|
activity.getResources(),
|
|
getContentResolver(),
|
|
new HashMap<String, InputMethodInfo>(),
|
|
new ArrayList<InputMethodInfo>(),
|
|
USER_SYSTEM,
|
|
false /* copyOnWrite */);
|
|
mKeyboardAssistanceCategory = Preconditions.checkNotNull(
|
|
(PreferenceCategory) findPreference(KEYBOARD_ASSISTANCE_CATEGORY));
|
|
mShowVirtualKeyboardSwitch = Preconditions.checkNotNull(
|
|
(SwitchPreference) mKeyboardAssistanceCategory.findPreference(
|
|
SHOW_VIRTUAL_KEYBOARD_SWITCH));
|
|
}
|
|
|
|
@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<Keyboards> onCreateLoader(int id, Bundle args) {
|
|
final InputDeviceIdentifier deviceId = mLoaderReference.get(id).first;
|
|
return new KeyboardLayoutLoader(
|
|
getActivity().getBaseContext(), mIm, mImiSubtypes, deviceId);
|
|
}
|
|
|
|
@Override
|
|
public void onLoadFinished(Loader<Keyboards> loader, 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 (Keyboards.KeyboardInfo info : data.mInfos) {
|
|
Preference pref = new Preference(getPrefContext(), null);
|
|
final InputMethodInfo imi = info.mImi;
|
|
final InputMethodSubtype imSubtype = info.mImSubtype;
|
|
if (imi != null && imSubtype != null) {
|
|
pref.setTitle(getDisplayName(getContext(), imi, imSubtype));
|
|
KeyboardLayout layout = info.mLayout;
|
|
if (layout != null) {
|
|
pref.setSummary(layout.getLabel());
|
|
}
|
|
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
@Override
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
showKeyboardLayoutScreen(deviceId, imi, imSubtype);
|
|
return true;
|
|
}
|
|
});
|
|
category.addPreference(pref);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onLoaderReset(Loader<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 MetricsEvent.PHYSICAL_KEYBOARDS;
|
|
}
|
|
|
|
private void updateHardKeyboards() {
|
|
clearHardKeyboardsData();
|
|
loadInputMethodInfoSubtypes();
|
|
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 PreferenceCategory category = new PreferenceCategory(getPrefContext(), null);
|
|
category.setTitle(device.getName());
|
|
category.setOrder(0);
|
|
mLoaderReference.put(deviceIndex, new Pair(device.getIdentifier(), category));
|
|
getPreferenceScreen().addPreference(category);
|
|
}
|
|
}
|
|
mKeyboardAssistanceCategory.setOrder(1);
|
|
getPreferenceScreen().addPreference(mKeyboardAssistanceCategory);
|
|
|
|
for (int deviceIndex : mLoaderReference.keySet()) {
|
|
getLoaderManager().initLoader(deviceIndex, null, this);
|
|
}
|
|
updateShowVirtualKeyboardSwitch();
|
|
}
|
|
|
|
private void showKeyboardLayoutScreen(
|
|
InputDeviceIdentifier inputDeviceIdentifier,
|
|
InputMethodInfo imi,
|
|
InputMethodSubtype imSubtype) {
|
|
final Intent intent = new Intent(Intent.ACTION_MAIN);
|
|
intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class);
|
|
intent.putExtra(KeyboardLayoutPickerFragment2.EXTRA_INPUT_DEVICE_IDENTIFIER,
|
|
inputDeviceIdentifier);
|
|
intent.putExtra(KeyboardLayoutPickerFragment2.EXTRA_INPUT_METHOD_INFO, imi);
|
|
intent.putExtra(KeyboardLayoutPickerFragment2.EXTRA_INPUT_METHOD_SUBTYPE, imSubtype);
|
|
startActivity(intent);
|
|
}
|
|
|
|
private void clearHardKeyboardsData() {
|
|
getPreferenceScreen().removeAll();
|
|
for (int index = 0; index < mLoaderReference.size(); index++) {
|
|
getLoaderManager().destroyLoader(index);
|
|
}
|
|
mLoaderReference.clear();
|
|
}
|
|
|
|
private void loadInputMethodInfoSubtypes() {
|
|
mImiSubtypes.clear();
|
|
final List<InputMethodInfo> imis = mImm.getEnabledInputMethodList();
|
|
for (InputMethodInfo imi : imis) {
|
|
final List<InputMethodSubtype> subtypes = new ArrayList<>();
|
|
for (InputMethodSubtype subtype : mImm.getEnabledInputMethodSubtypeList(
|
|
imi, true /* allowsImplicitlySelectedSubtypes */)) {
|
|
if (IM_SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode())) {
|
|
subtypes.add(subtype);
|
|
}
|
|
}
|
|
mImiSubtypes.put(imi, subtypes);
|
|
}
|
|
}
|
|
|
|
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 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();
|
|
}
|
|
};
|
|
|
|
static String getDisplayName(
|
|
Context context, InputMethodInfo imi, InputMethodSubtype imSubtype) {
|
|
CharSequence imSubtypeName = imSubtype.getDisplayName(
|
|
context, imi.getPackageName(),
|
|
imi.getServiceInfo().applicationInfo);
|
|
CharSequence imeName = imi.loadLabel(context.getPackageManager());
|
|
return String.format(
|
|
context.getString(R.string.physical_device_title), imSubtypeName, imeName);
|
|
}
|
|
|
|
private static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> {
|
|
|
|
private final Map<InputMethodInfo, List<InputMethodSubtype>> mImiSubtypes;
|
|
private final InputDeviceIdentifier mInputDeviceIdentifier;
|
|
private final InputManager mIm;
|
|
|
|
public KeyboardLayoutLoader(
|
|
Context context,
|
|
InputManager im,
|
|
Map<InputMethodInfo, List<InputMethodSubtype>> imiSubtypes,
|
|
InputDeviceIdentifier inputDeviceIdentifier) {
|
|
super(context);
|
|
mIm = Preconditions.checkNotNull(im);
|
|
mInputDeviceIdentifier = Preconditions.checkNotNull(inputDeviceIdentifier);
|
|
mImiSubtypes = new HashMap<>(imiSubtypes);
|
|
}
|
|
|
|
@Override
|
|
public Keyboards loadInBackground() {
|
|
final Keyboards keyboards = new Keyboards();
|
|
for (InputMethodInfo imi : mImiSubtypes.keySet()) {
|
|
for (InputMethodSubtype subtype : mImiSubtypes.get(imi)) {
|
|
final KeyboardLayout layout = mIm.getKeyboardLayoutForInputDevice(
|
|
mInputDeviceIdentifier, imi, subtype);
|
|
keyboards.mInfos.add(new Keyboards.KeyboardInfo(imi, subtype, layout));
|
|
}
|
|
}
|
|
return keyboards;
|
|
}
|
|
|
|
@Override
|
|
protected void onStartLoading() {
|
|
super.onStartLoading();
|
|
forceLoad();
|
|
}
|
|
|
|
@Override
|
|
protected void onStopLoading() {
|
|
super.onStopLoading();
|
|
cancelLoad();
|
|
}
|
|
}
|
|
|
|
public static final class Keyboards {
|
|
|
|
public final ArrayList<KeyboardInfo> mInfos = new ArrayList<>();
|
|
|
|
public static final class KeyboardInfo {
|
|
|
|
public final InputMethodInfo mImi;
|
|
public final InputMethodSubtype mImSubtype;
|
|
public final KeyboardLayout mLayout;
|
|
|
|
public KeyboardInfo(
|
|
InputMethodInfo imi, InputMethodSubtype imSubtype, KeyboardLayout layout) {
|
|
mImi = imi;
|
|
mImSubtype = imSubtype;
|
|
mLayout = layout;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|