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>&#64;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