AccessibilityUtils.java revision cc4b63ec4c3d3622f778c647eb584c68a3c00615
15ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette/* 25ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Copyright (C) 2011 The Android Open Source Project 35ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 45ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 55ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * you may not use this file except in compliance with the License. 65ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * You may obtain a copy of the License at 75ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 85ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 95ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 105ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Unless required by applicable law or agreed to in writing, software 115ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 125ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * See the License for the specific language governing permissions and 145ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * limitations under the License. 155ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 165ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 175ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverettepackage com.android.inputmethod.accessibility; 185ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 195ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.content.Context; 205ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.content.SharedPreferences; 215ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.inputmethodservice.InputMethodService; 225ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.os.SystemClock; 235ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.util.Log; 245ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.view.MotionEvent; 255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.view.accessibility.AccessibilityEvent; 265ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.view.accessibility.AccessibilityManager; 275ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 285ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.compat.AccessibilityEventCompatUtils; 295ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.compat.AccessibilityManagerCompatWrapper; 305ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.compat.MotionEventCompatUtils; 315ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 325ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverettepublic class AccessibilityUtils { 335ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static final String TAG = AccessibilityUtils.class.getSimpleName(); 345ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static final String CLASS = AccessibilityUtils.class.getClass().getName(); 355ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static final String PACKAGE = AccessibilityUtils.class.getClass().getPackage() 365ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette .getName(); 375ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 385ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static final AccessibilityUtils sInstance = new AccessibilityUtils(); 395ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 405ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private AccessibilityManager mAccessibilityManager; 415ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private AccessibilityManagerCompatWrapper mCompatManager; 425ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 435ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /* 445ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Setting this constant to {@code false} will disable all keyboard 455ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * accessibility code, regardless of whether Accessibility is turned on in 465ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the system settings. It should ONLY be used in the event of an emergency. 475ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 485ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static final boolean ENABLE_ACCESSIBILITY = true; 495ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 505ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public static void init(InputMethodService inputMethod, SharedPreferences prefs) { 515ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (!ENABLE_ACCESSIBILITY) 525ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return; 535ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 545ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // These only need to be initialized if the kill switch is off. 555ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette sInstance.initInternal(inputMethod, prefs); 565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette KeyCodeDescriptionMapper.init(inputMethod, prefs); 575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette AccessibleInputMethodServiceProxy.init(inputMethod, prefs); 585ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette AccessibleKeyboardViewProxy.init(inputMethod, prefs); 595ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 605ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public static AccessibilityUtils getInstance() { 625ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return sInstance; 635ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 645ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 655ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private AccessibilityUtils() { 665ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // This class is not publicly instantiable. 675ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 685ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 695ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private void initInternal(Context context, SharedPreferences prefs) { 705ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mAccessibilityManager = (AccessibilityManager) context 715ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette .getSystemService(Context.ACCESSIBILITY_SERVICE); 725ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mCompatManager = new AccessibilityManagerCompatWrapper(mAccessibilityManager); 735ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 745ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 755ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 765ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Returns {@code true} if touch exploration is enabled. Currently, this 775ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * means that the kill switch is off, the device supports touch exploration, 785ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * and a spoken feedback service is turned on. 795ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 805ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return {@code true} if touch exploration is enabled. 815ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 825ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public boolean isTouchExplorationEnabled() { 835ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return ENABLE_ACCESSIBILITY 845ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette && mAccessibilityManager.isEnabled() 85cc4b63ec4c3d3622f778c647eb584c68a3c00615Alan Viverette && mCompatManager.isTouchExplorationEnabled(); 865ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 875ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 885ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 895ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Returns {@true} if the provided event is a touch exploration (e.g. hover) 905ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * event. This is used to determine whether the event should be processed by 915ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the touch exploration code within the keyboard. 925ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 935ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param event The event to check. 945ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return {@true} is the event is a touch exploration event 955ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 965ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public boolean isTouchExplorationEvent(MotionEvent event) { 975ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final int action = event.getAction(); 985ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 995ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return action == MotionEventCompatUtils.ACTION_HOVER_ENTER 1005ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette || action == MotionEventCompatUtils.ACTION_HOVER_EXIT 1015ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette || action == MotionEventCompatUtils.ACTION_HOVER_MOVE; 1025ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1035ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1045ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 1055ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * Sends the specified text to the {@link AccessibilityManager} to be 1065ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * spoken. 1075ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 1085ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param text the text to speak 1095ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 1105ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public void speak(CharSequence text) { 1115ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette if (!mAccessibilityManager.isEnabled()) { 1125ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette Log.e(TAG, "Attempted to speak when accessibility was disabled!"); 1135ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return; 1145ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1155ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1165ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // The following is a hack to avoid using the heavy-weight TextToSpeech 1175ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // class. Instead, we're just forcing a fake AccessibilityEvent into 1185ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // the screen reader to make it speak. 1195ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final AccessibilityEvent event = AccessibilityEvent 1205ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette .obtain(AccessibilityEventCompatUtils.TYPE_VIEW_HOVER_ENTER); 1215ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1225ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette event.setPackageName(PACKAGE); 1235ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette event.setClassName(CLASS); 1245ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette event.setEventTime(SystemClock.uptimeMillis()); 1255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette event.setEnabled(true); 1265ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette event.getText().add(text); 1275ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1285ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette mAccessibilityManager.sendAccessibilityEvent(event); 1295ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1305ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette} 131