Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2eecea3b authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android (Google) Code Review
Browse files

Merge "Speedup the accessibility window querying APIs and clean up."

parents c5143d2a 79311c4a
Loading
Loading
Loading
Loading
+44 −13
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package android.accessibilityservice;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -218,10 +220,17 @@ public abstract class AccessibilityService extends Service {

    private static final String LOG_TAG = "AccessibilityService";

    private AccessibilityServiceInfo mInfo;
    interface Callbacks {
        public void onAccessibilityEvent(AccessibilityEvent event);
        public void onInterrupt();
        public void onServiceConnected();
        public void onSetConnectionId(int connectionId);
    }

    private int mConnectionId;

    private AccessibilityServiceInfo mInfo;

    /**
     * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
     *
@@ -282,27 +291,49 @@ public abstract class AccessibilityService extends Service {
     */
    @Override
    public final IBinder onBind(Intent intent) {
        return new IEventListenerWrapper(this);
        return new IEventListenerWrapper(this, getMainLooper(), new Callbacks() {
            @Override
            public void onServiceConnected() {
                AccessibilityService.this.onServiceConnected();
            }

            @Override
            public void onInterrupt() {
                AccessibilityService.this.onInterrupt();
            }

            @Override
            public void onAccessibilityEvent(AccessibilityEvent event) {
                AccessibilityService.this.onAccessibilityEvent(event);
            }

            @Override
            public void onSetConnectionId( int connectionId) {
                mConnectionId = connectionId;
            }
        });
    }

    /**
     * Implements the internal {@link IEventListener} interface to convert
     * incoming calls to it back to calls on an {@link AccessibilityService}.
     */
    class IEventListenerWrapper extends IEventListener.Stub
    static class IEventListenerWrapper extends IEventListener.Stub
            implements HandlerCaller.Callback {

        static final int NO_ID = -1;

        private static final int DO_SET_SET_CONNECTION = 10;
        private static final int DO_ON_INTERRUPT = 20;
        private static final int DO_ON_ACCESSIBILITY_EVENT = 30;

        private final HandlerCaller mCaller;

        private final AccessibilityService mTarget;
        private final Callbacks mCallback;

        public IEventListenerWrapper(AccessibilityService context) {
            mTarget = context;
            mCaller = new HandlerCaller(context, this);
        public IEventListenerWrapper(Context context, Looper looper, Callbacks callback) {
            mCallback = callback;
            mCaller = new HandlerCaller(context, looper, this);
        }

        public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
@@ -326,12 +357,13 @@ public abstract class AccessibilityService extends Service {
                case DO_ON_ACCESSIBILITY_EVENT :
                    AccessibilityEvent event = (AccessibilityEvent) message.obj;
                    if (event != null) {
                        mTarget.onAccessibilityEvent(event);
                        AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
                        mCallback.onAccessibilityEvent(event);
                        event.recycle();
                    }
                    return;
                case DO_ON_INTERRUPT :
                    mTarget.onInterrupt();
                    mCallback.onInterrupt();
                    return;
                case DO_SET_SET_CONNECTION :
                    final int connectionId = message.arg1;
@@ -340,12 +372,11 @@ public abstract class AccessibilityService extends Service {
                    if (connection != null) {
                        AccessibilityInteractionClient.getInstance().addConnection(connectionId,
                                connection);
                        mConnectionId = connectionId;
                        mTarget.onServiceConnected();
                        mCallback.onSetConnectionId(connectionId);
                        mCallback.onServiceConnected();
                    } else {
                        AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
                        mConnectionId = AccessibilityInteractionClient.NO_ID;
                        // TODO: Do we need a onServiceDisconnected callback?
                        mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
                    }
                    return;
                default :
+36 −30
Original line number Diff line number Diff line
@@ -32,8 +32,13 @@ interface IAccessibilityServiceConnection {
    /**
     * Finds an {@link AccessibilityNodeInfo} by accessibility id.
     *
     * @param accessibilityWindowId A unique window id.
     * @param accessibilityNodeId A unique view id or virtual descendant id.
     * @param accessibilityWindowId A unique window id. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
     *     to query the currently active window.
     * @param accessibilityNodeId A unique view id or virtual descendant id from
     *     where to start the search. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
     *     to start from the root.
     * @param interactionId The id of the interaction for matching with the callback result.
     * @param callback Callback which to receive the result.
     * @param threadId The id of the calling thread.
@@ -46,57 +51,58 @@ interface IAccessibilityServiceConnection {
    /**
     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
     * insensitive containment. The search is performed in the window whose
     * id is specified and starts from the View whose accessibility id is
     * id is specified and starts from the node whose accessibility id is
     * specified.
     *
     * @param text The searched text.
     * @param accessibilityWindowId A unique window id.
     * @param accessibilityWindowId A unique window id. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
     *     to query the currently active window.
     * @param accessibilityNodeId A unique view id or virtual descendant id from
     *        where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
     * @param interactionId The id of the interaction for matching with the callback result.
     * @param callback Callback which to receive the result.
     * @param threadId The id of the calling thread.
     * @return The current window scale, where zero means a failure.
     */
    float findAccessibilityNodeInfosByText(String text, int accessibilityWindowId,
        long accessibilityNodeId, int interractionId,
        IAccessibilityInteractionConnectionCallback callback, long threadId);

    /**
     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
     * insensitive containment. The search is performed in the currently
     * active window and start from the root View in the window.
     *
     *     where to start the search. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
     *     to start from the root.
     * @param text The searched text.
     * @param accessibilityId The id of the view from which to start searching.
     *        Use {@link android.view.View#NO_ID} to start from the root.
     * @param interactionId The id of the interaction for matching with the callback result.
     * @param callback Callback which to receive the result.
     * @param threadId The id of the calling thread.
     * @return The current window scale, where zero means a failure.
     */
    float findAccessibilityNodeInfosByTextInActiveWindow(String text,
        int interactionId, IAccessibilityInteractionConnectionCallback callback,
    float findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
        String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
        long threadId);

    /**
     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
     * in the currently active window and starts from the root View in the window.
     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
     * the window whose id is specified and starts from the node whose accessibility
     * id is specified.
     *
     * @param accessibilityWindowId A unique window id. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
     *     to query the currently active window.
     * @param accessibilityNodeId A unique view id or virtual descendant id from
     *     where to start the search. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
     *     to start from the root.
     * @param id The id of the node.
     * @param interactionId The id of the interaction for matching with the callback result.
     * @param callback Callback which to receive the result.
     * @param threadId The id of the calling thread.
     * @return The current window scale, where zero means a failure.
     */
    float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId, int interactionId,
        IAccessibilityInteractionConnectionCallback callback, long threadId);
    float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId,
        int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
        long threadId);

    /**
     * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
     *
     * @param accessibilityWindowId The id of the window.
     * @param accessibilityNodeId A unique view id or virtual descendant id.
     * @param accessibilityWindowId A unique window id. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
     *     to query the currently active window.
     * @param accessibilityNodeId A unique view id or virtual descendant id from
     *     where to start the search. Use
     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
     *     to start from the root.
     * @param action The action to perform.
     * @param interactionId The id of the interaction for matching with the callback result.
     * @param callback Callback which to receive the result.
+418 −0

File added.

Preview size limit exceeded, changes collapsed.

+171 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.util.LongSparseArray;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;

/**
 * Simple cache for AccessibilityNodeInfos. The cache is mapping an
 * accessibility id to an info. The cache allows storing of
 * <code>null</code> values. It also tracks accessibility events
 * and invalidates accordingly.
 *
 * @hide
 */
public class AccessibilityNodeInfoCache {

    private final boolean ENABLED = true;

    /**
     * @return A new <strong>not synchronized</strong> AccessibilityNodeInfoCache.
     */
    public static AccessibilityNodeInfoCache newAccessibilityNodeInfoCache() {
        return new AccessibilityNodeInfoCache();
    }

    /**
     * @return A new <strong>synchronized</strong> AccessibilityNodeInfoCache.
     */
    public static AccessibilityNodeInfoCache newSynchronizedAccessibilityNodeInfoCache() {
        return new AccessibilityNodeInfoCache() {
            private final Object mLock = new Object();

            @Override
            public void clear() {
                synchronized(mLock) {
                    super.clear();
                }
            }

            @Override
            public AccessibilityNodeInfo get(long accessibilityNodeId) {
                synchronized(mLock) {
                    return super.get(accessibilityNodeId);
                }
            }

            @Override
            public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
                synchronized(mLock) {
                   super.put(accessibilityNodeId, info);
                }
            }

            @Override
            public void remove(long accessibilityNodeId) {
                synchronized(mLock) {
                   super.remove(accessibilityNodeId);
                }
            }
        };
    }

    private final LongSparseArray<AccessibilityNodeInfo> mCacheImpl;

    private AccessibilityNodeInfoCache() {
        if (ENABLED) {
            mCacheImpl = new LongSparseArray<AccessibilityNodeInfo>();
        } else {
            mCacheImpl = null;
        }
    }

    /**
     * The cache keeps track of {@link AccessibilityEvent}s and invalidates
     * cached nodes as appropriate.
     *
     * @param event An event.
     */
    public void onAccessibilityEvent(AccessibilityEvent event) {
        final int eventType = event.getEventType();
        switch (eventType) {
            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                clear();
                break;
            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
            case AccessibilityEvent.TYPE_VIEW_SELECTED:
            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
            case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
                final long accessibilityNodeId = event.getSourceNodeId();
                remove(accessibilityNodeId);
                break;
        }
    }

    /**
     * Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
     *
     * @param accessibilityNodeId The info accessibility node id.
     * @return The cached {@link AccessibilityNodeInfo} or null if such not found.
     */
    public AccessibilityNodeInfo get(long accessibilityNodeId) {
        if (ENABLED) {
            return mCacheImpl.get(accessibilityNodeId);
        } else {
            return null;
        }
    }

    /**
     * Caches an {@link AccessibilityNodeInfo} given its accessibility node id.
     *
     * @param accessibilityNodeId The info accessibility node id.
     * @param info The {@link AccessibilityNodeInfo} to cache.
     */
    public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
        if (ENABLED) {
            mCacheImpl.put(accessibilityNodeId, info);
        }
    }

    /**
     * Returns whether the cache contains an accessibility node id key.
     *
     * @param accessibilityNodeId The key for which to check.
     * @return True if the key is in the cache.
     */
    public boolean containsKey(long accessibilityNodeId) {
        if (ENABLED) {
            return (mCacheImpl.indexOfKey(accessibilityNodeId) >= 0);
        } else {
            return false;
        }
    }

    /**
     * Removes a cached {@link AccessibilityNodeInfo}.
     *
     * @param accessibilityNodeId The info accessibility node id.
     */
    public void remove(long accessibilityNodeId) {
        if (ENABLED) {
            mCacheImpl.remove(accessibilityNodeId);
        }
    }

    /**
     * Clears the cache.
     */
    public void clear() {
        if (ENABLED) {
            mCacheImpl.clear();
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -12679,6 +12679,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
        }
        if (getAccessibilityNodeProvider() != null) {
            throw new IllegalStateException("Views with AccessibilityNodeProvider"
                    + " can't have children.");
        }
        mPrivateFlags |= FORCE_LAYOUT;
        mPrivateFlags |= INVALIDATED;
Loading