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 
17 package com.android.settings.inputmethod;
18 
19 import android.annotation.Nullable;
20 import android.app.Activity;
21 import android.hardware.input.InputDeviceIdentifier;
22 import android.hardware.input.InputManager;
23 import android.hardware.input.InputManager.InputDeviceListener;
24 import android.hardware.input.KeyboardLayout;
25 import android.os.Bundle;
26 import android.support.v7.preference.Preference;
27 import android.support.v7.preference.PreferenceScreen;
28 import android.view.InputDevice;
29 
30 import android.view.inputmethod.InputMethodInfo;
31 import android.view.inputmethod.InputMethodSubtype;
32 import com.android.internal.logging.MetricsLogger;
33 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
34 import com.android.internal.util.Preconditions;
35 import com.android.settings.R;
36 import com.android.settings.SettingsPreferenceFragment;
37 import com.android.settings.inputmethod.PhysicalKeyboardFragment.KeyboardInfoPreference;
38 
39 import java.util.Arrays;
40 import java.util.HashMap;
41 import java.util.Map;
42 
43 public final class KeyboardLayoutPickerFragment 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
getMetricsCategory()74     public int getMetricsCategory() {
75         return MetricsEvent.INPUTMETHOD_KEYBOARD;
76     }
77 
78     @Override
onCreate(Bundle icicle)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
onResume()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
onPause()114     public void onPause() {
115         mIm.unregisterInputDeviceListener(this);
116         mInputDeviceId = -1;
117 
118         super.onPause();
119     }
120 
121     @Override
onPreferenceTreeClick(Preference preference)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
onInputDeviceAdded(int deviceId)134     public void onInputDeviceAdded(int deviceId) {}
135 
136     @Override
onInputDeviceChanged(int deviceId)137     public void onInputDeviceChanged(int deviceId) {}
138 
139     @Override
onInputDeviceRemoved(int deviceId)140     public void onInputDeviceRemoved(int deviceId) {
141         if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
142             getActivity().finish();
143         }
144     }
145 
createPreferenceHierarchy()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