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