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 android.hardware.input; 18 19 import android.Manifest; 20 import android.annotation.FloatRange; 21 import android.annotation.NonNull; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SuppressLint; 24 import android.annotation.TestApi; 25 import android.content.Context; 26 import android.os.UserHandle; 27 import android.provider.Settings; 28 import android.sysprop.InputProperties; 29 30 /** 31 * InputSettings encapsulates reading and writing settings related to input 32 * 33 * @hide 34 */ 35 @TestApi 36 public class InputSettings { 37 /** 38 * Pointer Speed: The minimum (slowest) pointer speed (-7). 39 * @hide 40 */ 41 public static final int MIN_POINTER_SPEED = -7; 42 43 /** 44 * Pointer Speed: The maximum (fastest) pointer speed (7). 45 * @hide 46 */ 47 public static final int MAX_POINTER_SPEED = 7; 48 49 /** 50 * Pointer Speed: The default pointer speed (0). 51 * @hide 52 */ 53 public static final int DEFAULT_POINTER_SPEED = 0; 54 55 /** 56 * The maximum allowed obscuring opacity by UID to propagate touches (0 <= x <= 1). 57 * @hide 58 */ 59 public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f; 60 61 InputSettings()62 private InputSettings() { 63 } 64 65 /** 66 * Gets the mouse pointer speed. 67 * <p> 68 * Only returns the permanent mouse pointer speed. Ignores any temporary pointer 69 * speed set by {@link InputManager#tryPointerSpeed}. 70 * </p> 71 * 72 * @param context The application context. 73 * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 74 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 75 * 76 * @hide 77 */ 78 @SuppressLint("NonUserGetterCalled") getPointerSpeed(Context context)79 public static int getPointerSpeed(Context context) { 80 return Settings.System.getInt(context.getContentResolver(), 81 Settings.System.POINTER_SPEED, DEFAULT_POINTER_SPEED); 82 } 83 84 /** 85 * Sets the mouse pointer speed. 86 * <p> 87 * Requires {@link android.Manifest.permission#WRITE_SETTINGS}. 88 * </p> 89 * 90 * @param context The application context. 91 * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 92 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 93 * 94 * @hide 95 */ 96 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setPointerSpeed(Context context, int speed)97 public static void setPointerSpeed(Context context, int speed) { 98 if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) { 99 throw new IllegalArgumentException("speed out of range"); 100 } 101 102 Settings.System.putInt(context.getContentResolver(), 103 Settings.System.POINTER_SPEED, speed); 104 } 105 106 /** 107 * Returns the maximum allowed obscuring opacity per UID to propagate touches. 108 * 109 * <p>For certain window types (e.g. {@link LayoutParams#TYPE_APPLICATION_OVERLAY}), 110 * the decision of honoring {@link LayoutParams#FLAG_NOT_TOUCHABLE} or not depends on 111 * the combined obscuring opacity of the windows above the touch-consuming window, per 112 * UID. Check documentation of {@link LayoutParams#FLAG_NOT_TOUCHABLE} for more details. 113 * 114 * <p>The value returned is between 0 (inclusive) and 1 (inclusive). 115 * 116 * @see LayoutParams#FLAG_NOT_TOUCHABLE 117 * 118 * @hide 119 */ 120 @FloatRange(from = 0, to = 1) getMaximumObscuringOpacityForTouch(Context context)121 public static float getMaximumObscuringOpacityForTouch(Context context) { 122 return Settings.Global.getFloat(context.getContentResolver(), 123 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, 124 DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH); 125 } 126 127 /** 128 * Sets the maximum allowed obscuring opacity by UID to propagate touches. 129 * 130 * <p>For certain window types (e.g. SAWs), the decision of honoring {@link LayoutParams 131 * #FLAG_NOT_TOUCHABLE} or not depends on the combined obscuring opacity of the windows 132 * above the touch-consuming window. 133 * 134 * <p>For a certain UID: 135 * <ul> 136 * <li>If it's the same as the UID of the touch-consuming window, allow it to propagate 137 * the touch. 138 * <li>Otherwise take all its windows of eligible window types above the touch-consuming 139 * window, compute their combined obscuring opacity considering that {@code 140 * opacity(A, B) = 1 - (1 - opacity(A))*(1 - opacity(B))}. If the computed value is 141 * less than or equal to this setting and there are no other windows preventing the 142 * touch, allow the UID to propagate the touch. 143 * </ul> 144 * 145 * <p>This value should be between 0 (inclusive) and 1 (inclusive). 146 * 147 * @see #getMaximumObscuringOpacityForTouch(Context) 148 * 149 * @hide 150 */ 151 @TestApi 152 @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) setMaximumObscuringOpacityForTouch( @onNull Context context, @FloatRange(from = 0, to = 1) float opacity)153 public static void setMaximumObscuringOpacityForTouch( 154 @NonNull Context context, 155 @FloatRange(from = 0, to = 1) float opacity) { 156 if (opacity < 0 || opacity > 1) { 157 throw new IllegalArgumentException( 158 "Maximum obscuring opacity for touch should be >= 0 and <= 1"); 159 } 160 Settings.Global.putFloat(context.getContentResolver(), 161 Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH, opacity); 162 } 163 164 /** 165 * Whether stylus has ever been used on device (false by default). 166 * @hide 167 */ isStylusEverUsed(@onNull Context context)168 public static boolean isStylusEverUsed(@NonNull Context context) { 169 return Settings.Global.getInt(context.getContentResolver(), 170 Settings.Global.STYLUS_EVER_USED, 0) == 1; 171 } 172 173 /** 174 * Set whether stylus has ever been used on device. 175 * Should only ever be set to true once after stylus first usage. 176 * @hide 177 */ 178 @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) setStylusEverUsed(@onNull Context context, boolean stylusEverUsed)179 public static void setStylusEverUsed(@NonNull Context context, boolean stylusEverUsed) { 180 Settings.Global.putInt(context.getContentResolver(), 181 Settings.Global.STYLUS_EVER_USED, stylusEverUsed ? 1 : 0); 182 } 183 184 185 /** 186 * Gets the touchpad pointer speed. 187 * 188 * The returned value only applies to gesture-compatible touchpads. 189 * 190 * @param context The application context. 191 * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 192 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 193 * 194 * @hide 195 */ getTouchpadPointerSpeed(@onNull Context context)196 public static int getTouchpadPointerSpeed(@NonNull Context context) { 197 return Settings.System.getIntForUser(context.getContentResolver(), 198 Settings.System.TOUCHPAD_POINTER_SPEED, DEFAULT_POINTER_SPEED, 199 UserHandle.USER_CURRENT); 200 } 201 202 /** 203 * Sets the touchpad pointer speed, and saves it in the settings. 204 * 205 * The new speed will only apply to gesture-compatible touchpads. 206 * 207 * @param context The application context. 208 * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and 209 * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}. 210 * 211 * @hide 212 */ 213 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setTouchpadPointerSpeed(@onNull Context context, int speed)214 public static void setTouchpadPointerSpeed(@NonNull Context context, int speed) { 215 if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) { 216 throw new IllegalArgumentException("speed out of range"); 217 } 218 219 Settings.System.putIntForUser(context.getContentResolver(), 220 Settings.System.TOUCHPAD_POINTER_SPEED, speed, UserHandle.USER_CURRENT); 221 } 222 223 /** 224 * Returns true if moving two fingers upwards on the touchpad should 225 * scroll down, which is known as natural scrolling. 226 * 227 * The returned value only applies to gesture-compatible touchpads. 228 * 229 * @param context The application context. 230 * @return Whether the touchpad should use natural scrolling. 231 * 232 * @hide 233 */ useTouchpadNaturalScrolling(@onNull Context context)234 public static boolean useTouchpadNaturalScrolling(@NonNull Context context) { 235 return Settings.System.getIntForUser(context.getContentResolver(), 236 Settings.System.TOUCHPAD_NATURAL_SCROLLING, 1, UserHandle.USER_CURRENT) == 1; 237 } 238 239 /** 240 * Sets the natural scroll behavior for the touchpad. 241 * 242 * If natural scrolling is enabled, moving two fingers upwards on the 243 * touchpad will scroll down. 244 * 245 * @param context The application context. 246 * @param enabled Will enable natural scroll if true, disable it if false 247 * 248 * @hide 249 */ 250 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setTouchpadNaturalScrolling(@onNull Context context, boolean enabled)251 public static void setTouchpadNaturalScrolling(@NonNull Context context, boolean enabled) { 252 Settings.System.putIntForUser(context.getContentResolver(), 253 Settings.System.TOUCHPAD_NATURAL_SCROLLING, enabled ? 1 : 0, 254 UserHandle.USER_CURRENT); 255 } 256 257 /** 258 * Returns true if the touchpad should use tap to click. 259 * 260 * The returned value only applies to gesture-compatible touchpads. 261 * 262 * @param context The application context. 263 * @return Whether the touchpad should use tap to click. 264 * 265 * @hide 266 */ useTouchpadTapToClick(@onNull Context context)267 public static boolean useTouchpadTapToClick(@NonNull Context context) { 268 return Settings.System.getIntForUser(context.getContentResolver(), 269 Settings.System.TOUCHPAD_TAP_TO_CLICK, 1, UserHandle.USER_CURRENT) == 1; 270 } 271 272 /** 273 * Sets the tap to click behavior for the touchpad. 274 * 275 * The new behavior is only applied to gesture-compatible touchpads. 276 * 277 * @param context The application context. 278 * @param enabled Will enable tap to click if true, disable it if false 279 * 280 * @hide 281 */ 282 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setTouchpadTapToClick(@onNull Context context, boolean enabled)283 public static void setTouchpadTapToClick(@NonNull Context context, boolean enabled) { 284 Settings.System.putIntForUser(context.getContentResolver(), 285 Settings.System.TOUCHPAD_TAP_TO_CLICK, enabled ? 1 : 0, 286 UserHandle.USER_CURRENT); 287 } 288 289 /** 290 * Returns true if the touchpad should use the right click zone. 291 * 292 * The returned value only applies to gesture-compatible touchpads. 293 * 294 * @param context The application context. 295 * @return Whether the touchpad should use the right click zone. 296 * 297 * @hide 298 */ useTouchpadRightClickZone(@onNull Context context)299 public static boolean useTouchpadRightClickZone(@NonNull Context context) { 300 return Settings.System.getIntForUser(context.getContentResolver(), 301 Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, 0, UserHandle.USER_CURRENT) == 1; 302 } 303 304 /** 305 * Sets the right click zone behavior for the touchpad. 306 * 307 * The new behavior is only applied to gesture-compatible touchpads. 308 * 309 * @param context The application context. 310 * @param enabled Will enable the right click zone if true, disable it if false 311 * 312 * @hide 313 */ 314 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setTouchpadRightClickZone(@onNull Context context, boolean enabled)315 public static void setTouchpadRightClickZone(@NonNull Context context, boolean enabled) { 316 Settings.System.putIntForUser(context.getContentResolver(), 317 Settings.System.TOUCHPAD_RIGHT_CLICK_ZONE, enabled ? 1 : 0, 318 UserHandle.USER_CURRENT); 319 } 320 321 /** 322 * Whether a pointer icon will be shown over the location of a 323 * stylus pointer. 324 * @hide 325 */ isStylusPointerIconEnabled(@onNull Context context)326 public static boolean isStylusPointerIconEnabled(@NonNull Context context) { 327 return context.getResources() 328 .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon) 329 || InputProperties.force_enable_stylus_pointer_icon().orElse(false); 330 } 331 } 332