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

Commit 6e79d125 authored by Peter_Liang's avatar Peter_Liang
Browse files

Fix clicking the allow/deny button of the dialog was not working after quickly...

Fix clicking the allow/deny button of the dialog was not working after quickly clicking multiple times.

Root cause:
Show at least two dialogs after quickly clicking multiple times.

Goal:
Should only show one dialog on the screen.

Bug: 233248607
Test: atest AccessibilityShortcutChooserActivityTest
Change-Id: I7dcc9708fe1fe178017464b09e8aa8abaa6a07ac
parent a7a7a9c1
Loading
Loading
Loading
Loading
+20 −10
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static com.android.internal.accessibility.util.AccessibilityUtils.isUserS
import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.os.Bundle;
@@ -102,21 +103,30 @@ public class AccessibilityShortcutChooserActivity extends Activity {
        final AccessibilityTarget target = mTargets.get(position);

        if ((target instanceof AccessibilityServiceTarget) && !target.isShortcutEnabled()) {
            mPermissionDialog = new AlertDialog.Builder(this)
                    .setView(createEnableDialogContentView(this,
                            (AccessibilityServiceTarget) target,
            showPermissionDialogIfNeeded(this, (AccessibilityServiceTarget) target, mTargetAdapter);
            return;
        }

        target.onCheckedChanged(!target.isShortcutEnabled());
        mTargetAdapter.notifyDataSetChanged();
    }

    private void showPermissionDialogIfNeeded(Context context,
            AccessibilityServiceTarget serviceTarget, ShortcutTargetAdapter targetAdapter) {
        if (mPermissionDialog != null) {
            return;
        }

        mPermissionDialog = new AlertDialog.Builder(context)
                .setView(createEnableDialogContentView(context, serviceTarget,
                        v -> {
                            mPermissionDialog.dismiss();
                                mTargetAdapter.notifyDataSetChanged();
                            targetAdapter.notifyDataSetChanged();
                        },
                        v -> mPermissionDialog.dismiss()))
                .setOnDismissListener(dialog -> mPermissionDialog = null)
                .create();
        mPermissionDialog.show();
            return;
        }

        target.onCheckedChanged(!target.isShortcutEnabled());
        mTargetAdapter.notifyDataSetChanged();
    }

    private void onDoneButtonClicked() {
+4 −0
Original line number Diff line number Diff line
@@ -161,6 +161,9 @@
    <!-- ChooserActivityTest permissions-->
    <uses-permission android:name="android.permission.SET_CLIP_SOURCE" />

    <!-- AccessibilityShortcutChooserActivityTest permissions -->
    <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY" />

    <application android:theme="@style/Theme" android:supportsRtl="true">
        <uses-library android:name="android.test.runner" />
        <uses-library android:name="org.apache.http.legacy" android:required="false" />
@@ -1411,6 +1414,7 @@
        <activity android:name="com.android.internal.app.ChooserWrapperActivity"/>
        <activity android:name="com.android.internal.app.ResolverWrapperActivity"/>
        <activity android:name="com.android.internal.app.IntentForwarderActivityTest$IntentForwarderWrapperActivity"/>
        <activity android:name="com.android.internal.accessibility.AccessibilityShortcutChooserActivityTest$TestAccessibilityShortcutChooserActivity"/>

        <receiver android:name="android.app.activity.AbortReceiver"
            android:exported="true">
+146 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 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.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Handler;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;

import androidx.lifecycle.Lifecycle;
import androidx.test.core.app.ActivityScenario;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.R;
import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Collections;

/**
 * Tests for {@link AccessibilityShortcutChooserActivity}.
 */
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutChooserActivityTest {
    private static final String TEST_LABEL = "TEST_LABEL";
    private static final Context sContext =
            InstrumentationRegistry.getInstrumentation().getContext();
    private ActivityScenario<TestAccessibilityShortcutChooserActivity> mScenario;
    private static IAccessibilityManager sAccessibilityManagerService;

    @Mock
    private AccessibilityServiceInfo mAccessibilityServiceInfo;

    @Mock
    private ResolveInfo mResolveInfo;

    @Mock
    private ServiceInfo mServiceInfo;

    @Mock
    private ApplicationInfo mApplicationInfo;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        sAccessibilityManagerService = mock(IAccessibilityManager.class);

        when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
        mResolveInfo.serviceInfo = mServiceInfo;
        mServiceInfo.applicationInfo = mApplicationInfo;
        when(mResolveInfo.loadLabel(any(PackageManager.class))).thenReturn(TEST_LABEL);
        when(mAccessibilityServiceInfo.getComponentName()).thenReturn(
                new ComponentName("package", "class"));
        when(sAccessibilityManagerService.getInstalledAccessibilityServiceList(
                anyInt())).thenReturn(Collections.singletonList(mAccessibilityServiceInfo));

        mScenario = ActivityScenario.launch(TestAccessibilityShortcutChooserActivity.class);
    }

    @Test
    public void doubleClickServiceTargetAndClickDenyButton_permissionDialogDoesNotExist() {
        mScenario.moveToState(Lifecycle.State.CREATED);
        mScenario.moveToState(Lifecycle.State.STARTED);
        mScenario.moveToState(Lifecycle.State.RESUMED);
        onView(withText(R.string.accessibility_select_shortcut_menu_title)).inRoot(
                isDialog()).check(matches(isDisplayed()));
        onView(withText(R.string.edit_accessibility_shortcut_menu_button)).perform(click());

        onView(withText(TEST_LABEL)).perform(doubleClick());
        onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
                matches(isDisplayed()));
        onView(withId(R.id.accessibility_permission_enable_deny_button)).inRoot(isDialog()).check(
                matches(isDisplayed()));
        onView(withId(R.id.accessibility_permission_enable_deny_button)).perform(click());

        onView(withId(R.id.accessibility_permissionDialog_title)).inRoot(isDialog()).check(
                doesNotExist());
        mScenario.moveToState(Lifecycle.State.DESTROYED);
    }

    /**
     * Used for testing.
     */
    public static class TestAccessibilityShortcutChooserActivity extends
            AccessibilityShortcutChooserActivity {
        private AccessibilityManager mAccessibilityManager;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            mAccessibilityManager = new AccessibilityManager(sContext, new Handler(getMainLooper()),
                    sAccessibilityManagerService, /* userId= */ 0, /* serviceConnect= */ true);
            super.onCreate(savedInstanceState);
        }

        @Override
        public Object getSystemService(String name) {
            if (Context.ACCESSIBILITY_SERVICE.equals(name)) {
                return mAccessibilityManager;
            }

            return super.getSystemService(name);
        }
    }
}