1 /* 2 * Copyright (C) 2023 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 static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE; 20 import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER; 21 import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SuppressLint; 26 import android.annotation.UserIdInt; 27 import android.content.Context; 28 import android.hardware.input.InputDeviceIdentifier; 29 import android.hardware.input.InputManager; 30 import android.hardware.input.KeyboardLayout; 31 import android.hardware.input.KeyboardLayoutSelectionResult; 32 import android.hardware.input.KeyboardLayoutSelectionResult.LayoutSelectionCriteria; 33 import android.os.UserHandle; 34 import android.view.InputDevice; 35 import android.view.inputmethod.InputMethodInfo; 36 import android.view.inputmethod.InputMethodManager; 37 import android.view.inputmethod.InputMethodSubtype; 38 39 import androidx.annotation.StringRes; 40 41 import com.android.settings.R; 42 43 import java.util.Arrays; 44 import java.util.Comparator; 45 46 /** 47 * Utilities of input peripherals settings 48 */ 49 public class InputPeripheralsSettingsUtils { 50 51 static final String EXTRA_TITLE = "keyboard_layout_picker_title"; 52 static final String EXTRA_USER_ID = "user_id"; 53 static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier"; 54 static final String EXTRA_INPUT_DEVICE = "input_device"; 55 static final String EXTRA_INPUT_METHOD_INFO = "input_method_info"; 56 static final String EXTRA_INPUT_METHOD_SUBTYPE = "input_method_subtype"; 57 58 /** 59 * Returns whether any hard keyboard is connected. 60 */ isHardKeyboard()61 static boolean isHardKeyboard() { 62 for (int deviceId : InputDevice.getDeviceIds()) { 63 final InputDevice device = InputDevice.getDevice(deviceId); 64 if (device == null) { 65 continue; 66 } 67 if (device.isFullKeyboard() && !device.isVirtual()) { 68 return true; 69 } 70 } 71 return false; 72 } 73 74 /** 75 * Returns whether any touchpad is connected. 76 */ isTouchpad()77 static boolean isTouchpad() { 78 for (int deviceId : InputDevice.getDeviceIds()) { 79 final InputDevice device = InputDevice.getDevice(deviceId); 80 if (device == null) { 81 continue; 82 } 83 if ((device.getSources() & InputDevice.SOURCE_TOUCHPAD) 84 == InputDevice.SOURCE_TOUCHPAD) { 85 return true; 86 } 87 } 88 return false; 89 } 90 91 /** 92 * Returns whether any mouse is connected. 93 */ isMouse()94 static boolean isMouse() { 95 for (int deviceId : InputDevice.getDeviceIds()) { 96 final InputDevice device = InputDevice.getDevice(deviceId); 97 if (device == null) { 98 continue; 99 } 100 if ((device.getSources() & InputDevice.SOURCE_MOUSE) 101 == InputDevice.SOURCE_MOUSE) { 102 return true; 103 } 104 } 105 return false; 106 } 107 getTouchpadAndMouseTitleTitleResId()108 static @StringRes int getTouchpadAndMouseTitleTitleResId() { 109 boolean isMouse = isMouse(); 110 boolean isTouchpad = isTouchpad(); 111 if (isMouse && isTouchpad) { 112 return R.string.trackpad_mouse_settings; 113 } else if (isMouse) { 114 return R.string.mouse_settings; 115 } else { 116 return R.string.trackpad_settings; 117 } 118 } 119 120 @SuppressLint("MissingPermission") 121 @Nullable getSelectedKeyboardLayoutLabelForUser(Context context, @UserIdInt int userId, InputDeviceIdentifier inputDeviceIdentifier)122 static String getSelectedKeyboardLayoutLabelForUser(Context context, @UserIdInt int userId, 123 InputDeviceIdentifier inputDeviceIdentifier) { 124 InputMethodManager imm = context.getSystemService(InputMethodManager.class); 125 InputManager im = context.getSystemService(InputManager.class); 126 if (imm == null || im == null) { 127 return null; 128 } 129 InputMethodInfo imeInfo = imm.getCurrentInputMethodInfoAsUser(UserHandle.of(userId)); 130 InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype(); 131 KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(im, userId, inputDeviceIdentifier, 132 imeInfo, subtype); 133 KeyboardLayoutSelectionResult result = getKeyboardLayout(im, userId, inputDeviceIdentifier, 134 imeInfo, subtype); 135 if (result != null) { 136 for (KeyboardLayout keyboardLayout : keyboardLayouts) { 137 if (keyboardLayout.getDescriptor().equals(result.getLayoutDescriptor())) { 138 return keyboardLayout.getLabel(); 139 } 140 } 141 } 142 return null; 143 } 144 145 static class KeyboardInfo { 146 CharSequence mSubtypeLabel; 147 String mLayout; 148 @LayoutSelectionCriteria int mSelectionCriteria; 149 InputMethodInfo mInputMethodInfo; 150 InputMethodSubtype mInputMethodSubtype; 151 KeyboardInfo( CharSequence subtypeLabel, String layout, @LayoutSelectionCriteria int selectionCriteria, InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype)152 KeyboardInfo( 153 CharSequence subtypeLabel, 154 String layout, 155 @LayoutSelectionCriteria int selectionCriteria, 156 InputMethodInfo inputMethodInfo, 157 InputMethodSubtype inputMethodSubtype) { 158 mSubtypeLabel = subtypeLabel; 159 mLayout = layout; 160 mSelectionCriteria = selectionCriteria; 161 mInputMethodInfo = inputMethodInfo; 162 mInputMethodSubtype = inputMethodSubtype; 163 } 164 getPrefId()165 String getPrefId() { 166 return mInputMethodInfo.getId() + "_" + mInputMethodSubtype.hashCode(); 167 } 168 getSubtypeLabel()169 CharSequence getSubtypeLabel() { 170 return mSubtypeLabel; 171 } 172 getLayout()173 String getLayout() { 174 return mLayout; 175 } 176 getLayoutSummaryText(Context context)177 String getLayoutSummaryText(Context context) { 178 if (isAutomaticSelection(mSelectionCriteria)) { 179 return context.getResources().getString(R.string.automatic_keyboard_layout_label, 180 mLayout); 181 } else if (isUserSelection(mSelectionCriteria)) { 182 return context.getResources().getString( 183 R.string.user_selected_keyboard_layout_label, mLayout); 184 } 185 return mLayout; 186 } 187 getInputMethodInfo()188 InputMethodInfo getInputMethodInfo() { 189 return mInputMethodInfo; 190 } 191 getInputMethodSubtype()192 InputMethodSubtype getInputMethodSubtype() { 193 return mInputMethodSubtype; 194 } 195 } 196 getInputDevice(InputManager im, InputDeviceIdentifier identifier)197 static InputDevice getInputDevice(InputManager im, InputDeviceIdentifier identifier) { 198 return identifier == null ? null : im.getInputDeviceByDescriptor( 199 identifier.getDescriptor()); 200 } 201 getKeyboardLayouts(InputManager inputManager, int userId, InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype)202 static KeyboardLayout[] getKeyboardLayouts(InputManager inputManager, int userId, 203 InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) { 204 return inputManager.getKeyboardLayoutListForInputDevice(identifier, userId, info, subtype); 205 } 206 207 @NonNull getKeyboardLayout(InputManager inputManager, int userId, InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype)208 static KeyboardLayoutSelectionResult getKeyboardLayout(InputManager inputManager, int userId, 209 InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) { 210 return inputManager.getKeyboardLayoutForInputDevice(identifier, userId, info, subtype); 211 } 212 isAutomaticSelection(@ayoutSelectionCriteria int criteria)213 static boolean isAutomaticSelection(@LayoutSelectionCriteria int criteria) { 214 return criteria == LAYOUT_SELECTION_CRITERIA_DEVICE 215 || criteria == LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD; 216 } 217 isUserSelection(@ayoutSelectionCriteria int criteria)218 static boolean isUserSelection(@LayoutSelectionCriteria int criteria) { 219 return criteria == LAYOUT_SELECTION_CRITERIA_USER; 220 } 221 sortKeyboardLayoutsByLabel(KeyboardLayout[] keyboardLayouts)222 static void sortKeyboardLayoutsByLabel(KeyboardLayout[] keyboardLayouts) { 223 Arrays.sort( 224 keyboardLayouts, 225 Comparator.comparing(KeyboardLayout::getLabel) 226 ); 227 } 228 } 229