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.ContentResolver; 23 import android.content.Context; 24 import android.database.ContentObserver; 25 import android.hardware.input.InputManager; 26 import android.hardware.input.InputSettings; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.UserHandle; 31 import android.provider.Settings; 32 33 import androidx.annotation.NonNull; 34 import androidx.annotation.Nullable; 35 36 import com.android.internal.util.Preconditions; 37 import com.android.settings.R; 38 import com.android.settings.dashboard.DashboardFragment; 39 import com.android.settings.keyboard.Flags; 40 import com.android.settings.search.BaseSearchIndexProvider; 41 import com.android.settings.widget.LabeledSeekBarPreference; 42 import com.android.settingslib.utils.ThreadUtils; 43 44 import java.util.List; 45 46 public class KeyboardRepeatKeysMainFragment extends DashboardFragment 47 implements InputManager.InputDeviceListener { 48 private static final String TAG = "RepeatKeysMainFragment"; 49 private static final String TIME_OUT_KEY = "repeat_keys_timeout_preference"; 50 private static final String DELAY_KEY = "repeat_keys_delay_preference"; 51 52 private final Uri mRepeatKeyUri = Settings.Secure.getUriFor( 53 Settings.Secure.KEY_REPEAT_ENABLED); 54 private final ContentObserver mContentObserver = new ContentObserver(new Handler(true)) { 55 @Override 56 public void onChange(boolean selfChange, Uri uri) { 57 if (mRepeatKeyUri.equals(uri)) { 58 updatePreferencesState(); 59 } 60 } 61 }; 62 private InputManager mInputManager; 63 private ContentResolver mContentResolver; 64 @Nullable 65 private LabeledSeekBarPreference mRepeatTimeoutPreference; 66 @Nullable 67 private LabeledSeekBarPreference mRepeatDelayPreference; 68 69 @Override getMetricsCategory()70 public int getMetricsCategory() { 71 return SettingsEnums.PHYSICAL_KEYBOARD_REPEAT_KEYS; 72 } 73 74 @Override onAttach(@onNull Context context)75 public void onAttach(@NonNull Context context) { 76 super.onAttach(context); 77 mInputManager = Preconditions.checkNotNull(getActivity() 78 .getSystemService(InputManager.class)); 79 mContentResolver = context.getContentResolver(); 80 } 81 82 @Override onCreatePreferences(Bundle bundle, String s)83 public void onCreatePreferences(Bundle bundle, String s) { 84 super.onCreatePreferences(bundle, s); 85 mRepeatTimeoutPreference = findPreference(TIME_OUT_KEY); 86 mRepeatDelayPreference = findPreference(DELAY_KEY); 87 updatePreferencesState(); 88 } 89 90 @Override onResume()91 public void onResume() { 92 super.onResume(); 93 finishEarlyIfNeeded(); 94 mInputManager.registerInputDeviceListener(this, null); 95 registerSettingsObserver(); 96 } 97 98 @Override onPause()99 public void onPause() { 100 super.onPause(); 101 mInputManager.unregisterInputDeviceListener(this); 102 unregisterSettingsObserver(); 103 } 104 105 @Override getLogTag()106 protected String getLogTag() { 107 return TAG; 108 } 109 110 @Override getPreferenceScreenResId()111 protected int getPreferenceScreenResId() { 112 return R.xml.repeat_key_main_page; 113 } 114 updatePreferencesState()115 private void updatePreferencesState() { 116 boolean isRepeatKeyEnabled = InputSettings.isRepeatKeysEnabled(getContext()); 117 if (mRepeatTimeoutPreference != null && mRepeatDelayPreference != null) { 118 mRepeatTimeoutPreference.setEnabled(isRepeatKeyEnabled); 119 mRepeatDelayPreference.setEnabled(isRepeatKeyEnabled); 120 } 121 } 122 registerSettingsObserver()123 private void registerSettingsObserver() { 124 unregisterSettingsObserver(); 125 mContentResolver.registerContentObserver( 126 mRepeatKeyUri, 127 false, 128 mContentObserver, 129 UserHandle.myUserId()); 130 } 131 unregisterSettingsObserver()132 private void unregisterSettingsObserver() { 133 mContentResolver.unregisterContentObserver(mContentObserver); 134 } 135 136 @Override onInputDeviceAdded(int deviceId)137 public void onInputDeviceAdded(int deviceId) { 138 finishEarlyIfNeeded(); 139 } 140 141 @Override onInputDeviceRemoved(int deviceId)142 public void onInputDeviceRemoved(int deviceId) { 143 finishEarlyIfNeeded(); 144 } 145 146 @Override onInputDeviceChanged(int deviceId)147 public void onInputDeviceChanged(int deviceId) { 148 finishEarlyIfNeeded(); 149 } 150 finishEarlyIfNeeded()151 private void finishEarlyIfNeeded() { 152 final Context context = getContext(); 153 ThreadUtils.postOnBackgroundThread(() -> { 154 final List<PhysicalKeyboardFragment.HardKeyboardDeviceInfo> newHardKeyboards = 155 getHardKeyboards(context); 156 if (newHardKeyboards.isEmpty()) { 157 getActivity().finish(); 158 } 159 }); 160 } 161 162 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 163 new BaseSearchIndexProvider(R.xml.repeat_key_main_page) { 164 @Override 165 protected boolean isPageSearchEnabled(Context context) { 166 return Flags.keyboardAndTouchpadA11yNewPageEnabled() 167 && !getHardKeyboards(context).isEmpty(); 168 } 169 }; 170 } 171