• 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.content.Context;
20 import android.graphics.drawable.Drawable;
21 import android.hardware.input.InputManager;
22 import android.os.Bundle;
23 import android.text.Spannable;
24 import android.text.SpannableString;
25 import android.text.style.ForegroundColorSpan;
26 import android.util.Pair;
27 import android.view.KeyEvent;
28 import android.widget.ImageView;
29 import android.widget.TextView;
30 
31 import androidx.fragment.app.Fragment;
32 import androidx.fragment.app.FragmentManager;
33 import androidx.preference.Preference;
34 import androidx.preference.PreferenceScreen;
35 
36 import com.android.settings.R;
37 import com.android.settings.core.BasePreferenceController;
38 import com.android.settings.overlay.FeatureFactory;
39 import com.android.settingslib.widget.LayoutPreference;
40 
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.Objects;
46 
47 public class ModifierKeysPreferenceController extends BasePreferenceController {
48 
49     private static final String KEY_TAG = "modifier_keys_dialog_tag";
50     private static final String KEY_RESTORE_PREFERENCE = "modifier_keys_restore";
51 
52     private static final String KEY_PREFERENCE_CAPS_LOCK = "modifier_keys_caps_lock";
53     private static final String KEY_PREFERENCE_CTRL = "modifier_keys_ctrl";
54     private static final String KEY_PREFERENCE_META = "modifier_keys_meta";
55     private static final String KEY_PREFERENCE_ALT = "modifier_keys_alt";
56 
57     private Fragment mParent;
58     private FragmentManager mFragmentManager;
59     private final InputManager mIm;
60     private PreferenceScreen mScreen;
61     private Drawable mDrawable;
62 
63     private final List<Integer> mRemappableKeys = new ArrayList<>(
64             Arrays.asList(
65                     KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_CTRL_RIGHT,
66                     KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_META_RIGHT,
67                     KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_ALT_RIGHT,
68                     KeyEvent.KEYCODE_CAPS_LOCK));
69 
70     private final List<Pair<String, Integer>> mKeys = new ArrayList<>(
71             Arrays.asList(
72                     Pair.create(KEY_PREFERENCE_CTRL, R.string.modifier_keys_ctrl),
73                     Pair.create(KEY_PREFERENCE_META, R.string.modifier_keys_meta),
74                     Pair.create(KEY_PREFERENCE_ALT, R.string.modifier_keys_alt),
75                     Pair.create(KEY_PREFERENCE_CAPS_LOCK, R.string.modifier_keys_caps_lock)
76             ));
77 
78     private String[] mKeyNames = new String[] {
79             mContext.getString(R.string.modifier_keys_ctrl),
80             mContext.getString(R.string.modifier_keys_ctrl),
81             mContext.getString(R.string.modifier_keys_meta),
82             mContext.getString(R.string.modifier_keys_meta),
83             mContext.getString(R.string.modifier_keys_alt),
84             mContext.getString(R.string.modifier_keys_alt),
85             mContext.getString(R.string.modifier_keys_caps_lock)};
86 
ModifierKeysPreferenceController(Context context, String key)87     public ModifierKeysPreferenceController(Context context, String key) {
88         super(context, key);
89         mIm = context.getSystemService(InputManager.class);
90         Objects.requireNonNull(mIm, "InputManager service cannot be null");
91         KeyboardSettingsFeatureProvider featureProvider =
92                 FeatureFactory.getFeatureFactory().getKeyboardSettingsFeatureProvider();
93         mDrawable = featureProvider.getActionKeyIcon(context);
94     }
95 
setFragment(Fragment parent)96     public void setFragment(Fragment parent) {
97         mParent = parent;
98     }
99 
100     @Override
displayPreference(PreferenceScreen screen)101     public void displayPreference(PreferenceScreen screen) {
102         super.displayPreference(screen);
103         if (mParent == null) {
104             return;
105         }
106         mScreen = screen;
107         refreshUi();
108     }
109 
refreshUi()110     private void refreshUi() {
111         initDefaultKeysName();
112         for (Map.Entry<Integer, Integer> entry : mIm.getModifierKeyRemapping().entrySet()) {
113             int fromKey = entry.getKey();
114             int toKey = entry.getValue();
115             int index = mRemappableKeys.indexOf(toKey);
116 
117             if (isCtrl(fromKey) && mRemappableKeys.contains(toKey)) {
118                 setSummaryColor(KEY_PREFERENCE_CTRL, index);
119             }
120 
121             if (isMeta(fromKey) && mRemappableKeys.contains(toKey)) {
122                 setSummaryColor(KEY_PREFERENCE_META, index);
123             }
124 
125             if (isAlt(fromKey) && mRemappableKeys.contains(toKey)) {
126                 setSummaryColor(KEY_PREFERENCE_ALT, index);
127             }
128 
129             if (isCapLock(fromKey) && mRemappableKeys.contains(toKey)) {
130                 setSummaryColor(KEY_PREFERENCE_CAPS_LOCK, index);
131             }
132         }
133     }
134 
initDefaultKeysName()135     private void initDefaultKeysName() {
136         for (Pair<String, Integer> key : mKeys) {
137             LayoutPreference layoutPreference = mScreen.findPreference(key.first);
138             TextView title = layoutPreference.findViewById(R.id.title);
139             TextView summary = layoutPreference.findViewById(R.id.summary);
140             title.setText(key.second);
141             summary.setText(R.string.modifier_keys_default_summary);
142 
143             if (key.first.equals(KEY_PREFERENCE_META) && mDrawable != null) {
144                 setActionKeyIcon(layoutPreference, mDrawable);
145             }
146         }
147     }
148 
setActionKeyIcon(LayoutPreference preference, Drawable drawable)149     private static void setActionKeyIcon(LayoutPreference preference, Drawable drawable) {
150         TextView leftBracket = preference.findViewById(R.id.modifier_key_left_bracket);
151         TextView rightBracket = preference.findViewById(R.id.modifier_key_right_bracket);
152         ImageView actionKeyIcon = preference.findViewById(R.id.modifier_key_action_key_icon);
153         leftBracket.setText("(");
154         rightBracket.setText(")");
155         actionKeyIcon.setImageDrawable(drawable);
156     }
157 
setSummaryColor(String key, int targetIndex)158     private void setSummaryColor(String key, int targetIndex) {
159         LayoutPreference layoutPreference = mScreen.findPreference(key);
160         TextView summary = layoutPreference.findViewById(R.id.summary);
161         summary.setText(changeSummaryColor(mKeyNames[targetIndex]));
162     }
163 
164     @Override
handlePreferenceTreeClick(Preference preference)165     public boolean handlePreferenceTreeClick(Preference preference) {
166         if (preference.getKey().equals(KEY_RESTORE_PREFERENCE)) {
167             return false;
168         }
169         showModifierKeysDialog(preference);
170         return true;
171     }
172 
173     @Override
getAvailabilityStatus()174     public int getAvailabilityStatus() {
175         return AVAILABLE;
176     }
177 
showModifierKeysDialog(Preference preference)178     private void showModifierKeysDialog(Preference preference) {
179         mFragmentManager = mParent.getFragmentManager();
180         ModifierKeysPickerDialogFragment fragment = new ModifierKeysPickerDialogFragment();
181         fragment.setTargetFragment(mParent, 0);
182         Bundle bundle = new Bundle();
183         TextView title = ((LayoutPreference) preference).findViewById(R.id.title);
184         TextView summary = ((LayoutPreference) preference).findViewById(R.id.summary);
185         bundle.putString(
186                 ModifierKeysPickerDialogFragment.DEFAULT_KEY,
187                 title.getText().toString());
188         bundle.putString(
189                 ModifierKeysPickerDialogFragment.SELECTION_KEY,
190                 summary.getText().toString());
191         fragment.setArguments(bundle);
192         fragment.show(mFragmentManager, KEY_TAG);
193     }
194 
changeSummaryColor(String summary)195     private Spannable changeSummaryColor(String summary) {
196         Spannable spannableSummary = new SpannableString(summary);
197         spannableSummary.setSpan(
198                 new ForegroundColorSpan(getColorOfMaterialColorPrimary()),
199                 0, spannableSummary.length(), 0);
200         return spannableSummary;
201     }
202 
getColorOfMaterialColorPrimary()203     private int getColorOfMaterialColorPrimary() {
204         return mContext.getColor(com.android.internal.R.color.materialColorPrimary);
205     }
206 
isCtrl(int keyCode)207     private static boolean isCtrl(int keyCode) {
208         return keyCode == KeyEvent.KEYCODE_CTRL_LEFT || keyCode == KeyEvent.KEYCODE_CTRL_RIGHT;
209     }
210 
isMeta(int keyCode)211     private static boolean isMeta(int keyCode) {
212         return keyCode == KeyEvent.KEYCODE_META_LEFT || keyCode == KeyEvent.KEYCODE_META_RIGHT;
213     }
214 
isAlt(int keyCode)215     private static boolean isAlt(int keyCode) {
216         return keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT;
217     }
218 
isCapLock(int keyCode)219     private static boolean isCapLock(int keyCode) {
220         return keyCode == KeyEvent.KEYCODE_CAPS_LOCK;
221     }
222 }
223