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

Commit d67dae7d authored by Daniel Norman's avatar Daniel Norman Committed by Android (Google) Code Review
Browse files

Merge "Use A11yManagerService to check if the A11yService warning is required." into main

parents 0d75a206 592a9570
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -185,15 +185,30 @@ public final class AccessibilityManager {

    /**
     * Annotations for the shortcut type.
     * <p>Note: Keep in sync with {@link #SHORTCUT_TYPES}.</p>
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {
            // LINT.IfChange(shortcut_type_intdef)
            ACCESSIBILITY_BUTTON,
            ACCESSIBILITY_SHORTCUT_KEY
            // LINT.ThenChange(:shortcut_type_array)
    })
    public @interface ShortcutType {}

    /**
     * Used for iterating through {@link ShortcutType}.
     * <p>Note: Keep in sync with {@link ShortcutType}.</p>
     * @hide
     */
    public static final int[] SHORTCUT_TYPES = {
            // LINT.IfChange(shortcut_type_array)
            ACCESSIBILITY_BUTTON,
            ACCESSIBILITY_SHORTCUT_KEY,
            // LINT.ThenChange(:shortcut_type_intdef)
    };

    /**
     * Annotations for content flag of UI.
     * @hide
@@ -913,6 +928,28 @@ public final class AccessibilityManager {
        }
    }

    /**
     * Returns whether the user must be shown the AccessibilityService warning dialog
     * before the AccessibilityService (or any shortcut for the service) can be enabled.
     * @hide
     */
    @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
    public boolean isAccessibilityServiceWarningRequired(@NonNull AccessibilityServiceInfo info) {
        final IAccessibilityManager service;
        synchronized (mLock) {
            service = getServiceLocked();
            if (service == null) {
                return true;
            }
        }
        try {
            return service.isAccessibilityServiceWarningRequired(info);
        } catch (RemoteException re) {
            Log.e(LOG_TAG, "Error while checking isAccessibilityServiceWarningRequired: ", re);
            return true;
        }
    }

    /**
     * Registers an {@link AccessibilityStateChangeListener} for changes in
     * the global accessibility state of the system. Equivalent to calling
+3 −0
Original line number Diff line number Diff line
@@ -128,6 +128,9 @@ interface IAccessibilityManager {
    boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId);
    boolean sendRestrictedDialogIntent(String packageName, int uid, int userId);

    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
    boolean isAccessibilityServiceWarningRequired(in AccessibilityServiceInfo info);

    parcelable WindowTransformationSpec {
        float[] transformationMatrix;
        MagnificationSpec magnificationSpec;
+6 −6
Original line number Diff line number Diff line
@@ -17,17 +17,17 @@ flag {
}

flag {
    name: "cleanup_accessibility_warning_dialog"
    namespace: "accessibility"
    name: "collection_info_item_counts"
    description: "Fields for total items and the number of important for accessibility items in a collection"
    bug: "302376158"
    description: "Cleans up duplicated or broken logic surrounding the accessibility warning dialog."
    bug: "303511250"
}

flag {
    name: "deduplicate_accessibility_warning_dialog"
    namespace: "accessibility"
    description: "Removes duplicate definition of the accessibility warning dialog."
    bug: "303511250"
    name: "collection_info_item_counts"
    description: "Fields for total items and the number of important for accessibility items in a collection"
    bug: "302376158"
}

flag {
+30 −8
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.Flags;
import android.widget.AdapterView;

@@ -114,6 +115,26 @@ public class AccessibilityShortcutChooserActivity extends Activity {
    private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) {
        final AccessibilityTarget target = mTargets.get(position);

        if (Flags.cleanupAccessibilityWarningDialog()) {
            if (target instanceof AccessibilityServiceTarget serviceTarget) {
                if (sendRestrictedDialogIntentIfNeeded(target)) {
                    return;
                }
                final AccessibilityManager am = getSystemService(AccessibilityManager.class);
                if (am.isAccessibilityServiceWarningRequired(
                        serviceTarget.getAccessibilityServiceInfo())) {
                    showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target,
                            position, mTargetAdapter);
                    return;
                }
            }
            if (target instanceof AccessibilityActivityTarget activityTarget) {
                if (!activityTarget.isShortcutEnabled()
                        && sendRestrictedDialogIntentIfNeeded(activityTarget)) {
                    return;
                }
            }
        } else {
            if (!target.isShortcutEnabled()) {
                if (target instanceof AccessibilityServiceTarget
                        || target instanceof AccessibilityActivityTarget) {
@@ -128,6 +149,7 @@ public class AccessibilityShortcutChooserActivity extends Activity {
                    return;
                }
            }
        }

        target.onCheckedChanged(!target.isShortcutEnabled());
        mTargetAdapter.notifyDataSetChanged();
@@ -156,7 +178,7 @@ public class AccessibilityShortcutChooserActivity extends Activity {
            return;
        }

        if (Flags.deduplicateAccessibilityWarningDialog()) {
        if (Flags.cleanupAccessibilityWarningDialog()) {
            mPermissionDialog = AccessibilityServiceWarning
                    .createAccessibilityServiceWarningDialog(context,
                            serviceTarget.getAccessibilityServiceInfo(),
+63 −6
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.internal.accessibility;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.doubleClick;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.action.ViewActions.swipeUp;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
@@ -85,10 +84,13 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.stubbing.Answer;

import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Tests for {@link AccessibilityShortcutChooserActivity}.
@@ -151,6 +153,8 @@ public class AccessibilityShortcutChooserActivityTest {
        when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(
                anyInt())).thenReturn(new ParceledListSlice<>(
                Collections.singletonList(mAccessibilityServiceInfo)));
        when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
                .thenReturn(true);
        when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
                anyString(), anyInt(), anyInt())).thenReturn(true);
        when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
@@ -169,7 +173,7 @@ public class AccessibilityShortcutChooserActivityTest {
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
    @RequiresFlagsDisabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
    public void selectTestService_oldPermissionDialog_deny_dialogIsHidden() {
        launchActivity();
        openShortcutsList();
@@ -183,7 +187,7 @@ public class AccessibilityShortcutChooserActivityTest {
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
    @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
    public void selectTestService_permissionDialog_allow_rowChecked() {
        launchActivity();
        openShortcutsList();
@@ -197,7 +201,7 @@ public class AccessibilityShortcutChooserActivityTest {
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
    @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
    public void selectTestService_permissionDialog_deny_rowNotChecked() {
        launchActivity();
        openShortcutsList();
@@ -211,7 +215,7 @@ public class AccessibilityShortcutChooserActivityTest {
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_DEDUPLICATE_ACCESSIBILITY_WARNING_DIALOG)
    @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
    public void selectTestService_permissionDialog_uninstall_callsUninstaller_rowRemoved() {
        launchActivity();
        openShortcutsList();
@@ -226,6 +230,59 @@ public class AccessibilityShortcutChooserActivityTest {
                UI_TIMEOUT_MS)).isFalse();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
    public void selectTestService_permissionDialog_notShownWhenNotRequired() throws Exception {
        when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
                .thenReturn(false);
        launchActivity();
        openShortcutsList();

        // Clicking the test service should not show a permission dialog window,
        assertThat(mDevice.findObject(By.text(TEST_LABEL)).clickAndWait(
                Until.newWindow(), UI_TIMEOUT_MS)).isFalse();
        // and should become checked.
        assertThat(mDevice.findObject(By.checked(true))).isNotNull();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
    public void selectTestService_notPermittedByAdmin_blockedEvenIfNoWarningRequired()
            throws Exception {
        when(mAccessibilityManagerService.isAccessibilityServiceWarningRequired(any()))
                .thenReturn(false);
        when(mAccessibilityManagerService.isAccessibilityTargetAllowed(
                eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt())).thenReturn(false);
        // This test class mocks AccessibilityManagerService, so the restricted dialog window
        // will not actually appear and therefore cannot be used for a wait Until.newWindow().
        // To still allow smart waiting in this test we can instead set up the mocked method
        // to update an atomic boolean and wait for that to be set.
        final Object waitObject = new Object();
        final AtomicBoolean calledSendRestrictedDialogIntent = new AtomicBoolean(false);
        Mockito.doAnswer((Answer<Void>) invocation -> {
            synchronized (waitObject) {
                calledSendRestrictedDialogIntent.set(true);
                waitObject.notify();
            }
            return null;
        }).when(mAccessibilityManagerService).sendRestrictedDialogIntent(
                eq(TEST_COMPONENT_NAME.getPackageName()), anyInt(), anyInt());
        launchActivity();
        openShortcutsList();

        mDevice.findObject(By.text(TEST_LABEL)).click();
        final long timeout = System.currentTimeMillis() + UI_TIMEOUT_MS;
        synchronized (waitObject) {
            while (!calledSendRestrictedDialogIntent.get() &&
                    (System.currentTimeMillis() < timeout)) {
                waitObject.wait(timeout - System.currentTimeMillis());
            }
        }

        assertThat(calledSendRestrictedDialogIntent.get()).isTrue();
        assertThat(mDevice.findObject(By.checked(true))).isNull();
    }

    @Test
    public void clickServiceTarget_notPermittedByAdmin_sendRestrictedDialogIntent()
            throws Exception {
@@ -329,7 +386,7 @@ public class AccessibilityShortcutChooserActivityTest {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (Flags.deduplicateAccessibilityWarningDialog()) {
            if (Flags.cleanupAccessibilityWarningDialog()) {
                // Setting the Theme is necessary here for the dialog to use the proper style
                // resources as designated in its layout XML.
                setTheme(R.style.Theme_DeviceDefault_DayNight);
Loading