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.accessibility.*; 24bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.MotionEvent; 25bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.View; 26bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.ViewParent; 27bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityEvent; 28bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityManager; 29bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeInfo; 30ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viveretteimport android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 31bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglioimport android.view.accessibility.AccessibilityNodeProvider; 32bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 33bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio/** 34bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ExploreByTouchHelper is a utility class for implementing accessibility 35bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * support in custom {@link android.view.View}s that represent a collection of View-like 36bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * logical items. It extends {@link android.view.accessibility.AccessibilityNodeProvider} and 37bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * simplifies many aspects of providing information to accessibility services 38bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * and managing accessibility focus. This class does not currently support 39bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * hierarchies of logical items. 40bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 41bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * This should be applied to the parent view using 42bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link android.view.View#setAccessibilityDelegate}: 43bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 44bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <pre> 45bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * mAccessHelper = ExploreByTouchHelper.create(someView, mAccessHelperCallback); 46bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ViewCompat.setAccessibilityDelegate(someView, mAccessHelper); 47bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </pre> 48bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 49bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Megliopublic abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { 50bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Virtual node identifier value for invalid nodes. */ 51bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public static final int INVALID_ID = Integer.MIN_VALUE; 52bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 53bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Default class name used for virtual views. */ 54bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private static final String DEFAULT_CLASS_NAME = View.class.getName(); 55bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 567a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette /** Default bounds used to determine if the client didn't set any. */ 577a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette private static final Rect INVALID_PARENT_BOUNDS = new Rect( 587a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); 597a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette 60ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette // Lazily-created temporary data structures used when creating nodes. 61ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private Rect mTempScreenRect; 62ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private Rect mTempParentRect; 63ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private int[] mTempGlobalRect; 64ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 65ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Lazily-created temporary data structure used to compute visibility. */ 66ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private Rect mTempVisibleRect; 67bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 68ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Lazily-created temporary data structure used to obtain child IDs. */ 69ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private IntArray mTempArray; 70bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 71bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** System accessibility manager, used to check state and send events. */ 72bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final AccessibilityManager mManager; 73bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 74bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** View whose internal structure is exposed through this helper. */ 75bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private final View mView; 76bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 77ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette /** Context of the host view. **/ 78ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private final Context mContext; 79ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 80bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Node provider that handles creating nodes and performing actions. */ 81bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private ExploreByTouchNodeProvider mNodeProvider; 82bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 83bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Virtual view id for the currently focused logical item. */ 84bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mFocusedVirtualViewId = INVALID_ID; 85bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 86bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** Virtual view id for the currently hovered logical item. */ 87bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private int mHoveredVirtualViewId = INVALID_ID; 88bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 89bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 90bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Factory method to create a new {@link ExploreByTouchHelper}. 91bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 92bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param forView View whose logical children are exposed by this helper. 93bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 94bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public ExploreByTouchHelper(View forView) { 95bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (forView == null) { 96bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new IllegalArgumentException("View may not be null"); 97bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 98bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 99bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mView = forView; 100bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mContext = forView.getContext(); 101bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 102bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 103bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 104bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 105bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Returns the {@link android.view.accessibility.AccessibilityNodeProvider} for this helper. 106bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 107bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param host View whose logical children are exposed by this helper. 108bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return The accessibility node provider for this helper. 109bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 110bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 111bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 112bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mNodeProvider == null) { 113bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mNodeProvider = new ExploreByTouchNodeProvider(); 114bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 115bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mNodeProvider; 116bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 117bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 118bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 119bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Dispatches hover {@link android.view.MotionEvent}s to the virtual view hierarchy when 120bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the Explore by Touch feature is enabled. 121bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 122bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * This method should be called by overriding 123bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link View#dispatchHoverEvent}: 124bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 125bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <pre>@Override 126bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * public boolean dispatchHoverEvent(MotionEvent event) { 127bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * if (mHelper.dispatchHoverEvent(this, event) { 128bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * return true; 129bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * } 130bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * return super.dispatchHoverEvent(event); 131bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * } 132bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </pre> 133bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 134bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param event The hover event to dispatch to the virtual view hierarchy. 135bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether the hover event was handled. 136bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 137bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean dispatchHoverEvent(MotionEvent event) { 138bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!mManager.isEnabled() || !mManager.isTouchExplorationEnabled()) { 139bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 140bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 141bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 142bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (event.getAction()) { 143bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_HOVER_MOVE: 144bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_HOVER_ENTER: 145bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int virtualViewId = getVirtualViewAt(event.getX(), event.getY()); 146bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio updateHoveredVirtualView(virtualViewId); 147bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (virtualViewId != INVALID_ID); 148bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case MotionEvent.ACTION_HOVER_EXIT: 149bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mFocusedVirtualViewId != INVALID_ID) { 150bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio updateHoveredVirtualView(INVALID_ID); 151bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 152bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 153bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 154bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 155bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 156bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 157bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 158bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 159bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 160bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates an event of the specified type with information about an item 161bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * and attempts to send it up through the view hierarchy. 162bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 163bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You should call this method after performing a user action that normally 164bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * fires an accessibility event, such as clicking on an item. 165bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 166bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <pre>public void performItemClick(T item) { 167bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ... 168bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * sendEventForVirtualViewId(item.id, AccessibilityEvent.TYPE_VIEW_CLICKED); 169bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * } 170bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </pre> 171bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 172bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for which to send an event. 173bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to send. 174bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return true if the event was sent successfully. 175bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 176bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean sendEventForVirtualView(int virtualViewId, int eventType) { 177bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((virtualViewId == INVALID_ID) || !mManager.isEnabled()) { 178bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 179bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 180bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 181bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final ViewParent parent = mView.getParent(); 182bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (parent == null) { 183bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 184bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 185bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 186bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityEvent event = createEvent(virtualViewId, eventType); 187bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return parent.requestSendAccessibilityEvent(mView, event); 188bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 189bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 190bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 191bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Notifies the accessibility framework that the properties of the parent 192bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * view have changed. 193bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 194bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You <b>must</b> call this method after adding or removing items from the 195bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * parent view. 196bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 197bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void invalidateRoot() { 198bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio invalidateVirtualView(View.NO_ID); 199bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 200bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 201bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 202bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Notifies the accessibility framework that the properties of a particular 203bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * item have changed. 204bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 205bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * You <b>must</b> call this method after changing any of the properties set 206bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * in {@link #onPopulateNodeForVirtualView}. 207bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 208bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id to invalidate. 209bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 210bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public void invalidateVirtualView(int virtualViewId) { 211bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 212bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 213bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 214bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 215bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Returns the virtual view id for the currently focused item, 216bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 217bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return A virtual view id, or {@link #INVALID_ID} if no item is 218bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * currently focused. 219bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 220bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public int getFocusedVirtualView() { 221bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return mFocusedVirtualViewId; 222bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 223bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 224bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 225bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Sets the currently hovered item, sending hover accessibility events as 226bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * necessary to maintain the correct state. 227bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 228bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item currently being 229bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * hovered, or {@link #INVALID_ID} if no item is hovered within 230bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the parent view. 231bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 232bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private void updateHoveredVirtualView(int virtualViewId) { 233bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mHoveredVirtualViewId == virtualViewId) { 234bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return; 235bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 236bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 237bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int previousVirtualViewId = mHoveredVirtualViewId; 238bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mHoveredVirtualViewId = virtualViewId; 239bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 240bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Stay consistent with framework behavior by sending ENTER/EXIT pairs 241bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // in reverse order. This is accurate as of API 18. 242bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 243bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(previousVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 244bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 245bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 246bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 247bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityEvent} for the specified 248bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * virtual view id, which includes the host view ({@link View#NO_ID}). 249bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 250bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 251bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * construct an event. 252bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to construct. 253bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityEvent} populated with information about 254bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the specified item. 255bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 256bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityEvent createEvent(int virtualViewId, int eventType) { 257bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (virtualViewId) { 258bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case View.NO_ID: 259bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createEventForHost(eventType); 260bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 261bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createEventForChild(virtualViewId, eventType); 262bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 263bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 264bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 265bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 266bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityEvent} for the host node. 267bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 268bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to construct. 269bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityEvent} populated with information about 270bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the specified item. 271bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 272bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityEvent createEventForHost(int eventType) { 273bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 274bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onInitializeAccessibilityEvent(mView, event); 275bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return event; 276bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 277bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 278bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 279bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityEvent} populated with 280bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * information about the specified item. 281bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 282bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 283bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * construct an event. 284bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param eventType The type of event to construct. 285bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityEvent} populated with information about 286bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * the specified item. 287bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 288bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityEvent createEventForChild(int virtualViewId, int eventType) { 289bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 290bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setEnabled(true); 291bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setClassName(DEFAULT_CLASS_NAME); 292bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 293bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Allow the client to populate the event. 294bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onPopulateEventForVirtualView(virtualViewId, event); 295bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 296bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Make sure the developer is following the rules. 297bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (event.getText().isEmpty() && (event.getContentDescription() == null)) { 298bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must add text or a content description in " 299bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateEventForVirtualViewId()"); 300bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 301bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 302bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Don't allow the client to override these properties. 303bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setPackageName(mView.getContext().getPackageName()); 304bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio event.setSource(mView, virtualViewId); 305bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 306bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return event; 307bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 308bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 309bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 310bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link android.view.accessibility.AccessibilityNodeInfo} for the 311bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specified virtual view id, which includes the host view 312bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * ({@link View#NO_ID}). 313bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 314bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 315bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * construct a node. 316bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link android.view.accessibility.AccessibilityNodeInfo} populated with information 317bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * about the specified item. 318bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 319bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityNodeInfo createNode(int virtualViewId) { 320bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (virtualViewId) { 321bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case View.NO_ID: 322bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createNodeForHost(); 323bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 324bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return createNodeForChild(virtualViewId); 325bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 326bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 327bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 328bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 329bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityNodeInfo} for the 330bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * host view populated with its virtual descendants. 331bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 332bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityNodeInfo} for the parent node. 333bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 334bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityNodeInfo createNodeForHost() { 335bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(mView); 336bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onInitializeAccessibilityNodeInfo(mView, node); 337bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 338bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Add the virtual descendants. 339ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mTempArray == null) { 340ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempArray = new IntArray(); 341ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } else { 342ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempArray.clear(); 343ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 344ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final IntArray virtualViewIds = mTempArray; 345bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio getVisibleVirtualViews(virtualViewIds); 346bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 347ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int N = virtualViewIds.size(); 348ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette for (int i = 0; i < N; i++) { 349ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addChild(mView, virtualViewIds.get(i)); 350bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 351bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 352bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return node; 353bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 354bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 355bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 356bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Constructs and returns an {@link AccessibilityNodeInfo} for the 357bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specified item. Automatically manages accessibility focus actions. 358bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 359bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Allows the implementing class to specify most node properties, but 360bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * overrides the following: 361bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 362bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setPackageName} 363bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setClassName} 364bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setParent(View)} 365bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setSource(View, int)} 366bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setVisibleToUser} 367bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)} 368bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 369bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 370bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Uses the bounds of the parent view and the parent-relative bounding 371bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * rectangle specified by 372bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#getBoundsInParent} to automatically 373bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * update the following properties: 374bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 375bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setVisibleToUser} 376bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>{@link AccessibilityNodeInfo#setBoundsInParent} 377bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 378bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 379bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for item for which to construct 380bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * a node. 381bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return An {@link AccessibilityNodeInfo} for the specified item. 382bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 383bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private AccessibilityNodeInfo createNodeForChild(int virtualViewId) { 384ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette ensureTempRects(); 385ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final Rect tempParentRect = mTempParentRect; 386ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int[] tempGlobalRect = mTempGlobalRect; 387ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final Rect tempScreenRect = mTempScreenRect; 388ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 389bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(); 390bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 391bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Ensure the client has good defaults. 392bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setEnabled(true); 393bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setClassName(DEFAULT_CLASS_NAME); 3947a81bd82f4d05e6843e4a9743e194cceb0c2d2e1Alan Viverette node.setBoundsInParent(INVALID_PARENT_BOUNDS); 395bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 396bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Allow the client to populate the node. 397bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio onPopulateNodeForVirtualView(virtualViewId, node); 398bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 399bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Make sure the developer is following the rules. 400bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((node.getText() == null) && (node.getContentDescription() == null)) { 401bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must add text or a content description in " 402bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 403bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 404bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 405ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.getBoundsInParent(tempParentRect); 406ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (tempParentRect.equals(INVALID_PARENT_BOUNDS)) { 407bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must set parent bounds in " 408bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 409bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 410bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 411bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final int actions = node.getActions(); 412bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((actions & AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) != 0) { 413bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in " 414bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 415bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 416bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((actions & AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) { 417bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in " 418bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio + "populateNodeForVirtualViewId()"); 419bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 420bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 421bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Don't allow the client to override these properties. 422bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setPackageName(mView.getContext().getPackageName()); 423bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setSource(mView, virtualViewId); 424bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setParent(mView); 425bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 426bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Manage internal accessibility focus state. 427bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mFocusedVirtualViewId == virtualViewId) { 428bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setAccessibilityFocused(true); 429ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 430bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } else { 431bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setAccessibilityFocused(false); 432ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); 433bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 434bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 435bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Set the visibility based on the parent bound. 436ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (intersectVisibleToUser(tempParentRect)) { 437bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio node.setVisibleToUser(true); 438ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setBoundsInParent(tempParentRect); 439bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 440bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 441bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Calculate screen-relative bound. 442ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mView.getLocationOnScreen(tempGlobalRect); 443ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int offsetX = tempGlobalRect[0]; 444ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final int offsetY = tempGlobalRect[1]; 445ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette tempScreenRect.set(tempParentRect); 446ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette tempScreenRect.offset(offsetX, offsetY); 447ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette node.setBoundsInScreen(tempScreenRect); 448bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 449bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return node; 450bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 451bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 452ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private void ensureTempRects() { 453ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempGlobalRect = new int[2]; 454ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempParentRect = new Rect(); 455ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempScreenRect = new Rect(); 456ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 457ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette 458bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean performAction(int virtualViewId, int action, Bundle arguments) { 459bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (virtualViewId) { 460bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case View.NO_ID: 461bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return performActionForHost(action, arguments); 462bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 463bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return performActionForChild(virtualViewId, action, arguments); 464bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 465bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 466bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 467bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean performActionForHost(int action, Bundle arguments) { 468bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return performAccessibilityAction(mView, action, arguments); 469bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 470bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 471bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) { 472bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 473bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: 474bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: 475ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return manageFocusForChild(virtualViewId, action); 476bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 477bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return onPerformActionForVirtualView(virtualViewId, action, arguments); 478bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 479bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 480bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 481ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette private boolean manageFocusForChild(int virtualViewId, int action) { 482bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio switch (action) { 483bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: 484bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return requestAccessibilityFocus(virtualViewId); 485bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: 486bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return clearAccessibilityFocus(virtualViewId); 487bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio default: 488bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 489bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 490bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 491bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 492bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 493bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Computes whether the specified {@link Rect} intersects with the visible 494bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * portion of its parent {@link View}. Modifies {@code localRect} to contain 495bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * only the visible portion. 496bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 497bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param localRect A rectangle in local (parent) coordinates. 498bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether the specified {@link Rect} is visible on the screen. 499bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 500bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean intersectVisibleToUser(Rect localRect) { 501bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Missing or empty bounds mean this view is not visible. 502bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((localRect == null) || localRect.isEmpty()) { 503bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 504bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 505bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 506bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Attached to invisible window means this view is not visible. 507bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (mView.getWindowVisibility() != View.VISIBLE) { 508bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 509bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 510bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 511bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // An invisible predecessor means that this view is not visible. 512bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio ViewParent viewParent = mView.getParent(); 513bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio while (viewParent instanceof View) { 514bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final View view = (View) viewParent; 515bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if ((view.getAlpha() <= 0) || (view.getVisibility() != View.VISIBLE)) { 516bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 517bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 518bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio viewParent = view.getParent(); 519bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 520bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 521bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // A null parent implies the view is not visible. 522bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (viewParent == null) { 523bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 524bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 525bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 526bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // If no portion of the parent is visible, this view is not visible. 527ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (mTempVisibleRect == null) { 528ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette mTempVisibleRect = new Rect(); 529ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette } 530ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette final Rect tempVisibleRect = mTempVisibleRect; 531ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette if (!mView.getLocalVisibleRect(tempVisibleRect)) { 532bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 533bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 534bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 535bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // Check if the view intersects the visible portion of the parent. 536ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette return localRect.intersect(tempVisibleRect); 537bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 538bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 539bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 540bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Returns whether this virtual view is accessibility focused. 541bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 542bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return True if the view is accessibility focused. 543bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 544bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean isAccessibilityFocused(int virtualViewId) { 545bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return (mFocusedVirtualViewId == virtualViewId); 546bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 547bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 548bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 549bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Attempts to give accessibility focus to a virtual view. 550bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 551bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * A virtual view will not actually take focus if 552bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityManager#isEnabled()} returns false, 553bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityManager#isTouchExplorationEnabled()} returns false, 554bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * or the view already has accessibility focus. 555bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 556bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The id of the virtual view on which to place 557bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * accessibility focus. 558bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether this virtual view actually took accessibility focus. 559bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 560bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean requestAccessibilityFocus(int virtualViewId) { 561bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio final AccessibilityManager accessibilityManager = 562bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); 563bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 564bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!mManager.isEnabled() 565bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio || !accessibilityManager.isTouchExplorationEnabled()) { 566bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 567bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 568bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // TODO: Check virtual view visibility. 569bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (!isAccessibilityFocused(virtualViewId)) { 570bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mFocusedVirtualViewId = virtualViewId; 571bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio // TODO: Only invalidate virtual view bounds. 572bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mView.invalidate(); 573bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, 574bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 575bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 576bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 577bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 578bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 579bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 580bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 581bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Attempts to clear accessibility focus from a virtual view. 582bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 583bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The id of the virtual view from which to clear 584bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * accessibility focus. 585bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return Whether this virtual view actually cleared accessibility focus. 586bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 587bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private boolean clearAccessibilityFocus(int virtualViewId) { 588bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio if (isAccessibilityFocused(virtualViewId)) { 589bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mFocusedVirtualViewId = INVALID_ID; 590bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio mView.invalidate(); 591bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio sendEventForVirtualView(virtualViewId, 592bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 593bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return true; 594bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 595bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return false; 596bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 597bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 598bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 599bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Provides a mapping between view-relative coordinates and logical 600bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * items. 601bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 602bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param x The view-relative x coordinate 603bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param y The view-relative y coordinate 604bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return virtual view identifier for the logical item under 605bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * coordinates (x,y) 606bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 607bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract int getVirtualViewAt(float x, float y); 608bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 609bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 610bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates a list with the view's visible items. The ordering of items 611bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within {@code virtualViewIds} specifies order of accessibility focus 612bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * traversal. 613bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 614bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewIds The list to populate with visible items 615bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 616ffb46bf2956d89e3190007ccf2ef3ce3eed005feAlan Viverette protected abstract void getVisibleVirtualViews(IntArray virtualViewIds); 617bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 618bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 619bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates an {@link AccessibilityEvent} with information about the 620bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * specified item. 621bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 622bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Implementations <b>must</b> populate the following required fields: 623bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 624bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>event text, see {@link AccessibilityEvent#getText} or 625bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityEvent#setContentDescription} 626bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 627bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 628bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class automatically populates the following fields with 629bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * default values, but implementations may optionally override them: 630bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 631bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>item class name, set to android.view.View, see 632bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityEvent#setClassName} 633bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 634bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 635bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The following required fields are automatically populated by the 636bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * helper class and may not be overridden: 637bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 638bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>package name, set to the package of the host view's 639bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link Context}, see {@link AccessibilityEvent#setPackageName} 640bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>event source, set to the host view and virtual view identifier, 641bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * see {@link AccessibilityRecord#setSource(View, int)} 642bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 643bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 644bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view id for the item for which to 645bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * populate the event 646bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param event The event to populate 647bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 648bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract void onPopulateEventForVirtualView( 649bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int virtualViewId, AccessibilityEvent event); 650bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 651bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 652bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Populates an {@link AccessibilityNodeInfo} with information 653bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * about the specified item. 654bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 655bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Implementations <b>must</b> populate the following required fields: 656bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 657bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>event text, see {@link AccessibilityNodeInfo#setText} or 658bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setContentDescription} 659bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>bounds in parent coordinates, see 660bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setBoundsInParent} 661bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 662bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 663bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class automatically populates the following fields with 664bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * default values, but implementations may optionally override them: 665bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 666bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>enabled state, set to true, see 667bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setEnabled} 668bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>item class name, identical to the class name set by 669bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateEventForVirtualView}, see 670bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setClassName} 671bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 672bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 673bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The following required fields are automatically populated by the 674bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * helper class and may not be overridden: 675bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <ul> 676bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>package name, identical to the package name set by 677bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateEventForVirtualView}, see 678bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setPackageName} 679bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>node source, identical to the event source set in 680bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateEventForVirtualView}, see 681bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setSource(View, int)} 682bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>parent view, set to the host view, see 683bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setParent(View)} 684bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>visibility, computed based on parent-relative bounds, see 685bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setVisibleToUser} 686bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>accessibility focus, computed based on internal helper state, see 687bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#setAccessibilityFocused} 688bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <li>bounds in screen coordinates, computed based on host view bounds, 689bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * see {@link AccessibilityNodeInfo#setBoundsInScreen} 690bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * </ul> 691bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 692bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Additionally, the helper class automatically handles accessibility 693bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * focus management by adding the appropriate 694bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS} or 695bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 696bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * action. Implementations must <b>never</b> manually add these actions. 697bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 698bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class also automatically modifies parent- and 699bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * screen-relative bounds to reflect the portion of the item visible 700bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * within its parent. 701bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 702bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view identifier of the item for 703bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * which to populate the node 704bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param node The node to populate 705bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 706bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract void onPopulateNodeForVirtualView( 707bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int virtualViewId, AccessibilityNodeInfo node); 708bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 709bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 710bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Performs the specified accessibility action on the item associated 711bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * with the virtual view identifier. See 712bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#performAction(int, Bundle)} for 713bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * more information. 714bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 715bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Implementations <b>must</b> handle any actions added manually in 716bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link #onPopulateNodeForVirtualView}. 717bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * <p> 718bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * The helper class automatically handles focus management resulting 719bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * from {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS} 720bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * and 721bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * {@link AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 722bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * actions. 723bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * 724bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param virtualViewId The virtual view identifier of the item on which 725bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * to perform the action 726bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param action The accessibility action to perform 727bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @param arguments (Optional) A bundle with additional arguments, or 728bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * null 729bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * @return true if the action was performed 730bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 731bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio protected abstract boolean onPerformActionForVirtualView( 732bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio int virtualViewId, int action, Bundle arguments); 733bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 734bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio /** 735bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * Exposes a virtual view hierarchy to the accessibility framework. Only 736bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio * used in API 16+. 737bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio */ 738bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio private class ExploreByTouchNodeProvider extends AccessibilityNodeProvider { 739bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 740bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 741bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.this.createNode(virtualViewId); 742bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 743bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio 744bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio @Override 745bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio public boolean performAction(int virtualViewId, int action, Bundle arguments) { 746bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments); 747bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 748bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio } 749bd9152f6ee156ee473f05f6f05f238605996fca4Fabrice Di Meglio} 750