| /* | |
| * Copyright (C) 2022 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.android.settings.inputmethod; | |
| import android.content.Context; | |
| import android.graphics.drawable.Drawable; | |
| import android.hardware.input.InputManager; | |
| import android.os.Bundle; | |
| import android.text.Spannable; | |
| import android.text.SpannableString; | |
| import android.text.style.ForegroundColorSpan; | |
| import android.util.Pair; | |
| import android.view.KeyEvent; | |
| import android.widget.ImageView; | |
| import android.widget.TextView; | |
| import androidx.fragment.app.Fragment; | |
| import androidx.fragment.app.FragmentManager; | |
| import androidx.preference.Preference; | |
| import androidx.preference.PreferenceScreen; | |
| import com.android.settings.R; | |
| import com.android.settings.core.BasePreferenceController; | |
| import com.android.settings.overlay.FeatureFactory; | |
| import com.android.settingslib.widget.LayoutPreference; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Objects; | |
| public class ModifierKeysPreferenceController extends BasePreferenceController { | |
| private static final String KEY_TAG = "modifier_keys_dialog_tag"; | |
| private static final String KEY_RESTORE_PREFERENCE = "modifier_keys_restore"; | |
| private static final String KEY_PREFERENCE_CAPS_LOCK = "modifier_keys_caps_lock"; | |
| private static final String KEY_PREFERENCE_CTRL = "modifier_keys_ctrl"; | |
| private static final String KEY_PREFERENCE_META = "modifier_keys_meta"; | |
| private static final String KEY_PREFERENCE_ALT = "modifier_keys_alt"; | |
| private Fragment mParent; | |
| private FragmentManager mFragmentManager; | |
| private final InputManager mIm; | |
| private PreferenceScreen mScreen; | |
| private Drawable mDrawable; | |
| private final List<Integer> mRemappableKeys = new ArrayList<>( | |
| Arrays.asList( | |
| KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_CTRL_RIGHT, | |
| KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_META_RIGHT, | |
| KeyEvent.KEYCODE_ALT_LEFT, KeyEvent.KEYCODE_ALT_RIGHT, | |
| KeyEvent.KEYCODE_CAPS_LOCK)); | |
| private final List<Pair<String, Integer>> mKeys = new ArrayList<>( | |
| Arrays.asList( | |
| Pair.create(KEY_PREFERENCE_CTRL, R.string.modifier_keys_ctrl), | |
| Pair.create(KEY_PREFERENCE_META, R.string.modifier_keys_meta), | |
| Pair.create(KEY_PREFERENCE_ALT, R.string.modifier_keys_alt), | |
| Pair.create(KEY_PREFERENCE_CAPS_LOCK, R.string.modifier_keys_caps_lock) | |
| )); | |
| private String[] mKeyNames = new String[] { | |
| mContext.getString(R.string.modifier_keys_ctrl), | |
| mContext.getString(R.string.modifier_keys_ctrl), | |
| mContext.getString(R.string.modifier_keys_meta), | |
| mContext.getString(R.string.modifier_keys_meta), | |
| mContext.getString(R.string.modifier_keys_alt), | |
| mContext.getString(R.string.modifier_keys_alt), | |
| mContext.getString(R.string.modifier_keys_caps_lock)}; | |
| public ModifierKeysPreferenceController(Context context, String key) { | |
| super(context, key); | |
| mIm = context.getSystemService(InputManager.class); | |
| Objects.requireNonNull(mIm, "InputManager service cannot be null"); | |
| KeyboardSettingsFeatureProvider featureProvider = | |
| FeatureFactory.getFeatureFactory().getKeyboardSettingsFeatureProvider(); | |
| mDrawable = featureProvider.getActionKeyIcon(context); | |
| } | |
| public void setFragment(Fragment parent) { | |
| mParent = parent; | |
| } | |
| @Override | |
| public void displayPreference(PreferenceScreen screen) { | |
| super.displayPreference(screen); | |
| if (mParent == null) { | |
| return; | |
| } | |
| mScreen = screen; | |
| refreshUi(); | |
| } | |
| private void refreshUi() { | |
| initDefaultKeysName(); | |
| for (Map.Entry<Integer, Integer> entry : mIm.getModifierKeyRemapping().entrySet()) { | |
| int fromKey = entry.getKey(); | |
| int toKey = entry.getValue(); | |
| int index = mRemappableKeys.indexOf(toKey); | |
| if (isCtrl(fromKey) && mRemappableKeys.contains(toKey)) { | |
| setSummaryColor(KEY_PREFERENCE_CTRL, index); | |
| } | |
| if (isMeta(fromKey) && mRemappableKeys.contains(toKey)) { | |
| setSummaryColor(KEY_PREFERENCE_META, index); | |
| } | |
| if (isAlt(fromKey) && mRemappableKeys.contains(toKey)) { | |
| setSummaryColor(KEY_PREFERENCE_ALT, index); | |
| } | |
| if (isCapLock(fromKey) && mRemappableKeys.contains(toKey)) { | |
| setSummaryColor(KEY_PREFERENCE_CAPS_LOCK, index); | |
| } | |
| } | |
| } | |
| private void initDefaultKeysName() { | |
| for (Pair<String, Integer> key : mKeys) { | |
| LayoutPreference layoutPreference = mScreen.findPreference(key.first); | |
| TextView title = layoutPreference.findViewById(R.id.title); | |
| TextView summary = layoutPreference.findViewById(R.id.summary); | |
| title.setText(key.second); | |
| summary.setText(R.string.modifier_keys_default_summary); | |
| if (key.first.equals(KEY_PREFERENCE_META) && mDrawable != null) { | |
| setActionKeyIcon(layoutPreference, mDrawable); | |
| } | |
| } | |
| } | |
| private static void setActionKeyIcon(LayoutPreference preference, Drawable drawable) { | |
| TextView leftBracket = preference.findViewById(R.id.modifier_key_left_bracket); | |
| TextView rightBracket = preference.findViewById(R.id.modifier_key_right_bracket); | |
| ImageView actionKeyIcon = preference.findViewById(R.id.modifier_key_action_key_icon); | |
| leftBracket.setText("("); | |
| rightBracket.setText(")"); | |
| actionKeyIcon.setImageDrawable(drawable); | |
| } | |
| private void setSummaryColor(String key, int targetIndex) { | |
| LayoutPreference layoutPreference = mScreen.findPreference(key); | |
| TextView summary = layoutPreference.findViewById(R.id.summary); | |
| summary.setText(changeSummaryColor(mKeyNames[targetIndex])); | |
| } | |
| @Override | |
| public boolean handlePreferenceTreeClick(Preference preference) { | |
| if (preference.getKey().equals(KEY_RESTORE_PREFERENCE)) { | |
| return false; | |
| } | |
| showModifierKeysDialog(preference); | |
| return true; | |
| } | |
| @Override | |
| public int getAvailabilityStatus() { | |
| return AVAILABLE; | |
| } | |
| private void showModifierKeysDialog(Preference preference) { | |
| mFragmentManager = mParent.getFragmentManager(); | |
| ModifierKeysPickerDialogFragment fragment = new ModifierKeysPickerDialogFragment(); | |
| fragment.setTargetFragment(mParent, 0); | |
| Bundle bundle = new Bundle(); | |
| TextView title = ((LayoutPreference) preference).findViewById(R.id.title); | |
| TextView summary = ((LayoutPreference) preference).findViewById(R.id.summary); | |
| bundle.putString( | |
| ModifierKeysPickerDialogFragment.DEFAULT_KEY, | |
| title.getText().toString()); | |
| bundle.putString( | |
| ModifierKeysPickerDialogFragment.SELECTION_KEY, | |
| summary.getText().toString()); | |
| fragment.setArguments(bundle); | |
| fragment.show(mFragmentManager, KEY_TAG); | |
| } | |
| private Spannable changeSummaryColor(String summary) { | |
| Spannable spannableSummary = new SpannableString(summary); | |
| spannableSummary.setSpan( | |
| new ForegroundColorSpan(getColorOfMaterialColorPrimary()), | |
| 0, spannableSummary.length(), 0); | |
| return spannableSummary; | |
| } | |
| private int getColorOfMaterialColorPrimary() { | |
| return mContext.getColor(com.android.internal.R.color.materialColorPrimary); | |
| } | |
| private static boolean isCtrl(int keyCode) { | |
| return keyCode == KeyEvent.KEYCODE_CTRL_LEFT || keyCode == KeyEvent.KEYCODE_CTRL_RIGHT; | |
| } | |
| private static boolean isMeta(int keyCode) { | |
| return keyCode == KeyEvent.KEYCODE_META_LEFT || keyCode == KeyEvent.KEYCODE_META_RIGHT; | |
| } | |
| private static boolean isAlt(int keyCode) { | |
| return keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT; | |
| } | |
| private static boolean isCapLock(int keyCode) { | |
| return keyCode == KeyEvent.KEYCODE_CAPS_LOCK; | |
| } | |
| } |