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.annotation.Nullable;
20import android.app.Activity;
21import android.hardware.input.InputDeviceIdentifier;
22import android.hardware.input.InputManager;
23import android.hardware.input.InputManager.InputDeviceListener;
24import android.hardware.input.KeyboardLayout;
25import android.os.Bundle;
26import android.support.v7.preference.Preference;
27import android.support.v7.preference.PreferenceScreen;
28import android.view.InputDevice;
29
30import android.view.inputmethod.InputMethodInfo;
31import android.view.inputmethod.InputMethodSubtype;
32import com.android.internal.logging.MetricsLogger;
33import com.android.internal.logging.MetricsProto.MetricsEvent;
34import com.android.internal.util.Preconditions;
35import com.android.settings.R;
36import com.android.settings.SettingsPreferenceFragment;
37import com.android.settings.inputmethod.PhysicalKeyboardFragment.KeyboardInfoPreference;
38
39import java.util.Arrays;
40import java.util.HashMap;
41import java.util.Map;
42
43public final class KeyboardLayoutPickerFragment2 extends SettingsPreferenceFragment
44        implements InputDeviceListener {
45
46    private InputDeviceIdentifier mInputDeviceIdentifier;
47    private int mInputDeviceId = -1;
48    private InputManager mIm;
49    private InputMethodInfo mImi;
50    @Nullable
51    private InputMethodSubtype mSubtype;
52    private KeyboardLayout[] mKeyboardLayouts;
53    private Map<Preference, KeyboardLayout> mPreferenceMap = new HashMap<>();
54
55    // TODO: Make these constants public API for b/25752827
56
57    /**
58     * Intent extra: The input device descriptor of the keyboard whose keyboard
59     * layout is to be changed.
60     */
61    public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier";
62
63    /**
64     * Intent extra: The associated {@link InputMethodInfo}.
65     */
66    public static final String EXTRA_INPUT_METHOD_INFO = "input_method_info";
67
68    /**
69     * Intent extra: The associated {@link InputMethodSubtype}.
70     */
71    public static final String EXTRA_INPUT_METHOD_SUBTYPE = "input_method_subtype";
72
73    @Override
74    protected int getMetricsCategory() {
75        return MetricsEvent.INPUTMETHOD_KEYBOARD;
76    }
77
78    @Override
79    public void onCreate(Bundle icicle) {
80        super.onCreate(icicle);
81        Activity activity = Preconditions.checkNotNull(getActivity());
82
83        mInputDeviceIdentifier = activity.getIntent().getParcelableExtra(
84                EXTRA_INPUT_DEVICE_IDENTIFIER);
85        mImi = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_INFO);
86        mSubtype = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_SUBTYPE);
87
88        if (mInputDeviceIdentifier == null || mImi == null) {
89            activity.finish();
90        }
91
92        mIm = activity.getSystemService(InputManager.class);
93        mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier);
94        Arrays.sort(mKeyboardLayouts);
95        setPreferenceScreen(createPreferenceHierarchy());
96    }
97
98    @Override
99    public void onResume() {
100        super.onResume();
101
102        mIm.registerInputDeviceListener(this, null);
103
104        InputDevice inputDevice =
105                mIm.getInputDeviceByDescriptor(mInputDeviceIdentifier.getDescriptor());
106        if (inputDevice == null) {
107            getActivity().finish();
108            return;
109        }
110        mInputDeviceId = inputDevice.getId();
111    }
112
113    @Override
114    public void onPause() {
115        mIm.unregisterInputDeviceListener(this);
116        mInputDeviceId = -1;
117
118        super.onPause();
119    }
120
121    @Override
122    public boolean onPreferenceTreeClick(Preference preference) {
123        KeyboardLayout layout = mPreferenceMap.get(preference);
124        if (layout != null) {
125            mIm.setKeyboardLayoutForInputDevice(mInputDeviceIdentifier, mImi, mSubtype,
126                    layout.getDescriptor());
127            getActivity().finish();
128            return true;
129        }
130        return super.onPreferenceTreeClick(preference);
131    }
132
133    @Override
134    public void onInputDeviceAdded(int deviceId) {}
135
136    @Override
137    public void onInputDeviceChanged(int deviceId) {}
138
139    @Override
140    public void onInputDeviceRemoved(int deviceId) {
141        if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
142            getActivity().finish();
143        }
144    }
145
146    private PreferenceScreen createPreferenceHierarchy() {
147        PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
148
149        for (KeyboardLayout layout : mKeyboardLayouts) {
150            Preference pref = new Preference(getPrefContext());
151            pref.setTitle(layout.getLabel());
152            pref.setSummary(layout.getCollection());
153            root.addPreference(pref);
154            mPreferenceMap.put(pref, layout);
155        }
156
157        root.setTitle(KeyboardInfoPreference.getDisplayName(getContext(), mImi, mSubtype));
158        return root;
159    }
160}
161