• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.input;
18 
19 import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
20 import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
21 import static android.view.flags.Flags.enableVectorCursorA11ySettings;
22 
23 import static com.android.input.flags.Flags.rateLimitUserActivityPokeInDispatcher;
24 
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.database.ContentObserver;
30 import android.hardware.input.InputSettings;
31 import android.net.Uri;
32 import android.os.Handler;
33 import android.os.UserHandle;
34 import android.provider.DeviceConfig;
35 import android.provider.Settings;
36 import android.util.Log;
37 import android.view.ViewConfiguration;
38 
39 import java.util.Map;
40 import java.util.function.Consumer;
41 
42 /** Observes settings changes and propagates them to the native side. */
43 class InputSettingsObserver extends ContentObserver {
44     static final String TAG = "InputManager";
45 
46     /** Feature flag name for the deep press feature */
47     private static final String DEEP_PRESS_ENABLED = "deep_press_enabled";
48 
49     private final Context mContext;
50     private final Handler mHandler;
51     private final InputManagerService mService;
52     private final NativeInputManagerService mNative;
53     private final Map<Uri, Consumer<String /* reason*/>> mObservers;
54 
InputSettingsObserver(Context context, Handler handler, InputManagerService service, NativeInputManagerService nativeIms)55     InputSettingsObserver(Context context, Handler handler, InputManagerService service,
56             NativeInputManagerService nativeIms) {
57         super(handler);
58         mContext = context;
59         mHandler = handler;
60         mService = service;
61         mNative = nativeIms;
62         mObservers = Map.ofEntries(
63                 Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SPEED),
64                         (reason) -> updateMousePointerSpeed()),
65                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_POINTER_SPEED),
66                         (reason) -> updateTouchpadPointerSpeed()),
67                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_NATURAL_SCROLLING),
68                         (reason) -> updateTouchpadNaturalScrollingEnabled()),
69                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_TAP_TO_CLICK),
70                         (reason) -> updateTouchpadTapToClickEnabled()),
71                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_TAP_DRAGGING),
72                         (reason) -> updateTouchpadTapDraggingEnabled()),
73                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE),
74                         (reason) -> updateTouchpadRightClickZoneEnabled()),
75                 Map.entry(Settings.System.getUriFor(Settings.System.SHOW_TOUCHES),
76                         (reason) -> updateShowTouches()),
77                 Map.entry(Settings.System.getUriFor(Settings.System.POINTER_LOCATION),
78                         (reason) -> updatePointerLocation()),
79                 Map.entry(
80                         Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON),
81                         (reason) -> updateAccessibilityLargePointer()),
82                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.LONG_PRESS_TIMEOUT),
83                         (reason) -> updateLongPressTimeout(reason)),
84                 Map.entry(
85                         Settings.Global.getUriFor(
86                                 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH),
87                         (reason) -> updateMaximumObscuringOpacityForTouch()),
88                 Map.entry(Settings.System.getUriFor(Settings.System.SHOW_KEY_PRESSES),
89                         (reason) -> updateShowKeyPresses()),
90                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_TIMEOUT_MS),
91                         (reason) -> updateKeyRepeatInfo()),
92                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_DELAY_MS),
93                         (reason) -> updateKeyRepeatInfo()),
94                 Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT),
95                         (reason) -> updateShowRotaryInput()),
96                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS),
97                         (reason) -> updateAccessibilityBounceKeys()),
98                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SLOW_KEYS),
99                         (reason) -> updateAccessibilitySlowKeys()),
100                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS),
101                         (reason) -> updateAccessibilityStickyKeys()),
102                 Map.entry(Settings.Secure.getUriFor(Settings.Secure.STYLUS_POINTER_ICON_ENABLED),
103                         (reason) -> updateStylusPointerIconEnabled()),
104                 Map.entry(Settings.System.getUriFor(Settings.System.POINTER_FILL_STYLE),
105                         (reason) -> updatePointerFillStyleFromSettings()),
106                 Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SCALE),
107                         (reason) -> updatePointerScaleFromSettings()));
108     }
109 
110     /**
111      * Registers observers for input-related settings and updates the input subsystem with their
112      * current values.
113      */
registerAndUpdate()114     public void registerAndUpdate() {
115         for (Uri uri : mObservers.keySet()) {
116             mContext.getContentResolver().registerContentObserver(
117                     uri, true /* notifyForDescendants */, this, UserHandle.USER_ALL);
118         }
119 
120         mContext.registerReceiver(new BroadcastReceiver() {
121             @Override
122             public void onReceive(Context context, Intent intent) {
123                 for (Consumer<String> observer : mObservers.values()) {
124                     observer.accept("user switched");
125                 }
126             }
127         }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
128 
129         for (Consumer<String> observer : mObservers.values()) {
130             observer.accept("just booted");
131         }
132 
133         configureUserActivityPokeInterval();
134     }
135 
136     @Override
onChange(boolean selfChange, Uri uri)137     public void onChange(boolean selfChange, Uri uri) {
138         mObservers.get(uri).accept("setting changed");
139     }
140 
getBoolean(String settingName, boolean defaultValue)141     private boolean getBoolean(String settingName, boolean defaultValue) {
142         final int setting = Settings.System.getIntForUser(mContext.getContentResolver(),
143                 settingName, defaultValue ? 1 : 0, UserHandle.USER_CURRENT);
144         return setting != 0;
145     }
146 
constrainPointerSpeedValue(int speed)147     private int constrainPointerSpeedValue(int speed) {
148         return Math.min(Math.max(speed, InputSettings.MIN_POINTER_SPEED),
149                 InputSettings.MAX_POINTER_SPEED);
150     }
151 
updateMousePointerSpeed()152     private void updateMousePointerSpeed() {
153         int speed = Settings.System.getIntForUser(mContext.getContentResolver(),
154                 Settings.System.POINTER_SPEED, InputSettings.DEFAULT_POINTER_SPEED,
155                 UserHandle.USER_CURRENT);
156         mNative.setPointerSpeed(constrainPointerSpeedValue(speed));
157     }
158 
updateTouchpadPointerSpeed()159     private void updateTouchpadPointerSpeed() {
160         mNative.setTouchpadPointerSpeed(
161                 constrainPointerSpeedValue(InputSettings.getTouchpadPointerSpeed(mContext)));
162     }
163 
updateTouchpadNaturalScrollingEnabled()164     private void updateTouchpadNaturalScrollingEnabled() {
165         mNative.setTouchpadNaturalScrollingEnabled(
166                 InputSettings.useTouchpadNaturalScrolling(mContext));
167     }
168 
updateTouchpadTapToClickEnabled()169     private void updateTouchpadTapToClickEnabled() {
170         mNative.setTouchpadTapToClickEnabled(InputSettings.useTouchpadTapToClick(mContext));
171     }
172 
updateTouchpadTapDraggingEnabled()173     private void updateTouchpadTapDraggingEnabled() {
174         mNative.setTouchpadTapDraggingEnabled(InputSettings.useTouchpadTapDragging(mContext));
175     }
176 
updateTouchpadRightClickZoneEnabled()177     private void updateTouchpadRightClickZoneEnabled() {
178         mNative.setTouchpadRightClickZoneEnabled(InputSettings.useTouchpadRightClickZone(mContext));
179     }
180 
updateShowTouches()181     private void updateShowTouches() {
182         mNative.setShowTouches(getBoolean(Settings.System.SHOW_TOUCHES, false));
183     }
184 
updatePointerLocation()185     private void updatePointerLocation() {
186         mService.updatePointerLocationEnabled(
187                 getBoolean(Settings.System.POINTER_LOCATION, false));
188     }
189 
updateShowKeyPresses()190     private void updateShowKeyPresses() {
191         mService.updateShowKeyPresses(getBoolean(Settings.System.SHOW_KEY_PRESSES, false));
192     }
193 
updateShowRotaryInput()194     private void updateShowRotaryInput() {
195         mService.updateShowRotaryInput(getBoolean(Settings.System.SHOW_ROTARY_INPUT, false));
196     }
197 
updateAccessibilityLargePointer()198     private void updateAccessibilityLargePointer() {
199         final int accessibilityConfig = Settings.Secure.getIntForUser(
200                 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
201                 0, UserHandle.USER_CURRENT);
202         mService.setUseLargePointerIcons(accessibilityConfig == 1);
203     }
204 
updateLongPressTimeout(String reason)205     private void updateLongPressTimeout(String reason) {
206         // Not using ViewConfiguration.getLongPressTimeout here because it may return a stale value.
207         final int longPressTimeoutMs = Settings.Secure.getIntForUser(mContext.getContentResolver(),
208                 Settings.Secure.LONG_PRESS_TIMEOUT, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT,
209                 UserHandle.USER_CURRENT);
210 
211         final boolean featureEnabledFlag =
212                 DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
213                         DEEP_PRESS_ENABLED, true /* default */);
214         final boolean enabled =
215                 featureEnabledFlag
216                         && longPressTimeoutMs <= ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
217         Log.i(TAG, (enabled ? "Enabling" : "Disabling") + " motion classifier because " + reason
218                 + ": feature " + (featureEnabledFlag ? "enabled" : "disabled")
219                 + ", long press timeout = " + longPressTimeoutMs + " ms");
220         mNative.setMotionClassifierEnabled(enabled);
221     }
222 
updateKeyRepeatInfo()223     private void updateKeyRepeatInfo() {
224         // Use ViewConfiguration getters only as fallbacks because they may return stale values.
225         final int timeoutMs = Settings.Secure.getIntForUser(mContext.getContentResolver(),
226                 Settings.Secure.KEY_REPEAT_TIMEOUT_MS, ViewConfiguration.getKeyRepeatTimeout(),
227                 UserHandle.USER_CURRENT);
228         final int delayMs = Settings.Secure.getIntForUser(mContext.getContentResolver(),
229                 Settings.Secure.KEY_REPEAT_DELAY_MS, ViewConfiguration.getKeyRepeatDelay(),
230                 UserHandle.USER_CURRENT);
231         mNative.setKeyRepeatConfiguration(timeoutMs, delayMs);
232     }
233 
updateMaximumObscuringOpacityForTouch()234     private void updateMaximumObscuringOpacityForTouch() {
235         final float opacity = InputSettings.getMaximumObscuringOpacityForTouch(mContext);
236         if (opacity < 0 || opacity > 1) {
237             Log.e(TAG, "Invalid maximum obscuring opacity " + opacity
238                     + ", it should be >= 0 and <= 1, rejecting update.");
239             return;
240         }
241         mNative.setMaximumObscuringOpacityForTouch(opacity);
242     }
243 
updateAccessibilityBounceKeys()244     private void updateAccessibilityBounceKeys() {
245         mService.setAccessibilityBounceKeysThreshold(
246                 InputSettings.getAccessibilityBounceKeysThreshold(mContext));
247     }
248 
updateAccessibilitySlowKeys()249     private void updateAccessibilitySlowKeys() {
250         mService.setAccessibilitySlowKeysThreshold(
251                 InputSettings.getAccessibilitySlowKeysThreshold(mContext));
252     }
253 
updateAccessibilityStickyKeys()254     private void updateAccessibilityStickyKeys() {
255         mService.setAccessibilityStickyKeysEnabled(
256                 InputSettings.isAccessibilityStickyKeysEnabled(mContext));
257     }
258 
configureUserActivityPokeInterval()259     private void configureUserActivityPokeInterval() {
260         if (rateLimitUserActivityPokeInDispatcher()) {
261             final int intervalMillis = mContext.getResources().getInteger(
262                     com.android.internal.R.integer.config_minMillisBetweenInputUserActivityEvents);
263             Log.i(TAG, "Setting user activity interval (ms) of " + intervalMillis);
264             mNative.setMinTimeBetweenUserActivityPokes(intervalMillis);
265         }
266     }
267 
updateStylusPointerIconEnabled()268     private void updateStylusPointerIconEnabled() {
269         mNative.setStylusPointerIconEnabled(
270                 InputSettings.isStylusPointerIconEnabled(mContext, true /* forceReloadSetting */));
271     }
272 
updatePointerFillStyleFromSettings()273     private void updatePointerFillStyleFromSettings() {
274         if (!enableVectorCursorA11ySettings()) {
275             return;
276         }
277         final int pointerFillStyle = Settings.System.getIntForUser(
278                 mContext.getContentResolver(), Settings.System.POINTER_FILL_STYLE,
279                 POINTER_ICON_VECTOR_STYLE_FILL_BLACK,
280                 UserHandle.USER_CURRENT);
281         mService.setPointerFillStyle(pointerFillStyle);
282     }
283 
updatePointerScaleFromSettings()284     private void updatePointerScaleFromSettings() {
285         if (!enableVectorCursorA11ySettings()) {
286             return;
287         }
288         final float pointerScale = Settings.System.getFloatForUser(mContext.getContentResolver(),
289                 Settings.System.POINTER_SCALE, DEFAULT_POINTER_SCALE,
290                 UserHandle.USER_CURRENT);
291         mService.setPointerScale(pointerScale);
292     }
293 }
294