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

Commit 098876f5 authored by Rhed Jao's avatar Rhed Jao Committed by Android (Google) Code Review
Browse files

Merge "Improve clear a11y forcus for A11yManagerService"

parents 20f1a5d3 23813d90
Loading
Loading
Loading
Loading
+78 −4
Original line number Diff line number Diff line
@@ -41,12 +41,14 @@ import android.view.View.AttachInfo;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityRequestPreparer;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;

import java.util.ArrayList;
@@ -64,8 +66,11 @@ import java.util.function.Predicate;
 * called from the interaction connection ViewAncestor gives the system to
 * talk to it and a corresponding *UiThread method that is executed on the
 * UI thread.
 *
 * @hide
 */
final class AccessibilityInteractionController {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final class AccessibilityInteractionController {

    private static final String LOG_TAG = "AccessibilityInteractionController";

@@ -85,7 +90,7 @@ final class AccessibilityInteractionController {

    private final Object mLock = new Object();

    private final Handler mHandler;
    private final PrivateHandler mHandler;

    private final ViewRootImpl mViewRootImpl;

@@ -131,14 +136,22 @@ final class AccessibilityInteractionController {
            // thread in this process, set the message as a static reference so
            // after this call completes the same thread but in the interrogating
            // client can handle the message to generate the result.
            if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
            if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId
                    && mHandler.hasAccessibilityCallback(message)) {
                AccessibilityInteractionClient.getInstanceForThread(
                        interrogatingTid).setSameThreadMessage(message);
            } else {
                // For messages without callback of interrogating client, just handle the
                // message immediately if this is UI thread.
                if (!mHandler.hasAccessibilityCallback(message)
                        && Thread.currentThread().getId() == mMyLooperThreadId) {
                    mHandler.handleMessage(message);
                } else {
                    mHandler.sendMessage(message);
                }
            }
        }
    }

    private boolean isShown(View view) {
        // The first two checks are made also made by isShown() which
@@ -731,6 +744,52 @@ final class AccessibilityInteractionController {
        }
    }

    /**
     * Finds the accessibility focused node in the root, and clears the accessibility focus.
     */
    public void clearAccessibilityFocusClientThread() {
        final Message message = mHandler.obtainMessage();
        message.what = PrivateHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS;

        // Don't care about pid and tid because there's no interrogating client for this message.
        scheduleMessage(message, 0, 0, CONSIDER_REQUEST_PREPARERS);
    }

    private void clearAccessibilityFocusUiThread() {
        if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
            return;
        }
        try {
            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags =
                    AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
            final View root = mViewRootImpl.mView;
            if (root != null && isShown(root)) {
                final View host = mViewRootImpl.mAccessibilityFocusedHost;
                // If there is no accessibility focus host or it is not a descendant
                // of the root from which to start the search, then the search failed.
                if (host == null || !ViewRootImpl.isViewDescendantOf(host, root)) {
                    return;
                }
                final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
                final AccessibilityNodeInfo focusNode =
                        mViewRootImpl.mAccessibilityFocusedVirtualView;
                if (provider != null && focusNode != null) {
                    final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
                            focusNode.getSourceNodeId());
                    provider.performAction(virtualNodeId,
                            AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(),
                            null);
                } else {
                    host.performAccessibilityAction(
                            AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(),
                            null);
                }
            }
        } finally {
            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
        }
    }

    private View findViewByAccessibilityId(int accessibilityId) {
        View root = mViewRootImpl.mView;
        if (root == null) {
@@ -1294,6 +1353,12 @@ final class AccessibilityInteractionController {
        private static final int MSG_APP_PREPARATION_FINISHED = 8;
        private static final int MSG_APP_PREPARATION_TIMEOUT = 9;

        // Uses FIRST_NO_ACCESSIBILITY_CALLBACK_MSG for messages that don't need to call back
        // results to interrogating client.
        private static final int FIRST_NO_ACCESSIBILITY_CALLBACK_MSG = 100;
        private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS =
                FIRST_NO_ACCESSIBILITY_CALLBACK_MSG + 1;

        public PrivateHandler(Looper looper) {
            super(looper);
        }
@@ -1320,6 +1385,8 @@ final class AccessibilityInteractionController {
                    return "MSG_APP_PREPARATION_FINISHED";
                case MSG_APP_PREPARATION_TIMEOUT:
                    return "MSG_APP_PREPARATION_TIMEOUT";
                case MSG_CLEAR_ACCESSIBILITY_FOCUS:
                    return "MSG_CLEAR_ACCESSIBILITY_FOCUS";
                default:
                    throw new IllegalArgumentException("Unknown message type: " + type);
            }
@@ -1356,10 +1423,17 @@ final class AccessibilityInteractionController {
                case MSG_APP_PREPARATION_TIMEOUT: {
                    requestPreparerTimeoutUiThread();
                } break;
                case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
                    clearAccessibilityFocusUiThread();
                } break;
                default:
                    throw new IllegalArgumentException("Unknown message type: " + type);
            }
        }

        boolean hasAccessibilityCallback(Message message) {
            return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
        }
    }

    private final class AddNodeInfosForViewId implements Predicate<View> {
+9 −0
Original line number Diff line number Diff line
@@ -8718,6 +8718,15 @@ public final class ViewRootImpl implements ViewParent,
                }
            }
        }

        @Override
        public void clearAccessibilityFocus() {
            ViewRootImpl viewRootImpl = mViewRootImpl.get();
            if (viewRootImpl != null && viewRootImpl.mView != null) {
                viewRootImpl.getAccessibilityInteractionController()
                        .clearAccessibilityFocusClientThread();
            }
        }
    }

    private class SendWindowContentChangedAccessibilityEvent implements Runnable {
+2 −0
Original line number Diff line number Diff line
@@ -55,4 +55,6 @@ oneway interface IAccessibilityInteractionConnection {
    void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
        int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
        int interrogatingPid, long interrogatingTid);

    void clearAccessibilityFocus();
}
+8 −0
Original line number Diff line number Diff line
@@ -1144,6 +1144,14 @@
            </intent-filter>
        </activity>

        <activity android:name="android.view.accessibility.AccessibilityTestActivity"
                  android:label="AccessibilityTestActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
            </intent-filter>
        </activity>

        <!-- Activity-level metadata -->
        <meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
        <meta-data android:name="com.android.frameworks.coretests.string" android:value="foo" />
+30 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2018 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.
  -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button android:id="@+id/appNameBtn"
        android:text="@string/app_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="60dp"
        android:bufferType="normal">
    </Button>
</LinearLayout>
Loading