• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.car.developeroptions.inputmethod;
18 
19 import android.annotation.DrawableRes;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.app.Activity;
23 import android.app.admin.DevicePolicyManager;
24 import android.app.settings.SettingsEnums;
25 import android.content.Context;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ServiceInfo;
29 import android.content.res.Configuration;
30 import android.graphics.Color;
31 import android.graphics.drawable.ColorDrawable;
32 import android.graphics.drawable.Drawable;
33 import android.os.Bundle;
34 import android.provider.SearchIndexableResource;
35 import android.view.inputmethod.InputMethodInfo;
36 import android.view.inputmethod.InputMethodManager;
37 
38 import com.android.car.developeroptions.R;
39 import com.android.car.developeroptions.SettingsPreferenceFragment;
40 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
41 import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtilCompat;
42 import com.android.settingslib.inputmethod.InputMethodPreference;
43 import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper;
44 import com.android.settingslib.search.SearchIndexable;
45 
46 import java.text.Collator;
47 import java.util.ArrayList;
48 import java.util.List;
49 
50 @SearchIndexable
51 public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFragment
52         implements InputMethodPreference.OnSavePreferenceListener {
53 
54     private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<>();
55     private InputMethodSettingValuesWrapper mInputMethodSettingValues;
56     private InputMethodManager mImm;
57     private DevicePolicyManager mDpm;
58 
59     @Override
onCreatePreferences(Bundle bundle, String s)60     public void onCreatePreferences(Bundle bundle, String s) {
61         addPreferencesFromResource(R.xml.available_virtual_keyboard);
62         Activity activity = getActivity();
63 
64         mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(activity);
65         mImm = activity.getSystemService(InputMethodManager.class);
66         mDpm = activity.getSystemService(DevicePolicyManager.class);
67     }
68 
69     @Override
onResume()70     public void onResume() {
71         super.onResume();
72         // Refresh internal states in mInputMethodSettingValues to keep the latest
73         // "InputMethodInfo"s and "InputMethodSubtype"s
74         mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
75         updateInputMethodPreferenceViews();
76     }
77 
78     @Override
onSaveInputMethodPreference(final InputMethodPreference pref)79     public void onSaveInputMethodPreference(final InputMethodPreference pref) {
80         final boolean hasHardwareKeyboard = getResources().getConfiguration().keyboard
81                 == Configuration.KEYBOARD_QWERTY;
82         InputMethodAndSubtypeUtilCompat.saveInputMethodSubtypeList(this, getContentResolver(),
83                 mImm.getInputMethodList(), hasHardwareKeyboard);
84         // Update input method settings and preference list.
85         mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
86         for (final InputMethodPreference p : mInputMethodPreferenceList) {
87             p.updatePreferenceViews();
88         }
89     }
90 
91     @Override
getMetricsCategory()92     public int getMetricsCategory() {
93         return SettingsEnums.ENABLE_VIRTUAL_KEYBOARDS;
94     }
95 
96     @Nullable
loadDrawable(@onNull final PackageManager packageManager, @NonNull final String packageName, @DrawableRes final int resId, @NonNull final ApplicationInfo applicationInfo)97     private static Drawable loadDrawable(@NonNull final PackageManager packageManager,
98             @NonNull final String packageName, @DrawableRes final int resId,
99             @NonNull final ApplicationInfo applicationInfo) {
100         if (resId == 0) {
101             return null;
102         }
103         try {
104             return packageManager.getDrawable(packageName, resId, applicationInfo);
105         } catch (Exception e) {
106             return null;
107         }
108     }
109 
110     @NonNull
getInputMethodIcon(@onNull final PackageManager packageManager, @NonNull final InputMethodInfo imi)111     private static Drawable getInputMethodIcon(@NonNull final PackageManager packageManager,
112             @NonNull final InputMethodInfo imi) {
113         final ServiceInfo si = imi.getServiceInfo();
114         final ApplicationInfo ai = si != null ? si.applicationInfo : null;
115         final String packageName = imi.getPackageName();
116         if (si == null || ai == null || packageName == null) {
117             return new ColorDrawable(Color.TRANSPARENT);
118         }
119         // We do not use ServiceInfo#loadLogo() and ServiceInfo#loadIcon here since those methods
120         // internally have some fallback rules, which we want to do manually.
121         Drawable drawable = loadDrawable(packageManager, packageName, si.logo, ai);
122         if (drawable != null) {
123             return drawable;
124         }
125         drawable = loadDrawable(packageManager, packageName, si.icon, ai);
126         if (drawable != null) {
127             return drawable;
128         }
129         // We do not use ApplicationInfo#loadLogo() and ApplicationInfo#loadIcon here since those
130         // methods internally have some fallback rules, which we want to do manually.
131         drawable = loadDrawable(packageManager, packageName, ai.logo, ai);
132         if (drawable != null) {
133             return drawable;
134         }
135         drawable = loadDrawable(packageManager, packageName, ai.icon, ai);
136         if (drawable != null) {
137             return drawable;
138         }
139         return new ColorDrawable(Color.TRANSPARENT);
140     }
141 
updateInputMethodPreferenceViews()142     private void updateInputMethodPreferenceViews() {
143         mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
144         // Clear existing "InputMethodPreference"s
145         mInputMethodPreferenceList.clear();
146         List<String> permittedList = mDpm.getPermittedInputMethodsForCurrentUser();
147         final Context context = getPrefContext();
148         final PackageManager packageManager = getActivity().getPackageManager();
149         final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList();
150         final int numImis = (imis == null ? 0 : imis.size());
151         for (int i = 0; i < numImis; ++i) {
152             final InputMethodInfo imi = imis.get(i);
153             final boolean isAllowedByOrganization = permittedList == null
154                     || permittedList.contains(imi.getPackageName());
155             final InputMethodPreference pref = new InputMethodPreference(
156                     context, imi, true, isAllowedByOrganization, this);
157             pref.setIcon(getInputMethodIcon(packageManager, imi));
158             mInputMethodPreferenceList.add(pref);
159         }
160         final Collator collator = Collator.getInstance();
161         mInputMethodPreferenceList.sort((lhs, rhs) -> lhs.compareTo(rhs, collator));
162         getPreferenceScreen().removeAll();
163         for (int i = 0; i < numImis; ++i) {
164             final InputMethodPreference pref = mInputMethodPreferenceList.get(i);
165             pref.setOrder(i);
166             getPreferenceScreen().addPreference(pref);
167             InputMethodAndSubtypeUtilCompat.removeUnnecessaryNonPersistentPreference(pref);
168             pref.updatePreferenceViews();
169         }
170     }
171 
172     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
173             new BaseSearchIndexProvider() {
174                 @Override
175                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
176                         boolean enabled) {
177                     List<SearchIndexableResource> res = new ArrayList<>();
178                     SearchIndexableResource index = new SearchIndexableResource(context);
179                     index.xmlResId = R.xml.available_virtual_keyboard;
180                     res.add(index);
181                     return res;
182                 }
183             };
184 }
185