1 /* 2 * Copyright (C) 2011 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 androidx.core.view.accessibility; 18 19 import android.accessibilityservice.AccessibilityServiceInfo; 20 import android.os.Build; 21 import android.view.accessibility.AccessibilityManager; 22 23 import androidx.annotation.RequiresApi; 24 25 import org.jspecify.annotations.NonNull; 26 27 import java.util.List; 28 29 /** 30 * Helper for accessing features in {@link AccessibilityManager}. 31 */ 32 public final class AccessibilityManagerCompat { 33 /** 34 * Registers an {@link AccessibilityManager.AccessibilityStateChangeListener} for changes in 35 * the global accessibility state of the system. 36 * 37 * @param manager The accessibility manager. 38 * @param listener The listener. 39 * @return True if successfully registered. 40 * 41 * @deprecated Use {@link AccessibilityManager#addAccessibilityStateChangeListener( 42 * AccessibilityManager.AccessibilityStateChangeListener)} directly. 43 */ 44 @SuppressWarnings("deprecation") 45 @Deprecated addAccessibilityStateChangeListener(AccessibilityManager manager, AccessibilityStateChangeListener listener)46 public static boolean addAccessibilityStateChangeListener(AccessibilityManager manager, 47 AccessibilityStateChangeListener listener) { 48 if (listener == null) { 49 return false; 50 } 51 return manager.addAccessibilityStateChangeListener( 52 new AccessibilityStateChangeListenerWrapper(listener)); 53 } 54 55 /** 56 * Unregisters an {@link AccessibilityManager.AccessibilityStateChangeListener}. 57 * 58 * @param manager The accessibility manager. 59 * @param listener The listener. 60 * @return True if successfully unregistered. 61 * 62 * @deprecated Use {@link AccessibilityManager#removeAccessibilityStateChangeListener( 63 * AccessibilityManager.AccessibilityStateChangeListener)} directly. 64 */ 65 @SuppressWarnings("deprecation") 66 @Deprecated removeAccessibilityStateChangeListener(AccessibilityManager manager, AccessibilityStateChangeListener listener)67 public static boolean removeAccessibilityStateChangeListener(AccessibilityManager manager, 68 AccessibilityStateChangeListener listener) { 69 if (listener == null) { 70 return false; 71 } 72 return manager.removeAccessibilityStateChangeListener( 73 new AccessibilityStateChangeListenerWrapper(listener)); 74 } 75 76 @SuppressWarnings("deprecation") 77 private static class AccessibilityStateChangeListenerWrapper 78 implements AccessibilityManager.AccessibilityStateChangeListener { 79 AccessibilityStateChangeListener mListener; 80 AccessibilityStateChangeListenerWrapper( @onNull AccessibilityStateChangeListener listener)81 AccessibilityStateChangeListenerWrapper( 82 @NonNull AccessibilityStateChangeListener listener) { 83 mListener = listener; 84 } 85 86 @Override hashCode()87 public int hashCode() { 88 return mListener.hashCode(); 89 } 90 91 @Override equals(Object o)92 public boolean equals(Object o) { 93 if (this == o) { 94 return true; 95 } 96 if (!(o instanceof AccessibilityStateChangeListenerWrapper)) { 97 return false; 98 } 99 AccessibilityStateChangeListenerWrapper other = 100 (AccessibilityStateChangeListenerWrapper) o; 101 return mListener.equals(other.mListener); 102 } 103 104 @Override onAccessibilityStateChanged(boolean enabled)105 public void onAccessibilityStateChanged(boolean enabled) { 106 mListener.onAccessibilityStateChanged(enabled); 107 } 108 } 109 110 /** 111 * Returns the {@link AccessibilityServiceInfo}s of the installed accessibility services. 112 * 113 * @param manager The accessibility manager. 114 * @return An unmodifiable list with {@link AccessibilityServiceInfo}s. 115 * 116 * @deprecated Use {@link AccessibilityManager#getInstalledAccessibilityServiceList()} directly. 117 */ 118 @androidx.annotation.ReplaceWith(expression = "manager.getInstalledAccessibilityServiceList()") 119 @Deprecated getInstalledAccessibilityServiceList( AccessibilityManager manager)120 public static List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList( 121 AccessibilityManager manager) { 122 return manager.getInstalledAccessibilityServiceList(); 123 } 124 125 /** 126 * Returns the {@link AccessibilityServiceInfo}s of the enabled accessibility services 127 * for a given feedback type. 128 * 129 * @param manager The accessibility manager. 130 * @param feedbackTypeFlags The feedback type flags. 131 * @return An unmodifiable list with {@link AccessibilityServiceInfo}s. 132 * 133 * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE 134 * @see AccessibilityServiceInfo#FEEDBACK_GENERIC 135 * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC 136 * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN 137 * @see AccessibilityServiceInfo#FEEDBACK_VISUAL 138 * 139 * @deprecated Use {@link AccessibilityManager#getEnabledAccessibilityServiceList(int)} 140 * directly. 141 */ 142 @androidx.annotation.ReplaceWith(expression = "manager.getEnabledAccessibilityServiceList(feedbackTypeFlags)") 143 @Deprecated getEnabledAccessibilityServiceList( AccessibilityManager manager, int feedbackTypeFlags)144 public static List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList( 145 AccessibilityManager manager, int feedbackTypeFlags) { 146 return manager.getEnabledAccessibilityServiceList(feedbackTypeFlags); 147 } 148 149 /** 150 * Returns if the touch exploration in the system is enabled. 151 * 152 * @param manager The accessibility manager. 153 * @return True if touch exploration is enabled, false otherwise. 154 * 155 * @deprecated Use {@link AccessibilityManager#isTouchExplorationEnabled()} directly. 156 */ 157 @androidx.annotation.ReplaceWith(expression = "manager.isTouchExplorationEnabled()") 158 @Deprecated isTouchExplorationEnabled(AccessibilityManager manager)159 public static boolean isTouchExplorationEnabled(AccessibilityManager manager) { 160 return manager.isTouchExplorationEnabled(); 161 } 162 163 /** 164 * Registers a {@link TouchExplorationStateChangeListener} for changes in 165 * the global touch exploration state of the system. 166 * 167 * @param manager AccessibilityManager for which to add the listener. 168 * @param listener The listener. 169 * @return True if successfully registered. 170 * @deprecated Call {@link AccessibilityManager#addTouchExplorationStateChangeListener(AccessibilityManager.TouchExplorationStateChangeListener)} directly. 171 */ 172 @Deprecated 173 @androidx.annotation.ReplaceWith(expression = "manager.addTouchExplorationStateChangeListener(listener)") addTouchExplorationStateChangeListener( @onNull AccessibilityManager manager, @NonNull TouchExplorationStateChangeListener listener)174 public static boolean addTouchExplorationStateChangeListener( 175 @NonNull AccessibilityManager manager, 176 @NonNull TouchExplorationStateChangeListener listener) { 177 return manager.addTouchExplorationStateChangeListener( 178 new TouchExplorationStateChangeListenerWrapper(listener)); 179 } 180 181 /** 182 * Unregisters a {@link TouchExplorationStateChangeListener}. 183 * 184 * @param manager AccessibilityManager for which to remove the listener. 185 * @param listener The listener. 186 * @return True if successfully unregistered. 187 * @deprecated Call {@link AccessibilityManager#removeTouchExplorationStateChangeListener(AccessibilityManager.TouchExplorationStateChangeListener)} directly. 188 */ 189 @Deprecated 190 @androidx.annotation.ReplaceWith(expression = "manager.removeTouchExplorationStateChangeListener(listener)") removeTouchExplorationStateChangeListener( @onNull AccessibilityManager manager, @NonNull TouchExplorationStateChangeListener listener)191 public static boolean removeTouchExplorationStateChangeListener( 192 @NonNull AccessibilityManager manager, 193 @NonNull TouchExplorationStateChangeListener listener) { 194 return manager.removeTouchExplorationStateChangeListener( 195 new TouchExplorationStateChangeListenerWrapper(listener)); 196 } 197 198 199 /** 200 * Whether the current accessibility request comes from an 201 * {@link android.accessibilityservice.AccessibilityService} with the 202 * {@link AccessibilityServiceInfo#isAccessibilityTool} 203 * property set to true. 204 * 205 * <p> 206 * You can use this method inside {@link android.view.accessibility.AccessibilityNodeProvider} 207 * to decide how to populate your nodes. 208 * </p> 209 * 210 * <p> 211 * <strong>Note:</strong> The return value is valid only when an 212 * {@link android.view.accessibility.AccessibilityNodeInfo} request is in progress, can 213 * change from one request to another, and has no meaning when a request is not in progress. 214 * </p> 215 * 216 * @return True if the current request is from a tool that sets isAccessibilityTool. 217 */ isRequestFromAccessibilityTool(@onNull AccessibilityManager manager)218 public static boolean isRequestFromAccessibilityTool(@NonNull AccessibilityManager manager) { 219 if (Build.VERSION.SDK_INT >= 34) { 220 return Api34Impl.isRequestFromAccessibilityTool(manager); 221 } else { 222 // To preserve behavior, assume every service isAccessibilityTool if the system does 223 // not support this check. 224 return true; 225 } 226 } 227 228 private static final class TouchExplorationStateChangeListenerWrapper 229 implements AccessibilityManager.TouchExplorationStateChangeListener { 230 final TouchExplorationStateChangeListener mListener; 231 TouchExplorationStateChangeListenerWrapper( @onNull TouchExplorationStateChangeListener listener)232 TouchExplorationStateChangeListenerWrapper( 233 @NonNull TouchExplorationStateChangeListener listener) { 234 mListener = listener; 235 } 236 237 @Override hashCode()238 public int hashCode() { 239 return mListener.hashCode(); 240 } 241 242 @Override equals(Object o)243 public boolean equals(Object o) { 244 if (this == o) { 245 return true; 246 } 247 if (!(o instanceof TouchExplorationStateChangeListenerWrapper)) { 248 return false; 249 } 250 TouchExplorationStateChangeListenerWrapper other = 251 (TouchExplorationStateChangeListenerWrapper) o; 252 return mListener.equals(other.mListener); 253 } 254 255 @Override onTouchExplorationStateChanged(boolean enabled)256 public void onTouchExplorationStateChanged(boolean enabled) { 257 mListener.onTouchExplorationStateChanged(enabled); 258 } 259 } 260 261 /** 262 * Listener for the accessibility state. 263 * 264 * @deprecated Use {@link AccessibilityManager.AccessibilityStateChangeListener} directly 265 * instead of this listener. 266 */ 267 @SuppressWarnings("deprecation") 268 @Deprecated 269 public static abstract class AccessibilityStateChangeListenerCompat 270 implements AccessibilityStateChangeListener { 271 } 272 273 /** 274 * Listener for the accessibility state. 275 * 276 * @deprecated Use {@link AccessibilityManager.AccessibilityStateChangeListener} directly 277 * instead of this listener. 278 */ 279 @Deprecated 280 public interface AccessibilityStateChangeListener { 281 /** 282 * Called back on change in the accessibility state. 283 * 284 * @param enabled Whether accessibility is enabled. 285 * 286 * @deprecated Use {@link AccessibilityManager.AccessibilityStateChangeListener} directly. 287 */ 288 @Deprecated onAccessibilityStateChanged(boolean enabled)289 void onAccessibilityStateChanged(boolean enabled); 290 } 291 292 /** 293 * Listener for the system touch exploration state. To listen for changes to 294 * the touch exploration state on the device, implement this interface and 295 * register it with the system by calling 296 * {@link #addTouchExplorationStateChangeListener}. 297 */ 298 public interface TouchExplorationStateChangeListener { 299 /** 300 * Called when the touch exploration enabled state changes. 301 * 302 * @param enabled Whether touch exploration is enabled. 303 */ onTouchExplorationStateChanged(boolean enabled)304 void onTouchExplorationStateChanged(boolean enabled); 305 } 306 AccessibilityManagerCompat()307 private AccessibilityManagerCompat() { 308 } 309 310 @RequiresApi(34) 311 static class Api34Impl { Api34Impl()312 private Api34Impl() { 313 // This class is not instantiable. 314 } 315 isRequestFromAccessibilityTool(AccessibilityManager accessibilityManager)316 static boolean isRequestFromAccessibilityTool(AccessibilityManager accessibilityManager) { 317 return accessibilityManager.isRequestFromAccessibilityTool(); 318 } 319 } 320 } 321