• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.app.settings.SettingsEnums;
20 import android.content.Context;
21 import android.hardware.input.InputDeviceIdentifier;
22 import android.hardware.input.InputManager;
23 import android.hardware.input.KeyboardLayout;
24 import android.os.Bundle;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.util.Log;
28 import android.view.InputDevice;
29 import android.view.inputmethod.InputMethodInfo;
30 import android.view.inputmethod.InputMethodManager;
31 import android.view.inputmethod.InputMethodSubtype;
32 
33 import androidx.preference.Preference;
34 import androidx.preference.PreferenceCategory;
35 import androidx.preference.PreferenceScreen;
36 
37 import com.android.settings.R;
38 import com.android.settings.Utils;
39 import com.android.settings.core.SubSettingLauncher;
40 import com.android.settings.dashboard.DashboardFragment;
41 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
42 import com.android.settings.inputmethod.NewKeyboardSettingsUtils.KeyboardInfo;
43 
44 import java.util.ArrayList;
45 import java.util.Collections;
46 import java.util.Comparator;
47 import java.util.List;
48 
49 public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
50         implements InputManager.InputDeviceListener {
51 
52     private static final String TAG = "NewKeyboardLayoutEnabledLocalesFragment";
53 
54     private InputManager mIm;
55     private InputMethodManager mImm;
56     private InputDeviceIdentifier mInputDeviceIdentifier;
57     private int mUserId;
58     private int mInputDeviceId;
59     private Context mContext;
60     private ArrayList<KeyboardInfo> mKeyboardInfoList = new ArrayList<>();
61 
62     @Override
onAttach(Context context)63     public void onAttach(Context context) {
64         super.onAttach(context);
65 
66         mContext = context;
67         final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE);
68         final int currentUserId = UserHandle.myUserId();
69         final int newUserId;
70         final UserManager userManager = mContext.getSystemService(UserManager.class);
71 
72         switch (profileType) {
73             case ProfileSelectFragment.ProfileType.WORK: {
74                 // If the user is a managed profile user, use currentUserId directly. Or get the
75                 // managed profile userId instead.
76                 newUserId = userManager.isManagedProfile()
77                         ? currentUserId : Utils.getManagedProfileId(userManager, currentUserId);
78                 break;
79             }
80             case ProfileSelectFragment.ProfileType.PERSONAL: {
81                 final UserHandle primaryUser = userManager.getPrimaryUser().getUserHandle();
82                 newUserId = primaryUser.getIdentifier();
83                 break;
84             }
85             default:
86                 newUserId = currentUserId;
87         }
88 
89         mUserId = newUserId;
90         mIm = mContext.getSystemService(InputManager.class);
91         mImm = mContext.getSystemService(InputMethodManager.class);
92         mInputDeviceId = -1;
93     }
94 
95     @Override
onActivityCreated(final Bundle icicle)96     public void onActivityCreated(final Bundle icicle) {
97         super.onActivityCreated(icicle);
98         Bundle arguments = getArguments();
99         mInputDeviceIdentifier =
100                 arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
101         if (mInputDeviceIdentifier == null) {
102             Log.e(TAG, "The inputDeviceIdentifier should not be null");
103             return;
104         }
105         InputDevice inputDevice =
106                 NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier);
107         if (inputDevice == null) {
108             Log.e(TAG, "inputDevice is null");
109             return;
110         }
111         final String title = inputDevice.getName();
112         getActivity().setTitle(title);
113     }
114 
115     @Override
onStart()116     public void onStart() {
117         super.onStart();
118         mIm.registerInputDeviceListener(this, null);
119         InputDevice inputDevice =
120                 NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier);
121         if (inputDevice == null) {
122             getActivity().finish();
123             return;
124         }
125         mInputDeviceId = inputDevice.getId();
126     }
127 
128     @Override
onResume()129     public void onResume() {
130         super.onResume();
131         updateCheckedState();
132     }
133 
134     @Override
onStop()135     public void onStop() {
136         super.onStop();
137         mIm.unregisterInputDeviceListener(this);
138         mInputDeviceId = -1;
139     }
140 
updateCheckedState()141     private void updateCheckedState() {
142         if (NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) {
143             return;
144         }
145 
146         PreferenceScreen preferenceScreen = getPreferenceScreen();
147         preferenceScreen.removeAll();
148         List<InputMethodInfo> infoList = mImm.getEnabledInputMethodListAsUser(mUserId);
149         Collections.sort(infoList, new Comparator<InputMethodInfo>() {
150             public int compare(InputMethodInfo o1, InputMethodInfo o2) {
151                 String s1 = o1.loadLabel(mContext.getPackageManager()).toString();
152                 String s2 = o2.loadLabel(mContext.getPackageManager()).toString();
153                 return s1.compareTo(s2);
154             }
155         });
156 
157         for (InputMethodInfo info : infoList) {
158             mKeyboardInfoList.clear();
159             List<InputMethodSubtype> subtypes =
160                     mImm.getEnabledInputMethodSubtypeListAsUser(info.getId(), true, mUserId);
161             for (InputMethodSubtype subtype : subtypes) {
162                 if (subtype.isSuitableForPhysicalKeyboardLayoutMapping()) {
163                     mapLanguageWithLayout(info, subtype);
164                 }
165             }
166             updatePreferenceLayout(preferenceScreen, info);
167         }
168     }
169 
mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype)170     private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) {
171         CharSequence subtypeLabel = getSubtypeLabel(mContext, info, subtype);
172         KeyboardLayout[] keyboardLayouts =
173                 NewKeyboardSettingsUtils.getKeyboardLayouts(
174                         mIm, mUserId, mInputDeviceIdentifier, info, subtype);
175         String layout = NewKeyboardSettingsUtils.getKeyboardLayout(
176                 mIm, mUserId, mInputDeviceIdentifier, info, subtype);
177         if (layout != null) {
178             for (int i = 0; i < keyboardLayouts.length; i++) {
179                 if (keyboardLayouts[i].getDescriptor().equals(layout)) {
180                     KeyboardInfo keyboardInfo = new KeyboardInfo(
181                             subtypeLabel,
182                             keyboardLayouts[i].getLabel(),
183                             info,
184                             subtype);
185                     mKeyboardInfoList.add(keyboardInfo);
186                     break;
187                 }
188             }
189         } else {
190             // if there is no auto-selected layout, we should show "Default"
191             KeyboardInfo keyboardInfo = new KeyboardInfo(
192                     subtypeLabel,
193                     mContext.getString(R.string.keyboard_default_layout),
194                     info,
195                     subtype);
196             mKeyboardInfoList.add(keyboardInfo);
197         }
198     }
199 
updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info)200     private void updatePreferenceLayout(PreferenceScreen preferenceScreen, InputMethodInfo info) {
201         if (mKeyboardInfoList.isEmpty()) {
202             return;
203         }
204         PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
205         preferenceCategory.setTitle(info.loadLabel(mContext.getPackageManager()));
206         preferenceCategory.setKey(info.getPackageName());
207         preferenceScreen.addPreference(preferenceCategory);
208         Collections.sort(mKeyboardInfoList, new Comparator<KeyboardInfo>() {
209             public int compare(KeyboardInfo o1, KeyboardInfo o2) {
210                 String s1 = o1.getSubtypeLabel().toString();
211                 String s2 = o2.getSubtypeLabel().toString();
212                 return s1.compareTo(s2);
213             }
214         });
215 
216         for (KeyboardInfo keyboardInfo : mKeyboardInfoList) {
217             final Preference pref = new Preference(mContext);
218             pref.setKey(keyboardInfo.getPrefId());
219             pref.setTitle(keyboardInfo.getSubtypeLabel());
220             pref.setSummary(keyboardInfo.getLayout());
221             pref.setOnPreferenceClickListener(
222                     preference -> {
223                         showKeyboardLayoutPicker(
224                                 keyboardInfo.getSubtypeLabel(),
225                                 mInputDeviceIdentifier,
226                                 mUserId,
227                                 keyboardInfo.getInputMethodInfo(),
228                                 keyboardInfo.getInputMethodSubtype());
229                         return true;
230                     });
231             preferenceCategory.addPreference(pref);
232         }
233     }
234 
235     @Override
onInputDeviceAdded(int deviceId)236     public void onInputDeviceAdded(int deviceId) {
237         // Do nothing.
238     }
239 
240     @Override
onInputDeviceRemoved(int deviceId)241     public void onInputDeviceRemoved(int deviceId) {
242         if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
243             getActivity().finish();
244         }
245     }
246 
247     @Override
onInputDeviceChanged(int deviceId)248     public void onInputDeviceChanged(int deviceId) {
249         if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) {
250             updateCheckedState();
251         }
252     }
253 
254     @Override
getLogTag()255     protected String getLogTag() {
256         return TAG;
257     }
258 
259     @Override
getMetricsCategory()260     public int getMetricsCategory() {
261         return SettingsEnums.SETTINGS_KEYBOARDS_ENABLED_LOCALES;
262     }
263 
264     @Override
getPreferenceScreenResId()265     protected int getPreferenceScreenResId() {
266         return R.xml.keyboard_settings_enabled_locales_list;
267     }
268 
showKeyboardLayoutPicker( CharSequence subtypeLabel, InputDeviceIdentifier inputDeviceIdentifier, int userId, InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype)269     private void showKeyboardLayoutPicker(
270             CharSequence subtypeLabel,
271             InputDeviceIdentifier inputDeviceIdentifier,
272             int userId,
273             InputMethodInfo inputMethodInfo,
274             InputMethodSubtype inputMethodSubtype) {
275         Bundle arguments = new Bundle();
276         arguments.putParcelable(
277                 NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, inputDeviceIdentifier);
278         arguments.putParcelable(
279                 NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO, inputMethodInfo);
280         arguments.putParcelable(
281                 NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype);
282         arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId);
283         arguments.putCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE, subtypeLabel);
284         new SubSettingLauncher(mContext)
285                 .setSourceMetricsCategory(getMetricsCategory())
286                 .setDestination(NewKeyboardLayoutPickerFragment.class.getName())
287                 .setArguments(arguments)
288                 .launch();
289     }
290 
getSubtypeLabel( Context context, InputMethodInfo info, InputMethodSubtype subtype)291     private CharSequence getSubtypeLabel(
292             Context context, InputMethodInfo info, InputMethodSubtype subtype) {
293         return subtype.getDisplayName(
294                 context, info.getPackageName(), info.getServiceInfo().applicationInfo);
295     }
296 }
297