1bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/* 2bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Copyright (C) 2013 The Android Open Source Project 3bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 4bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Licensed under the Apache License, Version 2.0 (the "License"); 5bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * you may not use this file except in compliance with the License. 6bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You may obtain a copy of the License at 7bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 8bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * http://www.apache.org/licenses/LICENSE-2.0 9bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 10bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Unless required by applicable law or agreed to in writing, software 11bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * distributed under the License is distributed on an "AS IS" BASIS, 12bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * See the License for the specific language governing permissions and 14bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * limitations under the License. 15bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 16bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 17bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopackage com.android.internal.widget; 18bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 19bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.content.Context; 20bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.graphics.Rect; 21bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.os.Bundle; 22ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.util.IntArray; 23bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.MotionEvent; 24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View; 25bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.ViewParent; 26bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 27bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityManager; 28bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeInfo; 29ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 30bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeProvider; 31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/** 33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ExploreByTouchHelper is a utility class for implementing accessibility 34bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * support in custom {@link android.view.View}s that represent a collection of View-like 35bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * logical items. It extends {@link android.view.accessibility.AccessibilityNodeProvider} and 36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * simplifies many aspects of providing information to accessibility services 37bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * and managing accessibility focus. This class does not currently support 38bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * hierarchies of logical items. 39bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 40bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * This should be applied to the parent view using 41bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link android.view.View#setAccessibilityDelegate}: 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <pre> 44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * mAccessHelper = ExploreByTouchHelper.create(someView, mAccessHelperCallback); 45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ViewCompat.setAccessibilityDelegate(someView, mAccessHelper); 46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </pre> 47bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 48bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopublic abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { 49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Virtual node identifier value for invalid nodes. */ 50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public static final int INVALID_ID = Integer.MIN_VALUE; 51bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 52961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette /** Virtual node identifier value for the host view's node. */ 53961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette public static final int HOST_ID = View.NO_ID; 54961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette 55bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Default class name used for virtual views. */ 56bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String DEFAULT_CLASS_NAME = View.class.getName(); 57bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 587a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette /** Default bounds used to determine if the client didn't set any. */ 597a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette private static final Rect INVALID_PARENT_BOUNDS = new Rect( 607a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); 617a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette 62ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // Lazily-created temporary data structures used when creating nodes. 63ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private Rect mTempScreenRect; 64ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private Rect mTempParentRect; 65ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int[] mTempGlobalRect; 66ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 67ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Lazily-created temporary data structure used to compute visibility. */ 68ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private Rect mTempVisibleRect; 69bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 70ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Lazily-created temporary data structure used to obtain child IDs. */ 71ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private IntArray mTempArray; 72bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 73bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** System accessibility manager, used to check state and send events. */ 74bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final AccessibilityManager mManager; 75bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** View whose internal structure is exposed through this helper. */ 77bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final View mView; 78bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 79ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Context of the host view. **/ 80ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final Context mContext; 81ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 82bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Node provider that handles creating nodes and performing actions. */ 83bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private ExploreByTouchNodeProvider mNodeProvider; 84bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 85bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Virtual view id for the currently focused logical item. */ 86bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mFocusedVirtualViewId = INVALID_ID; 87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Virtual view id for the currently hovered logical item. */ 89bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mHoveredVirtualViewId = INVALID_ID; 90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 91bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 92bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Factory method to create a new {@link ExploreByTouchHelper}. 93bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 94bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param forView View whose logical children are exposed by this helper. 95bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 96bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public ExploreByTouchHelper(View forView) { 97bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (forView == null) { 98bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new IllegalArgumentException("View may not be null"); 99bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 100bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 101bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mView = forView; 102bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mContext = forView.getContext(); 103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 104bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 105bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 106bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 107bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Returns the {@link android.view.accessibility.AccessibilityNodeProvider} for this helper. 108bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param host View whose logical children are exposed by this helper. 110bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return The accessibility node provider for this helper. 111bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 112bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 113bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 114bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mNodeProvider == null) { 115bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNodeProvider = new ExploreByTouchNodeProvider(); 116bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 117bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mNodeProvider; 118bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 119bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 120bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 121bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Dispatches hover {@link android.view.MotionEvent}s to the virtual view hierarchy when 122bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the Explore by Touch feature is enabled. 123bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 124bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * This method should be called by overriding 125bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link View#dispatchHoverEvent}: 126bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 127bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <pre>@Override 128bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * public boolean dispatchHoverEvent(MotionEvent event) { 129bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * if (mHelper.dispatchHoverEvent(this, event) { 130bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * return true; 131bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * } 132bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * return super.dispatchHoverEvent(event); 133bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * } 134bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </pre> 135bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 136bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param event The hover event to dispatch to the virtual view hierarchy. 137bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether the hover event was handled. 138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 139bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean dispatchHoverEvent(MotionEvent event) { 140bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!mManager.isEnabled() || !mManager.isTouchExplorationEnabled()) { 141bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 142bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 143bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 144bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (event.getAction()) { 145bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_HOVER_MOVE: 146bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_HOVER_ENTER: 147bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int virtualViewId = getVirtualViewAt(event.getX(), event.getY()); 148bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio updateHoveredVirtualView(virtualViewId); 149bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (virtualViewId != INVALID_ID); 150bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_HOVER_EXIT: 151bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mFocusedVirtualViewId != INVALID_ID) { 152bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio updateHoveredVirtualView(INVALID_ID); 153bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 154bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 155bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 156bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 157bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 158bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 161bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 162bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates an event of the specified type with information about an item 163bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * and attempts to send it up through the view hierarchy. 164bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 165bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You should call this method after performing a user action that normally 166bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * fires an accessibility event, such as clicking on an item. 167bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 168bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <pre>public void performItemClick(T item) { 169bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ... 170bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * sendEventForVirtualViewId(item.id, AccessibilityEvent.TYPE_VIEW_CLICKED); 171bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * } 172bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </pre> 173bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 174bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for which to send an event. 175bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to send. 176bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return true if the event was sent successfully. 177bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 178bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean sendEventForVirtualView(int virtualViewId, int eventType) { 179bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((virtualViewId == INVALID_ID) || !mManager.isEnabled()) { 180bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 181bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 182bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 183bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final ViewParent parent = mView.getParent(); 184bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (parent == null) { 185bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 186bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 187bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 188bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityEvent event = createEvent(virtualViewId, eventType); 189bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return parent.requestSendAccessibilityEvent(mView, event); 190bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 191bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 192bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 193bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Notifies the accessibility framework that the properties of the parent 194bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * view have changed. 195bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 196bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You <b>must</b> call this method after adding or removing items from the 197bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * parent view. 198bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 199bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void invalidateRoot() { 200961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette invalidateVirtualView(HOST_ID, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 201bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 202bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 203bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 204bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Notifies the accessibility framework that the properties of a particular 205bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * item have changed. 206bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 207bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You <b>must</b> call this method after changing any of the properties set 208bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * in {@link #onPopulateNodeForVirtualView}. 209bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 210961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * @param virtualViewId The virtual view id to invalidate, or 211961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * {@link #HOST_ID} to invalidate the root view. 212961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * @see #invalidateVirtualView(int, int) 213bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 214bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void invalidateVirtualView(int virtualViewId) { 215961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette invalidateVirtualView(virtualViewId, 216961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 217961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette } 218961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette 219961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette /** 220961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * Notifies the accessibility framework that the properties of a particular 221961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * item have changed. 222961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * <p> 223961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * You <b>must</b> call this method after changing any of the properties set 224961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * in {@link #onPopulateNodeForVirtualView}. 225961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * 226961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * @param virtualViewId The virtual view id to invalidate, or 227961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * {@link #HOST_ID} to invalidate the root view. 228961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * @param changeTypes The bit mask of change types. May be {@code 0} for the 229961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * default (undefined) change type or one or more of: 230961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * <ul> 231961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION} 232961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE} 233961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT} 234961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED} 235961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * </ul> 236961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette */ 237961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette public void invalidateVirtualView(int virtualViewId, int changeTypes) { 238961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette if (virtualViewId != INVALID_ID && mManager.isEnabled()) { 239961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette final ViewParent parent = mView.getParent(); 240961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette if (parent != null) { 241961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette final AccessibilityEvent event = createEvent(virtualViewId, 242961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 243961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette event.setContentChangeTypes(changeTypes); 244961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette parent.requestSendAccessibilityEvent(mView, event); 245961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette } 246961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette } 247bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 248bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 249bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 250bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Returns the virtual view id for the currently focused item, 251bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 252bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return A virtual view id, or {@link #INVALID_ID} if no item is 253bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * currently focused. 254bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 255bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public int getFocusedVirtualView() { 256bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mFocusedVirtualViewId; 257bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 258bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 259bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 260bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Sets the currently hovered item, sending hover accessibility events as 261bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * necessary to maintain the correct state. 262bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 263bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item currently being 264bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * hovered, or {@link #INVALID_ID} if no item is hovered within 265bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the parent view. 266bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 267bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void updateHoveredVirtualView(int virtualViewId) { 268bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mHoveredVirtualViewId == virtualViewId) { 269bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return; 270bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 271bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 272bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int previousVirtualViewId = mHoveredVirtualViewId; 273bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mHoveredVirtualViewId = virtualViewId; 274bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 275bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Stay consistent with framework behavior by sending ENTER/EXIT pairs 276bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // in reverse order. This is accurate as of API 18. 277bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 278bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(previousVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 279bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 280bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 281bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 282bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityEvent} for the specified 283961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * virtual view id, which includes the host view ({@link #HOST_ID}). 284bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 285bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 286bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * construct an event. 287bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to construct. 288bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityEvent} populated with information about 289bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the specified item. 290bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 291bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityEvent createEvent(int virtualViewId, int eventType) { 292bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (virtualViewId) { 293961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette case HOST_ID: 294bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createEventForHost(eventType); 295bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 296bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createEventForChild(virtualViewId, eventType); 297bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 298bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 299bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 300bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 301bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityEvent} for the host node. 302bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 303bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to construct. 304bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityEvent} populated with information about 305bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the specified item. 306bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 307bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityEvent createEventForHost(int eventType) { 308bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 309a6786d66239568d7b97825b5205a37e22c76e8d6Maurice Lam mView.onInitializeAccessibilityEvent(event); 310740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette 311740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette // Allow the client to populate the event. 312740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette onPopulateEventForHost(event); 313740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette 314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return event; 315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 316bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 317bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 318bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityEvent} populated with 319bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * information about the specified item. 320bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 321bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 322bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * construct an event. 323bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to construct. 324bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityEvent} populated with information about 325bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the specified item. 326bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 327bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityEvent createEventForChild(int virtualViewId, int eventType) { 328bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 329bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setEnabled(true); 330bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setClassName(DEFAULT_CLASS_NAME); 331bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 332bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Allow the client to populate the event. 333bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onPopulateEventForVirtualView(virtualViewId, event); 334bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 335bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Make sure the developer is following the rules. 336bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (event.getText().isEmpty() && (event.getContentDescription() == null)) { 337bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must add text or a content description in " 338bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateEventForVirtualViewId()"); 339bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 340bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 341bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Don't allow the client to override these properties. 342bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setPackageName(mView.getContext().getPackageName()); 343bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setSource(mView, virtualViewId); 344bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 345bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return event; 346bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 347bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 348bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 349bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link android.view.accessibility.AccessibilityNodeInfo} for the 350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specified virtual view id, which includes the host view 351961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * ({@link #HOST_ID}). 352bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 353bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 354bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * construct a node. 355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link android.view.accessibility.AccessibilityNodeInfo} populated with information 356bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * about the specified item. 357bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 358bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityNodeInfo createNode(int virtualViewId) { 359bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (virtualViewId) { 360961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette case HOST_ID: 361bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createNodeForHost(); 362bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 363bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createNodeForChild(virtualViewId); 364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 365bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 366bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 367bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 368bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityNodeInfo} for the 369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * host view populated with its virtual descendants. 370bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 371bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityNodeInfo} for the parent node. 372bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 373bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityNodeInfo createNodeForHost() { 374bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(mView); 375a6786d66239568d7b97825b5205a37e22c76e8d6Maurice Lam mView.onInitializeAccessibilityNodeInfo(node); 376740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette final int realNodeCount = node.getChildCount(); 377740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette 378740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette // Allow the client to populate the host node. 379740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette onPopulateNodeForHost(node); 380bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 381bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Add the virtual descendants. 382ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mTempArray == null) { 383ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempArray = new IntArray(); 384ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 385ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempArray.clear(); 386ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 387ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final IntArray virtualViewIds = mTempArray; 388bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getVisibleVirtualViews(virtualViewIds); 389740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette if (realNodeCount > 0 && virtualViewIds.size() > 0) { 390740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette throw new RuntimeException("Views cannot have both real and virtual children"); 391740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette } 392bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 393ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int N = virtualViewIds.size(); 394ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette for (int i = 0; i < N; i++) { 395ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addChild(mView, virtualViewIds.get(i)); 396bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 397bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 398bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return node; 399bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 400bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 401bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 402bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityNodeInfo} for the 403bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specified item. Automatically manages accessibility focus actions. 404bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 405bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Allows the implementing class to specify most node properties, but 406bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * overrides the following: 407bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 408bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setPackageName} 409bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setClassName} 410bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setParent(View)} 411bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setSource(View, int)} 412bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setVisibleToUser} 413bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)} 414bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 415bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 416bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Uses the bounds of the parent view and the parent-relative bounding 417bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * rectangle specified by 418bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#getBoundsInParent} to automatically 419bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * update the following properties: 420bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 421bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setVisibleToUser} 422bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setBoundsInParent} 423bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 424bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 425bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for item for which to construct 426bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * a node. 427bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityNodeInfo} for the specified item. 428bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 429bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityNodeInfo createNodeForChild(int virtualViewId) { 430ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette ensureTempRects(); 431ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final Rect tempParentRect = mTempParentRect; 432ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int[] tempGlobalRect = mTempGlobalRect; 433ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final Rect tempScreenRect = mTempScreenRect; 434ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 435bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(); 436bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 437bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Ensure the client has good defaults. 438bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setEnabled(true); 439bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setClassName(DEFAULT_CLASS_NAME); 4407a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette node.setBoundsInParent(INVALID_PARENT_BOUNDS); 441bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 442bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Allow the client to populate the node. 443bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onPopulateNodeForVirtualView(virtualViewId, node); 444bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 445bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Make sure the developer is following the rules. 446bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((node.getText() == null) && (node.getContentDescription() == null)) { 447bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must add text or a content description in " 448bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 449bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 450bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 451ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.getBoundsInParent(tempParentRect); 452ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (tempParentRect.equals(INVALID_PARENT_BOUNDS)) { 453bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must set parent bounds in " 454bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 455bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 456bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 457bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int actions = node.getActions(); 458bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((actions & AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) != 0) { 459bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in " 460bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 461bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 462bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((actions & AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) { 463bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in " 464bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 465bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 466bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 467bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Don't allow the client to override these properties. 468bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setPackageName(mView.getContext().getPackageName()); 469bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setSource(mView, virtualViewId); 470bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setParent(mView); 471bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 472bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Manage internal accessibility focus state. 473bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mFocusedVirtualViewId == virtualViewId) { 474bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setAccessibilityFocused(true); 475ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 476bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 477bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setAccessibilityFocused(false); 478ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); 479bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 480bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 481bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Set the visibility based on the parent bound. 482ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (intersectVisibleToUser(tempParentRect)) { 483bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setVisibleToUser(true); 484ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setBoundsInParent(tempParentRect); 485bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 486bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 487bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Calculate screen-relative bound. 488ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mView.getLocationOnScreen(tempGlobalRect); 489ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int offsetX = tempGlobalRect[0]; 490ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int offsetY = tempGlobalRect[1]; 491ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette tempScreenRect.set(tempParentRect); 492ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette tempScreenRect.offset(offsetX, offsetY); 493ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setBoundsInScreen(tempScreenRect); 494bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 495bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return node; 496bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 497bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 498ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private void ensureTempRects() { 499ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempGlobalRect = new int[2]; 500ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempParentRect = new Rect(); 501ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempScreenRect = new Rect(); 502ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 503ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 504bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean performAction(int virtualViewId, int action, Bundle arguments) { 505bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (virtualViewId) { 506961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette case HOST_ID: 507bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return performActionForHost(action, arguments); 508bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 509bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return performActionForChild(virtualViewId, action, arguments); 510bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 511bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 512bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 513bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean performActionForHost(int action, Bundle arguments) { 514a6786d66239568d7b97825b5205a37e22c76e8d6Maurice Lam return mView.performAccessibilityAction(action, arguments); 515bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 516bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 517bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) { 518bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 519bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: 520bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: 521ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return manageFocusForChild(virtualViewId, action); 522bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 523bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return onPerformActionForVirtualView(virtualViewId, action, arguments); 524bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 525bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 526bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 527ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private boolean manageFocusForChild(int virtualViewId, int action) { 528bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 529bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: 530bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return requestAccessibilityFocus(virtualViewId); 531bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: 532bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return clearAccessibilityFocus(virtualViewId); 533bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 534bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 535bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 536bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 537bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 538bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 539bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Computes whether the specified {@link Rect} intersects with the visible 540bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * portion of its parent {@link View}. Modifies {@code localRect} to contain 541bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * only the visible portion. 542bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param localRect A rectangle in local (parent) coordinates. 544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether the specified {@link Rect} is visible on the screen. 545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 546bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean intersectVisibleToUser(Rect localRect) { 547bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Missing or empty bounds mean this view is not visible. 548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((localRect == null) || localRect.isEmpty()) { 549bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 550bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 551bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 552bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Attached to invisible window means this view is not visible. 553bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mView.getWindowVisibility() != View.VISIBLE) { 554bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 555bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 556bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 557bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // An invisible predecessor means that this view is not visible. 558bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio ViewParent viewParent = mView.getParent(); 559bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio while (viewParent instanceof View) { 560bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final View view = (View) viewParent; 561bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((view.getAlpha() <= 0) || (view.getVisibility() != View.VISIBLE)) { 562bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 563bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 564bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio viewParent = view.getParent(); 565bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 566bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 567bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // A null parent implies the view is not visible. 568bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (viewParent == null) { 569bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 570bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // If no portion of the parent is visible, this view is not visible. 573ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mTempVisibleRect == null) { 574ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempVisibleRect = new Rect(); 575ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 576ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final Rect tempVisibleRect = mTempVisibleRect; 577ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (!mView.getLocalVisibleRect(tempVisibleRect)) { 578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 580bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 581bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Check if the view intersects the visible portion of the parent. 582ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return localRect.intersect(tempVisibleRect); 583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Returns whether this virtual view is accessibility focused. 587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return True if the view is accessibility focused. 589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean isAccessibilityFocused(int virtualViewId) { 591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (mFocusedVirtualViewId == virtualViewId); 592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 595bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Attempts to give accessibility focus to a virtual view. 596bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 597bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * A virtual view will not actually take focus if 598bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityManager#isEnabled()} returns false, 599bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityManager#isTouchExplorationEnabled()} returns false, 600bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * or the view already has accessibility focus. 601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 602bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The id of the virtual view on which to place 603bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * accessibility focus. 604bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether this virtual view actually took accessibility focus. 605bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 606bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean requestAccessibilityFocus(int virtualViewId) { 607bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityManager accessibilityManager = 608bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 609bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 610bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!mManager.isEnabled() 611bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio || !accessibilityManager.isTouchExplorationEnabled()) { 612bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 613bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 614bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // TODO: Check virtual view visibility. 615bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!isAccessibilityFocused(virtualViewId)) { 61691d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette // Clear focus from the previously focused view, if applicable. 61791d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette if (mFocusedVirtualViewId != INVALID_ID) { 61891d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette sendEventForVirtualView(mFocusedVirtualViewId, 61991d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 62091d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette } 62191d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette 62291d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette // Set focus on the new view. 623bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mFocusedVirtualViewId = virtualViewId; 62491d415d863de73430af100ebd1b4f5b3b795e8d1Alan Viverette 625bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // TODO: Only invalidate virtual view bounds. 626bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mView.invalidate(); 627bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, 628bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 629bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 630bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 631bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 632bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 633bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 634bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 635bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Attempts to clear accessibility focus from a virtual view. 636bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 637bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The id of the virtual view from which to clear 638bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * accessibility focus. 639bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether this virtual view actually cleared accessibility focus. 640bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 641bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean clearAccessibilityFocus(int virtualViewId) { 642bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (isAccessibilityFocused(virtualViewId)) { 643bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mFocusedVirtualViewId = INVALID_ID; 644bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mView.invalidate(); 645bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, 646bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 647bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 648bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 649bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 650bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 651bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 652bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 653bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Provides a mapping between view-relative coordinates and logical 654bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * items. 655bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 656bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param x The view-relative x coordinate 657bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param y The view-relative y coordinate 658bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return virtual view identifier for the logical item under 659bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * coordinates (x,y) 660bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 661bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract int getVirtualViewAt(float x, float y); 662bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 663bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 664bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates a list with the view's visible items. The ordering of items 665bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within {@code virtualViewIds} specifies order of accessibility focus 666bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * traversal. 667bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 668bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewIds The list to populate with visible items 669bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 670ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected abstract void getVisibleVirtualViews(IntArray virtualViewIds); 671bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 672bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 673bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates an {@link AccessibilityEvent} with information about the 674bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specified item. 675bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 676bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Implementations <b>must</b> populate the following required fields: 677bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 678bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>event text, see {@link AccessibilityEvent#getText} or 679bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityEvent#setContentDescription} 680bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 681bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 682bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class automatically populates the following fields with 683bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * default values, but implementations may optionally override them: 684bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 685bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>item class name, set to android.view.View, see 686bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityEvent#setClassName} 687bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 688bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 689bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The following required fields are automatically populated by the 690bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * helper class and may not be overridden: 691bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 692bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>package name, set to the package of the host view's 693bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link Context}, see {@link AccessibilityEvent#setPackageName} 694bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>event source, set to the host view and virtual view identifier, 695961cdbf10fdc8fed3808471f08a080fbd38a19afAlan Viverette * see {@link android.view.accessibility.AccessibilityRecord#setSource(View, int)} 696bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 697bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 698bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 699bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * populate the event 700bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param event The event to populate 701bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 702bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract void onPopulateEventForVirtualView( 703bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int virtualViewId, AccessibilityEvent event); 704bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 705bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 706740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * Populates an {@link AccessibilityEvent} with information about the host 707740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * view. 708740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * <p> 709740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * The default implementation is a no-op. 710740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * 711740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * @param event the event to populate with information about the host view 712740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette */ 713740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette protected void onPopulateEventForHost(AccessibilityEvent event) { 714740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette // Default implementation is no-op. 715740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette } 716740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette 717740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette /** 718bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates an {@link AccessibilityNodeInfo} with information 719bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * about the specified item. 720bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 721bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Implementations <b>must</b> populate the following required fields: 722bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 723bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>event text, see {@link AccessibilityNodeInfo#setText} or 724bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setContentDescription} 725bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>bounds in parent coordinates, see 726bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setBoundsInParent} 727bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 728bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 729bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class automatically populates the following fields with 730bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * default values, but implementations may optionally override them: 731bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 732bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>enabled state, set to true, see 733bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setEnabled} 734bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>item class name, identical to the class name set by 735bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateEventForVirtualView}, see 736bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setClassName} 737bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 738bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 739bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The following required fields are automatically populated by the 740bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * helper class and may not be overridden: 741bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 742bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>package name, identical to the package name set by 743bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateEventForVirtualView}, see 744bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setPackageName} 745bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>node source, identical to the event source set in 746bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateEventForVirtualView}, see 747bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setSource(View, int)} 748bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>parent view, set to the host view, see 749bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setParent(View)} 750bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>visibility, computed based on parent-relative bounds, see 751bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setVisibleToUser} 752bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>accessibility focus, computed based on internal helper state, see 753bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setAccessibilityFocused} 754bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>bounds in screen coordinates, computed based on host view bounds, 755bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * see {@link AccessibilityNodeInfo#setBoundsInScreen} 756bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 757bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 758bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Additionally, the helper class automatically handles accessibility 759bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * focus management by adding the appropriate 760bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS} or 761bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 762bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * action. Implementations must <b>never</b> manually add these actions. 763bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 764bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class also automatically modifies parent- and 765bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * screen-relative bounds to reflect the portion of the item visible 766bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within its parent. 767bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 768bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view identifier of the item for 769bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * which to populate the node 770bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param node The node to populate 771bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 772bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract void onPopulateNodeForVirtualView( 773bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int virtualViewId, AccessibilityNodeInfo node); 774bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 775bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 776740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * Populates an {@link AccessibilityNodeInfo} with information about the 777740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * host view. 778740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * <p> 779740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * The default implementation is a no-op. 780740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * 781740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette * @param node the node to populate with information about the host view 782740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette */ 783740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette protected void onPopulateNodeForHost(AccessibilityNodeInfo node) { 784740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette // Default implementation is no-op. 785740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette } 786740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette 787740b9397fbeea1722afc5a66215ef8fac2bd6bc4Alan Viverette /** 788bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Performs the specified accessibility action on the item associated 789bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * with the virtual view identifier. See 790bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#performAction(int, Bundle)} for 791bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * more information. 792bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 793bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Implementations <b>must</b> handle any actions added manually in 794bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateNodeForVirtualView}. 795bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 796bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class automatically handles focus management resulting 797bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * from {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS} 798bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * and 799bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 800bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * actions. 801bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 802bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view identifier of the item on which 803bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * to perform the action 804bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param action The accessibility action to perform 805bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param arguments (Optional) A bundle with additional arguments, or 806bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * null 807bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return true if the action was performed 808bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 809bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract boolean onPerformActionForVirtualView( 810bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int virtualViewId, int action, Bundle arguments); 811bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 812bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 813bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Exposes a virtual view hierarchy to the accessibility framework. Only 814bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * used in API 16+. 815bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 816bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class ExploreByTouchNodeProvider extends AccessibilityNodeProvider { 817bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 818bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 819bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.this.createNode(virtualViewId); 820bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 821bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 822bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 823bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean performAction(int virtualViewId, int action, Bundle arguments) { 824bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments); 825bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 826bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 827bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio} 828