ExploreByTouchHelper.java revision 6eb3cdf42d5382aef6b6a6afd7c305dbc27885b9
16eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette/* 26eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Copyright (C) 2013 The Android Open Source Project 36eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 46eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 56eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * you may not use this file except in compliance with the License. 66eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * You may obtain a copy of the License at 76eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 86eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 96eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Unless required by applicable law or agreed to in writing, software 116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * See the License for the specific language governing permissions and 146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * limitations under the License. 156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverettepackage android.support.v4.widget; 186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.content.Context; 206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.graphics.Rect; 216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.os.Bundle; 226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.AccessibilityDelegateCompat; 236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.MotionEventCompat; 246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.ViewCompat; 256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.ViewParentCompat; 266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityEventCompat; 276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityManagerCompat; 286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityNodeProviderCompat; 306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.support.v4.view.accessibility.AccessibilityRecordCompat; 316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.view.MotionEvent; 326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.view.View; 336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.view.ViewParent; 346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.view.accessibility.AccessibilityEvent; 356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport android.view.accessibility.AccessibilityManager; 366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport java.util.LinkedList; 386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viveretteimport java.util.List; 396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette/** 416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * ExploreByTouchHelper is a utility class for implementing accessibility 426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * support in custom {@link View}s that represent a collection of View-like 436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * logical items. It extends {@link AccessibilityNodeProviderCompat} and 446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * simplifies many aspects of providing information to accessibility services 456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * and managing accessibility focus. This class does not currently support 466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * hierarchies of logical items. 476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * This should be applied to the parent view using 496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link ViewCompat#setAccessibilityDelegate}: 506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <pre> 526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * mAccessHelper = ExploreByTouchHelper.create(someView, mAccessHelperCallback); 536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * ViewCompat.setAccessibilityDelegate(someView, mAccessHelper); 546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </pre> 556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverettepublic abstract class ExploreByTouchHelper extends AccessibilityDelegateCompat { 576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** Virtual node identifier value for invalid nodes. */ 586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public static final int INVALID_ID = Integer.MIN_VALUE; 596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** Default class name used for virtual views. */ 616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private static final String DEFAULT_CLASS_NAME = View.class.getName(); 626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Temporary, reusable data structures. 646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private final Rect mTempScreenRect = new Rect(); 656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private final Rect mTempParentRect = new Rect(); 666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private final Rect mTempVisibleRect = new Rect(); 676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private final int[] mTempGlobalRect = new int[2]; 686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** System accessibility manager, used to check state and send events. */ 706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private final AccessibilityManager mManager; 716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** View whose internal structure is exposed through this helper. */ 736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private final View mView; 746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** Node provider that handles creating nodes and performing actions. */ 766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private ExploreByTouchNodeProvider mNodeProvider; 776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** Virtual view id for the currently focused logical item. */ 796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private int mFocusedVirtualViewId = INVALID_ID; 806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** Virtual view id for the currently hovered logical item. */ 826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private int mHoveredVirtualViewId = INVALID_ID; 836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Factory method to create a new {@link ExploreByTouchHelper}. 866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param forView View whose logical children are exposed by this helper. 886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public ExploreByTouchHelper(View forView) { 906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (forView == null) { 916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette throw new IllegalArgumentException("View may not be null"); 926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mView = forView; 956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final Context context = forView.getContext(); 966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 1006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Returns the {@link AccessibilityNodeProviderCompat} for this helper. 1016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 1026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param host View whose logical children are exposed by this helper. 1036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return The accessibility node provider for this helper. 1046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 1056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette @Override 1066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) { 1076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (mNodeProvider == null) { 1086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mNodeProvider = new ExploreByTouchNodeProvider(); 1096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return mNodeProvider; 1116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 1146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Dispatches hover {@link MotionEvent}s to the virtual view hierarchy when 1156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * the Explore by Touch feature is enabled. 1166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 1176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * This method should be called by overriding 1186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link View#dispatchHoverEvent}: 1196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 1206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <pre>@Override 1216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * public boolean dispatchHoverEvent(MotionEvent event) { 1226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * if (mHelper.dispatchHoverEvent(this, event) { 1236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * return true; 1246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * } 1256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * return super.dispatchHoverEvent(event); 1266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * } 1276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </pre> 1286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 1296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param event The hover event to dispatch to the virtual view hierarchy. 1306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return Whether the hover event was handled. 1316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 1326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public boolean dispatchHoverEvent(MotionEvent event) { 1336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (!mManager.isEnabled() 1346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette || !AccessibilityManagerCompat.isTouchExplorationEnabled(mManager)) { 1356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 1366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette switch (event.getAction()) { 1396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case MotionEventCompat.ACTION_HOVER_MOVE: 1406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case MotionEventCompat.ACTION_HOVER_ENTER: 1416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final int virtualViewId = getVirtualViewAt(event.getX(), event.getY()); 1426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette updateHoveredVirtualView(virtualViewId); 1436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return (virtualViewId != INVALID_ID); 1446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case MotionEventCompat.ACTION_HOVER_EXIT: 1456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (mFocusedVirtualViewId != INVALID_ID) { 1466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette updateHoveredVirtualView(INVALID_ID); 1476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return true; 1486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 1506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette default: 1516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 1526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 1566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Populates an event of the specified type with information about an item 1576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * and attempts to send it up through the view hierarchy. 1586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 1596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * You should call this method after performing a user action that normally 1606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * fires an accessibility event, such as clicking on an item. 1616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 1626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <pre>public void performItemClick(T item) { 1636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * ... 1646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * sendEventForVirtualViewId(item.id, AccessibilityEvent.TYPE_VIEW_CLICKED); 1656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * } 1666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </pre> 1676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 1686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for which to send an event. 1696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param eventType The type of event to send. 1706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return true if the event was sent successfully. 1716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 1726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public boolean sendEventForVirtualView(int virtualViewId, int eventType) { 1736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if ((virtualViewId == INVALID_ID) || !mManager.isEnabled()) { 1746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 1756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final ViewParent parent = mView.getParent(); 1786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (parent == null) { 1796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 1806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final AccessibilityEvent event = createEvent(virtualViewId, eventType); 1836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return ViewParentCompat.requestSendAccessibilityEvent(parent, mView, event); 1846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 1876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Notifies the accessibility framework that the properties of the parent 1886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * view have changed. 1896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 1906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * You <b>must</b> call this method after adding or removing items from the 1916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * parent view. 1926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 1936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public void invalidateRoot() { 1946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette invalidateVirtualView(View.NO_ID); 1956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 1966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 1976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 1986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Notifies the accessibility framework that the properties of a particular 1996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * item have changed. 2006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 2016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * You <b>must</b> call this method after changing any of the properties set 2026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * in {@link #onPopulateNodeForVirtualView}. 2036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 2046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id to invalidate. 2056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 2066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public void invalidateVirtualView(int virtualViewId) { 2076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette sendEventForVirtualView( 2086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette virtualViewId, AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); 2096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 2126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Sets the currently hovered item, sending hover accessibility events as 2136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * necessary to maintain the correct state. 2146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 2156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for the item currently being 2166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * hovered, or {@link #INVALID_ID} if no item is hovered within 2176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * the parent view. 2186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 2196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private void updateHoveredVirtualView(int virtualViewId) { 2206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (mHoveredVirtualViewId == virtualViewId) { 2216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return; 2226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final int previousVirtualViewId = mHoveredVirtualViewId; 2256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mHoveredVirtualViewId = virtualViewId; 2266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Stay consistent with framework behavior by sending ENTER/EXIT pairs 2286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // in reverse order. This is accurate as of API 18. 2296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette sendEventForVirtualView(virtualViewId, AccessibilityEventCompat.TYPE_VIEW_HOVER_ENTER); 2306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette sendEventForVirtualView( 2316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette previousVirtualViewId, AccessibilityEventCompat.TYPE_VIEW_HOVER_EXIT); 2326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 2356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Constructs and returns an {@link AccessibilityEvent} for the specified 2366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * virtual view id, which includes the host view ({@link View#NO_ID}). 2376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 2386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for the item for which to 2396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * construct an event. 2406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param eventType The type of event to construct. 2416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return An {@link AccessibilityEvent} populated with information about 2426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * the specified item. 2436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 2446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private AccessibilityEvent createEvent(int virtualViewId, int eventType) { 2456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette switch (virtualViewId) { 2466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case View.NO_ID: 2476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return createEventForHost(eventType); 2486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette default: 2496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return createEventForChild(virtualViewId, eventType); 2506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 2546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Constructs and returns an {@link AccessibilityEvent} for the host node. 2556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 2566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param eventType The type of event to construct. 2576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return An {@link AccessibilityEvent} populated with information about 2586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * the specified item. 2596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 2606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private AccessibilityEvent createEventForHost(int eventType) { 2616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette ViewCompat.onInitializeAccessibilityEvent(mView, event); 2636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return event; 2646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 2676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Constructs and returns an {@link AccessibilityEvent} populated with 2686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * information about the specified item. 2696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 2706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for the item for which to 2716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * construct an event. 2726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param eventType The type of event to construct. 2736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return An {@link AccessibilityEvent} populated with information about 2746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * the specified item. 2756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 2766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private AccessibilityEvent createEventForChild(int virtualViewId, int eventType) { 2776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 2786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette event.setEnabled(true); 2796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette event.setClassName(DEFAULT_CLASS_NAME); 2806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Allow the client to populate the event. 2826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette onPopulateEventForVirtualView(virtualViewId, event); 2836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Make sure the developer is following the rules. 2856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (event.getText().isEmpty() && (event.getContentDescription() == null)) { 2866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette throw new RuntimeException("Callbacks must add text or a content description in " 2876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette + "populateEventForVirtualViewId()"); 2886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Don't allow the client to override these properties. 2916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette event.setPackageName(mView.getContext().getPackageName()); 2926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event); 2946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette record.setSource(mView, virtualViewId); 2956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return event; 2976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 2986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 2996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 3006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the 3016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * specified virtual view id, which includes the host view 3026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * ({@link View#NO_ID}). 3036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 3046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for the item for which to 3056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * construct a node. 3066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return An {@link AccessibilityNodeInfoCompat} populated with information 3076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * about the specified item. 3086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 3096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private AccessibilityNodeInfoCompat createNode(int virtualViewId) { 3106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette switch (virtualViewId) { 3116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case View.NO_ID: 3126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return createNodeForHost(); 3136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette default: 3146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return createNodeForChild(virtualViewId); 3156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 3196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the 3206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * host view populated with its virtual descendants. 3216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 3226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return An {@link AccessibilityNodeInfoCompat} for the parent node. 3236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 3246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private AccessibilityNodeInfoCompat createNodeForHost() { 3256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain(mView); 3266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette ViewCompat.onInitializeAccessibilityNodeInfo(mView, node); 3276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Add the virtual descendants. 3296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>(); 3306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette getVisibleVirtualViews(virtualViewIds); 3316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette for (Integer childVirtualViewId : virtualViewIds) { 3336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.addChild(mView, childVirtualViewId); 3346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return node; 3376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 3406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the 3416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * specified item. Automatically manages accessibility focus actions. 3426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 3436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Allows the implementing class to specify most node properties, but 3446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * overrides the following: 3456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 3466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setPackageName} 3476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setClassName} 3486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setParent(View)} 3496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)} 3506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser} 3516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)} 3526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 3536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 3546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Uses the bounds of the parent view and the parent-relative bounding 3556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * rectangle specified by 3566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically 3576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * update the following properties: 3586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 3596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser} 3606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent} 3616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 3626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 3636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for item for which to construct 3646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * a node. 3656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return An {@link AccessibilityNodeInfoCompat} for the specified item. 3666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 3676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) { 3686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain(); 3696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Ensure the client has good defaults. 3716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setEnabled(true); 3726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setClassName(DEFAULT_CLASS_NAME); 3736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Allow the client to populate the node. 3756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette onPopulateNodeForVirtualView(virtualViewId, node); 3766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Make sure the developer is following the rules. 3786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if ((node.getText() == null) && (node.getContentDescription() == null)) { 3796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette throw new RuntimeException("Callbacks must add text or a content description in " 3806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette + "populateNodeForVirtualViewId()"); 3816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.getBoundsInParent(mTempParentRect); 3846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (mTempParentRect.isEmpty()) { 3856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette throw new RuntimeException("Callbacks must set parent bounds in " 3866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette + "populateNodeForVirtualViewId()"); 3876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final int actions = node.getActions(); 3906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) { 3916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in " 3926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette + "populateNodeForVirtualViewId()"); 3936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) { 3956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in " 3966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette + "populateNodeForVirtualViewId()"); 3976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 3986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 3996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Don't allow the client to override these properties. 4006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setPackageName(mView.getContext().getPackageName()); 4016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setSource(mView, virtualViewId); 4026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setParent(mView); 4036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Manage internal accessibility focus state. 4056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (mFocusedVirtualViewId == virtualViewId) { 4066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setAccessibilityFocused(true); 4076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 4086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } else { 4096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setAccessibilityFocused(false); 4106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS); 4116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Set the visibility based on the parent bound. 4146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (intersectVisibleToUser(mTempParentRect)) { 4156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setVisibleToUser(true); 4166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setBoundsInParent(mTempParentRect); 4176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Calculate screen-relative bound. 4206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mView.getLocationOnScreen(mTempGlobalRect); 4216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final int offsetX = mTempGlobalRect[0]; 4226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final int offsetY = mTempGlobalRect[1]; 4236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mTempScreenRect.set(mTempParentRect); 4246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mTempScreenRect.offset(offsetX, offsetY); 4256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette node.setBoundsInScreen(mTempScreenRect); 4266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return node; 4286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean performAction(int virtualViewId, int action, Bundle arguments) { 4316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette switch (virtualViewId) { 4326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case View.NO_ID: 4336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return performActionForHost(action, arguments); 4346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette default: 4356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return performActionForChild(virtualViewId, action, arguments); 4366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean performActionForHost(int action, Bundle arguments) { 4406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return ViewCompat.performAccessibilityAction(mView, action, arguments); 4416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) { 4446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette switch (action) { 4456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS: 4466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS: 4476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return manageFocusForChild(virtualViewId, action, arguments); 4486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette default: 4496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return onPerformActionForVirtualView(virtualViewId, action, arguments); 4506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) { 4546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette switch (action) { 4556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS: 4566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (!isAccessibilityFocused(virtualViewId)) { 4576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return requestAccessibilityFocus(virtualViewId); 4586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 4606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS: 4616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (isAccessibilityFocused(virtualViewId)) { 4626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette clearAccessibilityFocus(virtualViewId); 4636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return true; 4646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 4666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette default: 4676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 4686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 4726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Computes whether the specified {@link Rect} intersects with the visible 4736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * portion of its parent {@link View}. Modifies {@code localRect} to contain 4746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * only the visible portion. 4756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 4766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param localRect A rectangle in local (parent) coordinates. 4776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return Whether the specified {@link Rect} is visible on the screen. 4786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 4796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean intersectVisibleToUser(Rect localRect) { 4806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Missing or empty bounds mean this view is not visible. 4816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if ((localRect == null) || localRect.isEmpty()) { 4826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 4836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Attached to invisible window means this view is not visible. 4866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (mView.getWindowVisibility() != View.VISIBLE) { 4876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 4886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 4906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // An invisible predecessor means that this view is not visible. 4916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette Object viewParent = this; 4926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette while (viewParent instanceof View) { 4936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette final View view = (View) viewParent; 4946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if ((ViewCompat.getAlpha(view) <= 0) || (view.getVisibility() != View.VISIBLE)) { 4956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 4966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette viewParent = view.getParent(); 4986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 4996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // A null parent implies the view is not visible. 5016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (viewParent == null) { 5026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 5036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // If no portion of the parent is visible, this view is not visible. 5066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (!mView.getLocalVisibleRect(mTempVisibleRect)) { 5076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 5086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // Check if the view intersects the visible portion of the parent. 5116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return localRect.intersect(mTempVisibleRect); 5126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 5156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Returns whether this virtual view is accessibility focused. 5166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 5176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return True if the view is accessibility focused. 5186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 5196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean isAccessibilityFocused(int virtualViewId) { 5206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return (mFocusedVirtualViewId == virtualViewId); 5216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 5246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Attempts to give accessibility focus to a virtual view. 5256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 5266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * A virtual view will not actually take focus if 5276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityManager#isEnabled()} returns false, 5286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityManager#isTouchExplorationEnabled()} returns false, 5296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * or the view already has accessibility focus. 5306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 5316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The id of the virtual view on which to place 5326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * accessibility focus. 5336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return Whether this virtual view actually took accessibility focus. 5346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 5356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private boolean requestAccessibilityFocus(int virtualViewId) { 5366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (!mManager.isEnabled() 5376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette || !AccessibilityManagerCompat.isTouchExplorationEnabled(mManager)) { 5386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 5396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // TODO: Check virtual view visibility. 5416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (!isAccessibilityFocused(virtualViewId)) { 5426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mFocusedVirtualViewId = virtualViewId; 5436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // TODO: Only invalidate virtual view bounds. 5446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mView.invalidate(); 5456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette sendEventForVirtualView(virtualViewId, 5466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 5476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette notifyAccessibilityStateChanged(virtualViewId); 5486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return true; 5496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return false; 5516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 5546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Attempts to clear accessibility focus from a virtual view. 5556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 5566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private void clearAccessibilityFocus(int virtualViewId) { 5576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette if (isAccessibilityFocused(virtualViewId)) { 5586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mFocusedVirtualViewId = INVALID_ID; 5596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette mView.invalidate(); 5606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette sendEventForVirtualView(virtualViewId, 5616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 5626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette notifyAccessibilityStateChanged(virtualViewId); 5636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private void notifyAccessibilityStateChanged(int virtualViewId) { 5676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette // TODO: This method is not visible. 5686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 5696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 5716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Provides a mapping between view-relative coordinates and logical 5726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * items. 5736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 5746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param x The view-relative x coordinate 5756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param y The view-relative y coordinate 5766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return virtual view identifier for the logical item under 5776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * coordinates (x,y) 5786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 5796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette protected abstract int getVirtualViewAt(float x, float y); 5806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 5826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Populates a list with the view's visible items. The ordering of items 5836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * within {@code virtualViewIds} specifies order of accessibility focus 5846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * traversal. 5856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 5866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewIds The list to populate with visible items 5876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 5886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette protected abstract void getVisibleVirtualViews(List<Integer> virtualViewIds); 5896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 5906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 5916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Populates an {@link AccessibilityEvent} with information about the 5926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * specified item. 5936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 5946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Implementations <b>must</b> populate the following required fields: 5956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 5966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>event text, see {@link AccessibilityEvent#getText} or 5976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityEvent#setContentDescription} 5986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 5996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * The helper class automatically populates the following fields with 6016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * default values, but implementations may optionally override them: 6026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 6036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>item class name, set to android.view.View, see 6046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityEvent#setClassName} 6056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 6066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * The following required fields are automatically populated by the 6086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * helper class and may not be overridden: 6096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 6106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>package name, set to the package of the host view's 6116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link Context}, see {@link AccessibilityEvent#setPackageName} 6126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>event source, set to the host view and virtual view identifier, 6136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * see {@link AccessibilityRecordCompat#setSource(View, int)} 6146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 6156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 6166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view id for the item for which to 6176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * populate the event 6186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param event The event to populate 6196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 6206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette protected abstract void onPopulateEventForVirtualView( 6216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette int virtualViewId, AccessibilityEvent event); 6226eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 6236eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 6246eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Populates an {@link AccessibilityNodeInfoCompat} with information 6256eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * about the specified item. 6266eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6276eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Implementations <b>must</b> populate the following required fields: 6286eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 6296eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>event text, see {@link AccessibilityNodeInfoCompat#setText} or 6306eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setContentDescription} 6316eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>bounds in parent coordinates, see 6326eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setBoundsInParent} 6336eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 6346eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6356eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * The helper class automatically populates the following fields with 6366eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * default values, but implementations may optionally override them: 6376eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 6386eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>enabled state, set to true, see 6396eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setEnabled} 6406eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>item class name, identical to the class name set by 6416eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link #onPopulateEventForVirtualView}, see 6426eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setClassName} 6436eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 6446eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6456eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * The following required fields are automatically populated by the 6466eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * helper class and may not be overridden: 6476eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <ul> 6486eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>package name, identical to the package name set by 6496eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link #onPopulateEventForVirtualView}, see 6506eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setPackageName} 6516eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>node source, identical to the event source set in 6526eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link #onPopulateEventForVirtualView}, see 6536eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setSource(View, int)} 6546eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>parent view, set to the host view, see 6556eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setParent(View)} 6566eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>visibility, computed based on parent-relative bounds, see 6576eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setVisibleToUser} 6586eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>accessibility focus, computed based on internal helper state, see 6596eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#setAccessibilityFocused} 6606eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <li>bounds in screen coordinates, computed based on host view bounds, 6616eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * see {@link AccessibilityNodeInfoCompat#setBoundsInScreen} 6626eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * </ul> 6636eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6646eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Additionally, the helper class automatically handles accessibility 6656eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * focus management by adding the appropriate 6666eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS} or 6676eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 6686eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * action. Implementations must <b>never</b> manually add these actions. 6696eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6706eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * The helper class also automatically modifies parent- and 6716eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * screen-relative bounds to reflect the portion of the item visible 6726eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * within its parent. 6736eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 6746eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view identifier of the item for 6756eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * which to populate the node 6766eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param node The node to populate 6776eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 6786eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette protected abstract void onPopulateNodeForVirtualView( 6796eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette int virtualViewId, AccessibilityNodeInfoCompat node); 6806eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 6816eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 6826eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Performs the specified accessibility action on the item associated 6836eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * with the virtual view identifier. See 6846eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#performAction(int, Bundle)} for 6856eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * more information. 6866eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6876eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Implementations <b>must</b> handle any actions added manually in 6886eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link #onPopulateNodeForVirtualView}. 6896eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * <p> 6906eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * The helper class automatically handles focus management resulting 6916eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * from {@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS} 6926eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * and 6936eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 6946eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * actions. 6956eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * 6966eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param virtualViewId The virtual view identifier of the item on which 6976eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * to perform the action 6986eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param action The accessibility action to perform 6996eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @param arguments (Optional) A bundle with additional arguments, or 7006eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * null 7016eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * @return true if the action was performed 7026eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 7036eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette protected abstract boolean onPerformActionForVirtualView( 7046eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette int virtualViewId, int action, Bundle arguments); 7056eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 7066eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette /** 7076eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * Exposes a virtual view hierarchy to the accessibility framework. Only 7086eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette * used in API 16+. 7096eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette */ 7106eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette private class ExploreByTouchNodeProvider extends AccessibilityNodeProviderCompat { 7116eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette @Override 7126eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) { 7136eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return ExploreByTouchHelper.this.createNode(virtualViewId); 7146eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 7156eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette 7166eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette @Override 7176eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette public boolean performAction(int virtualViewId, int action, Bundle arguments) { 7186eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments); 7196eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 7206eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette } 7216eb3cdf42d5382aef6b6a6afd7c305dbc27885b9Alan Viverette} 722