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"); you may not 55ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * use this file except in compliance with the License. You may obtain a copy of 65ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 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, WITHOUT 125ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 135ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * License for the specific language governing permissions and limitations under 145ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * the License. 155ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 165ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 175ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverettepackage com.android.inputmethod.accessibility; 185ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 195ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.content.Context; 2058e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viveretteimport android.inputmethodservice.InputMethodService; 219a81ce92c381007affe6bb2310bf94c9856eaae1alanvimport android.support.v4.view.AccessibilityDelegateCompat; 229a81ce92c381007affe6bb2310bf94c9856eaae1alanvimport android.support.v4.view.ViewCompat; 239a81ce92c381007affe6bb2310bf94c9856eaae1alanvimport android.support.v4.view.accessibility.AccessibilityEventCompat; 24f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanvimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport android.view.MotionEvent; 269a81ce92c381007affe6bb2310bf94c9856eaae1alanvimport android.view.View; 275ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 28e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaokaimport com.android.inputmethod.keyboard.Key; 298d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.keyboard.Keyboard; 308d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.keyboard.KeyboardId; 31c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView; 325ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.keyboard.PointerTracker; 338d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.latin.R; 345ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 35a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class AccessibleKeyboardViewProxy extends AccessibilityDelegateCompat { 365ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private static final AccessibleKeyboardViewProxy sInstance = new AccessibleKeyboardViewProxy(); 375ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 3858e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette private InputMethodService mInputMethod; 39c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka private MainKeyboardView mView; 409a81ce92c381007affe6bb2310bf94c9856eaae1alanv private AccessibilityEntityProvider mAccessibilityNodeProvider; 415ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 42e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka private Key mLastHoverKey = null; 435ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 446662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv /** 456662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * Inset in pixels to look for keys when the user's finger exits the 46e76a9b36cabc3eb9222be245e2cf736169432cd6alanv * keyboard area. 476662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv */ 486662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv private int mEdgeSlop; 496662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv 502ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka public static void init(InputMethodService inputMethod) { 512ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka sInstance.initInternal(inputMethod); 525ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 535ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 545ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette public static AccessibleKeyboardViewProxy getInstance() { 555ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return sInstance; 565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 585ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette private AccessibleKeyboardViewProxy() { 595ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // Not publicly instantiable. 605ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 622ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka private void initInternal(InputMethodService inputMethod) { 6358e3f1065ef47e7116299b9d5087ba2a2b6065a2Alan Viverette mInputMethod = inputMethod; 64e76a9b36cabc3eb9222be245e2cf736169432cd6alanv mEdgeSlop = inputMethod.getResources().getDimensionPixelSize( 65e76a9b36cabc3eb9222be245e2cf736169432cd6alanv R.dimen.accessibility_edge_slop); 665ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 675ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 689a81ce92c381007affe6bb2310bf94c9856eaae1alanv /** 699a81ce92c381007affe6bb2310bf94c9856eaae1alanv * Sets the view wrapped by this proxy. 709a81ce92c381007affe6bb2310bf94c9856eaae1alanv * 719a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @param view The view to wrap. 729a81ce92c381007affe6bb2310bf94c9856eaae1alanv */ 73c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka public void setView(MainKeyboardView view) { 749a81ce92c381007affe6bb2310bf94c9856eaae1alanv if (view == null) { 759a81ce92c381007affe6bb2310bf94c9856eaae1alanv // Ignore null views. 769a81ce92c381007affe6bb2310bf94c9856eaae1alanv return; 775ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 785ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 799a81ce92c381007affe6bb2310bf94c9856eaae1alanv mView = view; 805ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 819a81ce92c381007affe6bb2310bf94c9856eaae1alanv // Ensure that the view has an accessibility delegate. 829a81ce92c381007affe6bb2310bf94c9856eaae1alanv ViewCompat.setAccessibilityDelegate(view, this); 8348ccd5528163383a46b597e9d5ea919ddc799f25alanv 8448ccd5528163383a46b597e9d5ea919ddc799f25alanv if (mAccessibilityNodeProvider != null) { 8548ccd5528163383a46b597e9d5ea919ddc799f25alanv mAccessibilityNodeProvider.setView(view); 8648ccd5528163383a46b597e9d5ea919ddc799f25alanv } 879a81ce92c381007affe6bb2310bf94c9856eaae1alanv } 885ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 89f147794fd41491a3383e6aca6d49007f58124068alanv public void setKeyboard(Keyboard keyboard) { 90f147794fd41491a3383e6aca6d49007f58124068alanv if (mAccessibilityNodeProvider != null) { 91f147794fd41491a3383e6aca6d49007f58124068alanv mAccessibilityNodeProvider.setKeyboard(keyboard); 92f147794fd41491a3383e6aca6d49007f58124068alanv } 93f147794fd41491a3383e6aca6d49007f58124068alanv } 94f147794fd41491a3383e6aca6d49007f58124068alanv 959a81ce92c381007affe6bb2310bf94c9856eaae1alanv /** 969a81ce92c381007affe6bb2310bf94c9856eaae1alanv * Proxy method for View.getAccessibilityNodeProvider(). This method is 979a81ce92c381007affe6bb2310bf94c9856eaae1alanv * called in SDK version 15 and higher to obtain the virtual node hierarchy 989a81ce92c381007affe6bb2310bf94c9856eaae1alanv * provider. 999a81ce92c381007affe6bb2310bf94c9856eaae1alanv * 1009a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @return The accessibility node provider for the current keyboard. 1019a81ce92c381007affe6bb2310bf94c9856eaae1alanv */ 1029a81ce92c381007affe6bb2310bf94c9856eaae1alanv @Override 1039a81ce92c381007affe6bb2310bf94c9856eaae1alanv public AccessibilityEntityProvider getAccessibilityNodeProvider(View host) { 104f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv return getAccessibilityNodeProvider(); 1055ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1065ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1075ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette /** 108dc2ee7772402633817702e95c2a5b17f6dec03ebalanv * Intercepts touch events before dispatch when touch exploration is turned 109dc2ee7772402633817702e95c2a5b17f6dec03ebalanv * on in ICS and higher. 11026b424b6448fbaddc86d11377ca44ff3169a5d7ealanv * 111dc2ee7772402633817702e95c2a5b17f6dec03ebalanv * @param event The motion event being dispatched. 11226b424b6448fbaddc86d11377ca44ff3169a5d7ealanv * @return {@code true} if the event is handled 11326b424b6448fbaddc86d11377ca44ff3169a5d7ealanv */ 114dc2ee7772402633817702e95c2a5b17f6dec03ebalanv public boolean dispatchTouchEvent(MotionEvent event) { 11526b424b6448fbaddc86d11377ca44ff3169a5d7ealanv // To avoid accidental key presses during touch exploration, always drop 116dc2ee7772402633817702e95c2a5b17f6dec03ebalanv // touch events generated by the user. 11726b424b6448fbaddc86d11377ca44ff3169a5d7ealanv return false; 11826b424b6448fbaddc86d11377ca44ff3169a5d7ealanv } 11926b424b6448fbaddc86d11377ca44ff3169a5d7ealanv 12026b424b6448fbaddc86d11377ca44ff3169a5d7ealanv /** 12126b424b6448fbaddc86d11377ca44ff3169a5d7ealanv * Receives hover events when touch exploration is turned on in SDK versions 12226b424b6448fbaddc86d11377ca44ff3169a5d7ealanv * ICS and higher. 1235ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * 1245ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @param event The hover event. 1255ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette * @return {@code true} if the event is handled 1265ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette */ 127586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette public boolean dispatchHoverEvent(MotionEvent event, PointerTracker tracker) { 1285ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final int x = (int) event.getX(); 1295ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette final int y = (int) event.getY(); 1309a81ce92c381007affe6bb2310bf94c9856eaae1alanv final Key previousKey = mLastHoverKey; 131e76a9b36cabc3eb9222be245e2cf736169432cd6alanv final Key key; 132e76a9b36cabc3eb9222be245e2cf736169432cd6alanv 133e76a9b36cabc3eb9222be245e2cf736169432cd6alanv if (pointInView(x, y)) { 134e76a9b36cabc3eb9222be245e2cf736169432cd6alanv key = tracker.getKeyOn(x, y); 135e76a9b36cabc3eb9222be245e2cf736169432cd6alanv } else { 136e76a9b36cabc3eb9222be245e2cf736169432cd6alanv key = null; 137e76a9b36cabc3eb9222be245e2cf736169432cd6alanv } 1389a81ce92c381007affe6bb2310bf94c9856eaae1alanv 1399a81ce92c381007affe6bb2310bf94c9856eaae1alanv mLastHoverKey = key; 1405ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1415ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette switch (event.getAction()) { 142c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka case MotionEvent.ACTION_HOVER_EXIT: 1436662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv // Make sure we're not getting an EXIT event because the user slid 1446662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv // off the keyboard area, then force a key press. 145e76a9b36cabc3eb9222be245e2cf736169432cd6alanv if (key != null) { 146f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv getAccessibilityNodeProvider().simulateKeyPress(key); 1476662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv } 1486662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv //$FALL-THROUGH$ 1496662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv case MotionEvent.ACTION_HOVER_ENTER: 1509a81ce92c381007affe6bb2310bf94c9856eaae1alanv return onHoverKey(key, event); 151c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka case MotionEvent.ACTION_HOVER_MOVE: 1529a81ce92c381007affe6bb2310bf94c9856eaae1alanv if (key != previousKey) { 1539a81ce92c381007affe6bb2310bf94c9856eaae1alanv return onTransitionKey(key, previousKey, event); 1549a81ce92c381007affe6bb2310bf94c9856eaae1alanv } else { 1559a81ce92c381007affe6bb2310bf94c9856eaae1alanv return onHoverKey(key, event); 1565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1585ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1595ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette return false; 1605ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 1615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 1629a81ce92c381007affe6bb2310bf94c9856eaae1alanv /** 163f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv * @return A lazily-instantiated node provider for this view proxy. 164f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv */ 165f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv private AccessibilityEntityProvider getAccessibilityNodeProvider() { 166f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv // Instantiate the provide only when requested. Since the system 167f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv // will call this method multiple times it is a good practice to 168f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv // cache the provider instance. 169f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv if (mAccessibilityNodeProvider == null) { 170f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv mAccessibilityNodeProvider = new AccessibilityEntityProvider(mView, mInputMethod); 171f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv } 172f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv return mAccessibilityNodeProvider; 173f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv } 174f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv 175f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv /** 1766662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * Utility method to determine whether the given point, in local 1776662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * coordinates, is inside the view, where the area of the view is contracted 1786662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * by the edge slop factor. 1796662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * 1806662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * @param localX The local x-coordinate. 1816662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv * @param localY The local y-coordinate. 1826662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv */ 1836662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv private boolean pointInView(int localX, int localY) { 1846662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv return (localX >= mEdgeSlop) && (localY >= mEdgeSlop) 1856662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv && (localX < (mView.getWidth() - mEdgeSlop)) 1866662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv && (localY < (mView.getHeight() - mEdgeSlop)); 1876662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv } 1886662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv 1896662e2a40dc764d5b6a55c0e30ce650fd834afb6alanv /** 1909a81ce92c381007affe6bb2310bf94c9856eaae1alanv * Simulates a transition between two {@link Key}s by sending a HOVER_EXIT 1919a81ce92c381007affe6bb2310bf94c9856eaae1alanv * on the previous key, a HOVER_ENTER on the current key, and a HOVER_MOVE 1929a81ce92c381007affe6bb2310bf94c9856eaae1alanv * on the current key. 1939a81ce92c381007affe6bb2310bf94c9856eaae1alanv * 1949a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @param currentKey The currently hovered key. 1959a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @param previousKey The previously hovered key. 1969a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @param event The event that triggered the transition. 1979a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @return {@code true} if the event was handled. 1989a81ce92c381007affe6bb2310bf94c9856eaae1alanv */ 1999a81ce92c381007affe6bb2310bf94c9856eaae1alanv private boolean onTransitionKey(Key currentKey, Key previousKey, MotionEvent event) { 2009a81ce92c381007affe6bb2310bf94c9856eaae1alanv final int savedAction = event.getAction(); 2019a81ce92c381007affe6bb2310bf94c9856eaae1alanv 202c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka event.setAction(MotionEvent.ACTION_HOVER_EXIT); 2039a81ce92c381007affe6bb2310bf94c9856eaae1alanv onHoverKey(previousKey, event); 2049a81ce92c381007affe6bb2310bf94c9856eaae1alanv 205c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka event.setAction(MotionEvent.ACTION_HOVER_ENTER); 2069a81ce92c381007affe6bb2310bf94c9856eaae1alanv onHoverKey(currentKey, event); 2079a81ce92c381007affe6bb2310bf94c9856eaae1alanv 208c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka event.setAction(MotionEvent.ACTION_HOVER_MOVE); 2099a81ce92c381007affe6bb2310bf94c9856eaae1alanv final boolean handled = onHoverKey(currentKey, event); 2109a81ce92c381007affe6bb2310bf94c9856eaae1alanv 2119a81ce92c381007affe6bb2310bf94c9856eaae1alanv event.setAction(savedAction); 2129a81ce92c381007affe6bb2310bf94c9856eaae1alanv 2139a81ce92c381007affe6bb2310bf94c9856eaae1alanv return handled; 2149a81ce92c381007affe6bb2310bf94c9856eaae1alanv } 2159a81ce92c381007affe6bb2310bf94c9856eaae1alanv 2169a81ce92c381007affe6bb2310bf94c9856eaae1alanv /** 2179a81ce92c381007affe6bb2310bf94c9856eaae1alanv * Handles a hover event on a key. If {@link Key} extended View, this would 2189a81ce92c381007affe6bb2310bf94c9856eaae1alanv * be analogous to calling View.onHoverEvent(MotionEvent). 2199a81ce92c381007affe6bb2310bf94c9856eaae1alanv * 2209a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @param key The currently hovered key. 2219a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @param event The hover event. 2229a81ce92c381007affe6bb2310bf94c9856eaae1alanv * @return {@code true} if the event was handled. 2239a81ce92c381007affe6bb2310bf94c9856eaae1alanv */ 2249a81ce92c381007affe6bb2310bf94c9856eaae1alanv private boolean onHoverKey(Key key, MotionEvent event) { 2259a81ce92c381007affe6bb2310bf94c9856eaae1alanv // Null keys can't receive events. 2269a81ce92c381007affe6bb2310bf94c9856eaae1alanv if (key == null) { 2279a81ce92c381007affe6bb2310bf94c9856eaae1alanv return false; 2285ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 2295ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 230f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv final AccessibilityEntityProvider provider = getAccessibilityNodeProvider(); 231f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv 2329a81ce92c381007affe6bb2310bf94c9856eaae1alanv switch (event.getAction()) { 233c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka case MotionEvent.ACTION_HOVER_ENTER: 234f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv provider.sendAccessibilityEventForKey( 235f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv key, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER); 236f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv provider.performActionForKey( 237f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null); 2389a81ce92c381007affe6bb2310bf94c9856eaae1alanv break; 239c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka case MotionEvent.ACTION_HOVER_EXIT: 240f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv provider.sendAccessibilityEventForKey( 241f2eba97cc09c86f9a84b61cccf3f233e1fb85a6calanv key, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); 2429a81ce92c381007affe6bb2310bf94c9856eaae1alanv break; 2435ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette } 2445ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 2459a81ce92c381007affe6bb2310bf94c9856eaae1alanv return true; 2469a81ce92c381007affe6bb2310bf94c9856eaae1alanv } 2475ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 2489a81ce92c381007affe6bb2310bf94c9856eaae1alanv /** 2498d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv * Notifies the user of changes in the keyboard shift state. 2508d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv */ 2518d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv public void notifyShiftState() { 2528d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final Keyboard keyboard = mView.getKeyboard(); 2538d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final KeyboardId keyboardId = keyboard.mId; 2548d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final int elementId = keyboardId.mElementId; 2558d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final Context context = mView.getContext(); 2568d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final CharSequence text; 2578d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 2588d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (elementId) { 2598d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: 2608d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: 2618d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv text = context.getText(R.string.spoken_description_shiftmode_locked); 2628d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 2638d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: 2648d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: 2658d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: 2668d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv text = context.getText(R.string.spoken_description_shiftmode_on); 2678d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 2688d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv default: 2698d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv text = context.getText(R.string.spoken_description_shiftmode_off); 2708d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2718d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 2725f312c9c1546da9f73d02f911d3365da4ff658fbalanv AccessibilityUtils.getInstance().announceForAccessibility(mView, text); 2738d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2748d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 2758d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv /** 2768d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv * Notifies the user of changes in the keyboard symbols state. 2778d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv */ 2788d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv public void notifySymbolsState() { 2798d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final Keyboard keyboard = mView.getKeyboard(); 2808d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final Context context = mView.getContext(); 2818d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final KeyboardId keyboardId = keyboard.mId; 2828d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final int elementId = keyboardId.mElementId; 2838d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final int resId; 2848d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 2858d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (elementId) { 2868d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET: 2878d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED: 2888d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: 2898d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED: 2908d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED: 2918d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv resId = R.string.spoken_description_mode_alpha; 2928d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 2938d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_SYMBOLS: 2948d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_SYMBOLS_SHIFTED: 2958d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv resId = R.string.spoken_description_mode_symbol; 2968d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 2978d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_PHONE: 2988d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv resId = R.string.spoken_description_mode_phone; 2998d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 3008d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case KeyboardId.ELEMENT_PHONE_SYMBOLS: 3018d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv resId = R.string.spoken_description_mode_phone_shift; 3028d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 3038d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv default: 3048d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv resId = -1; 3058d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 3068d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 3078d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv if (resId < 0) { 3088d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv return; 3098d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 3108d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 3118d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv final String text = context.getString(resId); 3125f312c9c1546da9f73d02f911d3365da4ff658fbalanv AccessibilityUtils.getInstance().announceForAccessibility(mView, text); 3138d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 3145ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette} 315