1 /* 2 * Copyright 2024 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 com.android.settings.inputmethod.PhysicalKeyboardFragment.getHardKeyboards; 20 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.content.res.Configuration; 24 import android.hardware.input.InputManager; 25 import android.os.Bundle; 26 import android.view.InputDevice; 27 28 import androidx.annotation.NonNull; 29 import androidx.annotation.Nullable; 30 import androidx.preference.PreferenceScreen; 31 import androidx.recyclerview.widget.GridLayoutManager; 32 import androidx.recyclerview.widget.RecyclerView; 33 34 import com.android.internal.util.Preconditions; 35 import com.android.settings.R; 36 import com.android.settings.activityembedding.ActivityEmbeddingUtils; 37 import com.android.settings.dashboard.DashboardFragment; 38 import com.android.settings.keyboard.Flags; 39 import com.android.settings.search.BaseSearchIndexProvider; 40 import com.android.settingslib.search.SearchIndexable; 41 import com.android.settingslib.utils.ThreadUtils; 42 import com.android.settingslib.widget.LayoutPreference; 43 44 import java.util.List; 45 46 @SearchIndexable 47 public class MouseKeysMainPageFragment extends DashboardFragment 48 implements InputManager.InputDeviceListener { 49 50 private static final String TAG = "MouseKeysMainPageFragment"; 51 private static final String KEY_MOUSE_KEY_LIST = "mouse_keys_list"; 52 53 private InputManager mInputManager; 54 private LayoutPreference mMouseKeyImagesPreference; 55 @Nullable 56 private InputDevice mCurrentInputDevice; 57 58 @Override onCreate(@onNull Bundle bundle)59 public void onCreate(@NonNull Bundle bundle) { 60 super.onCreate(bundle); 61 mCurrentInputDevice = getInputDevice(); 62 final PreferenceScreen screen = getPreferenceScreen(); 63 mMouseKeyImagesPreference = screen.findPreference(KEY_MOUSE_KEY_LIST); 64 mInputManager = Preconditions.checkNotNull(getActivity() 65 .getSystemService(InputManager.class)); 66 String title = mCurrentInputDevice == null || getHardKeyboards(getContext()).size() == 1 67 ? getActivity().getString(R.string.mouse_keys) 68 : getActivity().getString(R.string.mouse_key_main_page_title, 69 mCurrentInputDevice.getName()); 70 getActivity().setTitle(title); 71 configureImagesPreference(); 72 } 73 74 @Override onResume()75 public void onResume() { 76 super.onResume(); 77 finishEarlyIfNeeded(); 78 mInputManager.registerInputDeviceListener(this, null); 79 } 80 81 @Override onPause()82 public void onPause() { 83 super.onPause(); 84 mInputManager.unregisterInputDeviceListener(this); 85 } 86 87 @Override getMetricsCategory()88 public int getMetricsCategory() { 89 return SettingsEnums.SETTINGS_PHYSICAL_KEYBOARD_MOUSE_KEYS; 90 } 91 92 @Override getPreferenceScreenResId()93 protected int getPreferenceScreenResId() { 94 return R.xml.mouse_keys_main_page; 95 } 96 97 @Override getLogTag()98 protected String getLogTag() { 99 return TAG; 100 } 101 102 @Override onInputDeviceAdded(int deviceId)103 public void onInputDeviceAdded(int deviceId) { 104 finishEarlyIfNeeded(); 105 } 106 107 @Override onInputDeviceRemoved(int deviceId)108 public void onInputDeviceRemoved(int deviceId) { 109 finishEarlyIfNeeded(); 110 } 111 112 @Override onInputDeviceChanged(int deviceId)113 public void onInputDeviceChanged(int deviceId) { 114 finishEarlyIfNeeded(); 115 } 116 finishEarlyIfNeeded()117 private void finishEarlyIfNeeded() { 118 final Context context = getContext(); 119 ThreadUtils.postOnBackgroundThread(() -> { 120 final List<PhysicalKeyboardFragment.HardKeyboardDeviceInfo> newHardKeyboards = 121 getHardKeyboards(context); 122 if (newHardKeyboards.isEmpty()) { 123 getActivity().finish(); 124 } 125 }); 126 } 127 configureImagesPreference()128 private void configureImagesPreference() { 129 final RecyclerView recyclerView = mMouseKeyImagesPreference.findViewById( 130 R.id.mouse_keys_image_recycler_list); 131 boolean isPortrait = getResources().getConfiguration().orientation 132 == Configuration.ORIENTATION_PORTRAIT; 133 boolean isTwoPaneState = ActivityEmbeddingUtils.isAlreadyEmbedded(this.getActivity()); 134 int column = isPortrait && !isTwoPaneState ? 1 : 2; 135 recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), column)); 136 recyclerView.setAdapter(new MouseKeysImageListAdapter(getActivity(), mCurrentInputDevice)); 137 } 138 139 /** 140 * Priority of picking input device: 141 * 1. internal keyboard(built-in keyboard) 142 * 2. first keyboard in the list 143 */ 144 @Nullable getInputDevice()145 private InputDevice getInputDevice() { 146 InputDevice inputDevice = null; 147 for (int deviceId : InputDevice.getDeviceIds()) { 148 final InputDevice device = InputDevice.getDevice(deviceId); 149 if (device == null || device.isVirtual() || !device.isFullKeyboard()) { 150 continue; 151 } 152 if (inputDevice == null) { 153 inputDevice = device; 154 } else if (!device.isExternal()) { 155 inputDevice = device; 156 break; 157 } 158 } 159 return inputDevice; 160 } 161 162 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 163 new BaseSearchIndexProvider(R.xml.mouse_keys_main_page) { 164 @Override 165 protected boolean isPageSearchEnabled(Context context) { 166 return Flags.keyboardAndTouchpadA11yNewPageEnabled() 167 && !getHardKeyboards(context).isEmpty(); 168 } 169 }; 170 } 171