1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.inputmethod;
18
19import android.content.Context;
20import android.hardware.input.InputDeviceIdentifier;
21import android.hardware.input.InputManager;
22import android.hardware.input.InputManager.InputDeviceListener;
23import android.hardware.input.KeyboardLayout;
24import android.os.Bundle;
25import android.support.v7.preference.CheckBoxPreference;
26import android.support.v7.preference.Preference;
27import android.support.v7.preference.PreferenceScreen;
28import android.view.InputDevice;
29
30import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
31import com.android.settings.SettingsPreferenceFragment;
32
33import java.util.Arrays;
34import java.util.HashMap;
35import java.util.Map;
36
37public class KeyboardLayoutPickerFragment extends SettingsPreferenceFragment
38        implements InputDeviceListener {
39    private InputDeviceIdentifier mInputDeviceIdentifier;
40    private int mInputDeviceId = -1;
41    private InputManager mIm;
42    private KeyboardLayout[] mKeyboardLayouts;
43    private HashMap<CheckBoxPreference, KeyboardLayout> mPreferenceMap = new HashMap<>();
44
45    /**
46     * Intent extra: The input device descriptor of the keyboard whose keyboard
47     * layout is to be changed.
48     */
49    public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
50
51    @Override
52    public int getMetricsCategory() {
53        return MetricsEvent.INPUTMETHOD_KEYBOARD;
54    }
55
56    @Override
57    public void onCreate(Bundle icicle) {
58        super.onCreate(icicle);
59
60        mInputDeviceIdentifier = getActivity().getIntent().getParcelableExtra(
61                EXTRA_INPUT_DEVICE_IDENTIFIER);
62        if (mInputDeviceIdentifier == null) {
63            getActivity().finish();
64        }
65
66        mIm = (InputManager) getSystemService(Context.INPUT_SERVICE);
67        mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
68        Arrays.sort(mKeyboardLayouts);
69        setPreferenceScreen(createPreferenceHierarchy());
70    }
71
72    @Override
73    public void onResume() {
74        super.onResume();
75
76        mIm.registerInputDeviceListener(this, null);
77
78        InputDevice inputDevice =
79                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
80        if (inputDevice == null) {
81            getActivity().finish();
82            return;
83        }
84        mInputDeviceId = inputDevice.getId();
85
86        updateCheckedState();
87    }
88
89    @Override
90    public void onPause() {
91        mIm.unregisterInputDeviceListener(this);
92        mInputDeviceId = -1;
93
94        super.onPause();
95    }
96
97    @Override
98    public boolean onPreferenceTreeClick(Preference preference) {
99        if (preference instanceof CheckBoxPreference) {
100            CheckBoxPreference checkboxPref = (CheckBoxPreference)preference;
101            KeyboardLayout layout = mPreferenceMap.get(checkboxPref);
102            if (layout != null) {
103                boolean checked = checkboxPref.isChecked();
104                if (checked) {
105                    mIm.addKeyboardLayoutForInputDevice(mInputDeviceIdentifier,
106                            layout.getDescriptor());
107                } else {
108                    mIm.removeKeyboardLayoutForInputDevice(mInputDeviceIdentifier,
109                            layout.getDescriptor());
110                }
111                return true;
112            }
113        }
114        return super.onPreferenceTreeClick(preference);
115    }
116
117    @Override
118    public void onInputDeviceAdded(int deviceId) {
119    }
120
121    @Override
122    public void onInputDeviceChanged(int deviceId) {
123        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
124            updateCheckedState();
125        }
126    }
127
128    @Override
129    public void onInputDeviceRemoved(int deviceId) {
130        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
131            getActivity().finish();
132        }
133    }
134
135    private PreferenceScreen createPreferenceHierarchy() {
136        PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
137
138        for (KeyboardLayout layout : mKeyboardLayouts) {
139            CheckBoxPreference pref = new CheckBoxPreference(getPrefContext());
140            pref.setTitle(layout.getLabel());
141            pref.setSummary(layout.getCollection());
142            root.addPreference(pref);
143            mPreferenceMap.put(pref, layout);
144        }
145        return root;
146    }
147
148    private void updateCheckedState() {
149        String[] enabledKeyboardLayouts = mIm.getEnabledKeyboardLayoutsForInputDevice(
150                mInputDeviceIdentifier);
151        Arrays.sort(enabledKeyboardLayouts);
152
153        for (Map.Entry<CheckBoxPreference, KeyboardLayout> entry : mPreferenceMap.entrySet()) {
154            entry.getKey().setChecked(Arrays.binarySearch(enabledKeyboardLayouts,
155                    entry.getValue().getDescriptor()) >= 0);
156        }
157    }
158}
159