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

Commit a5764d4c authored by Ryan Lin's avatar Ryan Lin Committed by Automerger Merge Worker
Browse files

Merge "Eanble sending non-A11yTool notification dyanmically" into tm-dev am:...

Merge "Eanble sending non-A11yTool notification dyanmically" into tm-dev am: 545ce755 am: eac9ebce

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17102870



Change-Id: I804257f3e785c732273265ec09a18823071f3954
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents ec745e58 eac9ebce
Loading
Loading
Loading
Loading
+28 −5
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.SettingsStringUtil.SettingStringHelper;
import android.safetycenter.SafetyCenterManager;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArraySet;
@@ -414,11 +415,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        mMainHandler = new MainHandler(mContext.getMainLooper());
        mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
        mPackageManager = mContext.getPackageManager();
        PolicyWarningUIController policyWarningUIController;
        if (AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
            policyWarningUIController = new PolicyWarningUIController(mMainHandler, context,
        final PolicyWarningUIController policyWarningUIController = new PolicyWarningUIController(
                mMainHandler, context,
                new PolicyWarningUIController.NotificationController(context));
        }
        mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext,
                this);
        mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
@@ -467,6 +466,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                        LocalServices.getService(AppWidgetManagerInternal.class));
            }
        }

        // SafetyCenterService is ready after this phase.
        if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
            setNonA11yToolNotificationToMatchSafetyCenter();
        }
    }

    private void setNonA11yToolNotificationToMatchSafetyCenter() {
        final boolean sendNotification = !mContext.getSystemService(
                SafetyCenterManager.class).isSafetyCenterEnabled();
        synchronized (mLock) {
            mSecurityPolicy.setSendingNonA11yToolNotificationLocked(sendNotification);
        }
    }

    AccessibilityUserState getCurrentUserState() {
@@ -722,6 +734,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                }
            }
        }, UserHandle.ALL, intentFilter, null, null);

        final IntentFilter filter = new IntentFilter();
        filter.addAction(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED);
        final BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                setNonA11yToolNotificationToMatchSafetyCenter();
            }
        };
        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, mMainHandler,
                Context.RECEIVER_EXPORTED);
    }

    // Called only during settings restore; currently supports only the owner user
+28 −19
Original line number Diff line number Diff line
@@ -80,8 +80,6 @@ public class AccessibilitySecurityPolicy {
            | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
            | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;

    public static final boolean POLICY_WARNING_ENABLED = true;

    /**
     * Methods that should find their way into separate modules, but are still in AMS
     * TODO (b/111889696): Refactoring UserState to AccessibilityUserManager.
@@ -106,6 +104,7 @@ public class AccessibilitySecurityPolicy {
    private AppWidgetManagerInternal mAppWidgetService;
    private AccessibilityWindowManager mAccessibilityWindowManager;
    private int mCurrentUserId = UserHandle.USER_NULL;
    private boolean mSendNonA11yToolNotificationEnabled = false;

    /**
     * Constructor for AccessibilityManagerService.
@@ -119,7 +118,25 @@ public class AccessibilitySecurityPolicy {
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        mPolicyWarningUIController = policyWarningUIController;
        mPolicyWarningUIController.setAccessibilityPolicyManager(this);
    }

    /**
     * Enables sending the notification for non-AccessibilityTool services with the given state.
     *
     */
    public void setSendingNonA11yToolNotificationLocked(boolean enable) {
        if (enable == mSendNonA11yToolNotificationEnabled) {
            return;
        }

        mSendNonA11yToolNotificationEnabled = enable;
        mPolicyWarningUIController.enableSendingNonA11yToolNotification(enable);
        if (enable) {
            for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
                final ComponentName service = mNonA11yCategoryServices.valueAt(i);
                mPolicyWarningUIController.onNonA11yCategoryServiceBound(mCurrentUserId, service);
            }
        }
    }

    /**
@@ -725,9 +742,6 @@ public class AccessibilitySecurityPolicy {
     */
    public void onBoundServicesChangedLocked(int userId,
            ArrayList<AccessibilityServiceConnection> boundServices) {
        if (!POLICY_WARNING_ENABLED) {
            return;
        }
        if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) {
            return;
        }
@@ -742,10 +756,12 @@ public class AccessibilitySecurityPolicy {
                if (mNonA11yCategoryServices.contains(service)) {
                    mNonA11yCategoryServices.remove(service);
                } else {
                    if (mSendNonA11yToolNotificationEnabled) {
                        mPolicyWarningUIController.onNonA11yCategoryServiceBound(userId, service);
                    }
                }
            }
        }

        for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
            final ComponentName service = mNonA11yCategoryServices.valueAt(i);
@@ -763,14 +779,11 @@ public class AccessibilitySecurityPolicy {
     * @param enabledServices The enabled services
     */
    public void onSwitchUserLocked(int userId, Set<ComponentName> enabledServices) {
        if (!POLICY_WARNING_ENABLED) {
            return;
        }
        if (mCurrentUserId == userId) {
            return;
        }

        mPolicyWarningUIController.onSwitchUserLocked(userId, enabledServices);
        mPolicyWarningUIController.onSwitchUser(userId,
                new ArraySet<>(enabledServices));

        for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
            mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(mCurrentUserId,
@@ -786,15 +799,11 @@ public class AccessibilitySecurityPolicy {
     * @param userId          The user id
     * @param enabledServices The enabled services
     */
    public void onEnabledServicesChangedLocked(int userId,
            Set<ComponentName> enabledServices) {
        if (!POLICY_WARNING_ENABLED) {
            return;
        }
    public void onEnabledServicesChangedLocked(int userId, Set<ComponentName> enabledServices) {
        if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) {
            return;
        }

        mPolicyWarningUIController.onEnabledServicesChangedLocked(userId, enabledServices);
        mPolicyWarningUIController.onEnabledServicesChanged(userId,
                new ArraySet<>(enabledServices));
    }
}
+49 −21
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ImageUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
@@ -96,24 +97,23 @@ public class PolicyWarningUIController {
        filter.addAction(ACTION_DISMISS_NOTIFICATION);
        mContext.registerReceiver(mNotificationController, filter,
                Manifest.permission.MANAGE_ACCESSIBILITY, mMainHandler, Context.RECEIVER_EXPORTED);

    }

    protected void setAccessibilityPolicyManager(
            AccessibilitySecurityPolicy accessibilitySecurityPolicy) {
        mNotificationController.setAccessibilityPolicyManager(accessibilitySecurityPolicy);
    }

    /**
     * Updates enabled accessibility services and notified accessibility services after switching
     * to another user.
     *
     * @param enabledServices The current enabled services
     * @param enabledServices the current enabled services
     */
    public void onSwitchUserLocked(int userId, Set<ComponentName> enabledServices) {
    public void onSwitchUser(int userId, Set<ComponentName> enabledServices) {
        mMainHandler.sendMessage(
                obtainMessage(this::onSwitchUserInternal, userId, enabledServices));
    }

    private void onSwitchUserInternal(int userId, Set<ComponentName> enabledServices) {
        mEnabledA11yServices.clear();
        mEnabledA11yServices.addAll(enabledServices);
        mMainHandler.sendMessage(obtainMessage(mNotificationController::onSwitchUser, userId));
        mNotificationController.onSwitchUser(userId);
    }

    /**
@@ -122,10 +122,14 @@ public class PolicyWarningUIController {
     * setting {@link Settings.Secure#ENABLED_ACCESSIBILITY_SERVICES} changed.
     *
     * @param userId          The user id
     * @param enabledServices The enabled services
     * @param enabledServices The enabled services set
     */
    public void onEnabledServicesChangedLocked(int userId,
            Set<ComponentName> enabledServices) {
    public void onEnabledServicesChanged(int userId, Set<ComponentName> enabledServices) {
        mMainHandler.sendMessage(
                obtainMessage(this::onEnabledServicesChangedInternal, userId, enabledServices));
    }

    void onEnabledServicesChangedInternal(int userId, Set<ComponentName> enabledServices) {
        final ArraySet<ComponentName> disabledServices = new ArraySet<>(mEnabledA11yServices);
        disabledServices.removeAll(enabledServices);
        mEnabledA11yServices.clear();
@@ -187,6 +191,18 @@ public class PolicyWarningUIController {
        return intent;
    }

    /**
     * Enables to send the notification for non-Accessibility services.
     */
    public void enableSendingNonA11yToolNotification(boolean enable) {
        mMainHandler.sendMessage(
                obtainMessage(this::enableSendingNonA11yToolNotificationInternal, enable));
    }

    private void enableSendingNonA11yToolNotificationInternal(boolean enable) {
        mNotificationController.setSendingNotification(enable);
    }

    /** A sub class to handle notifications and settings on the main thread. */
    @MainThread
    public static class NotificationController extends BroadcastReceiver {
@@ -194,22 +210,19 @@ public class PolicyWarningUIController {

        /** All accessibility services which are notified to the user by the policy warning rule. */
        private final ArraySet<ComponentName> mNotifiedA11yServices = new ArraySet<>();
        /** The component name of sent notifications. */
        private final List<ComponentName> mSentA11yServiceNotification = new ArrayList<>();
        private final NotificationManager mNotificationManager;
        private final Context mContext;

        private int mCurrentUserId;
        private AccessibilitySecurityPolicy mAccessibilitySecurityPolicy;
        private boolean mSendNotification;

        public NotificationController(Context context) {
            mContext = context;
            mNotificationManager = mContext.getSystemService(NotificationManager.class);
        }

        protected void setAccessibilityPolicyManager(
                AccessibilitySecurityPolicy accessibilitySecurityPolicy) {
            mAccessibilitySecurityPolicy = accessibilitySecurityPolicy;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
@@ -238,15 +251,18 @@ public class PolicyWarningUIController {
                }
                mNotificationManager.cancel(componentName.flattenToShortString(),
                        NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
                mSentA11yServiceNotification.remove(componentName);
                onNotificationCanceled(userId, componentName);
            } else if (ACTION_DISMISS_NOTIFICATION.equals(action)) {
                mSentA11yServiceNotification.remove(componentName);
                onNotificationCanceled(userId, componentName);
            }
        }

        protected void onSwitchUser(int userId) {
            mCurrentUserId = userId;
            cancelSentNotifications();
            mNotifiedA11yServices.clear();
            mCurrentUserId = userId;
            mNotifiedA11yServices.addAll(readNotifiedServiceList(userId));
        }

@@ -258,10 +274,11 @@ public class PolicyWarningUIController {
        }

        private boolean trySendNotification(int userId, ComponentName componentName) {
            if (!AccessibilitySecurityPolicy.POLICY_WARNING_ENABLED) {
            if (userId != mCurrentUserId) {
                return false;
            }
            if (userId != mCurrentUserId) {

            if (!mSendNotification) {
                return false;
            }

@@ -344,6 +361,7 @@ public class PolicyWarningUIController {
            mNotificationManager.notify(serviceComponentName.flattenToShortString(),
                    NOTE_A11Y_VIEW_AND_CONTROL_ACCESS,
                    notificationBuilder.build());
            mSentA11yServiceNotification.add(serviceComponentName);
        }

        private ArraySet<ComponentName> readNotifiedServiceList(int userId) {
@@ -393,5 +411,15 @@ public class PolicyWarningUIController {
            return accessibilityManager.getEnabledAccessibilityServiceList(
                    AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
        }

        private void cancelSentNotifications() {
            mSentA11yServiceNotification.forEach(componentName -> mNotificationManager.cancel(
                    componentName.flattenToShortString(), NOTE_A11Y_VIEW_AND_CONTROL_ACCESS));
            mSentA11yServiceNotification.clear();
        }

        void setSendingNotification(boolean enable) {
            mSendNotification = enable;
        }
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ public class AccessibilitySecurityPolicyTest {

        mA11ySecurityPolicy = new AccessibilitySecurityPolicy(
                mPolicyWarningUIController, mContext, mMockA11yUserManager);
        mA11ySecurityPolicy.setSendingNonA11yToolNotificationLocked(true);
        mA11ySecurityPolicy.setAccessibilityWindowManager(mMockA11yWindowManager);
        mA11ySecurityPolicy.setAppWidgetManager(mMockAppWidgetManager);
        mA11ySecurityPolicy.onSwitchUserLocked(TEST_USER_ID, new HashSet<>());
@@ -653,11 +654,18 @@ public class AccessibilitySecurityPolicyTest {

        mA11ySecurityPolicy.onSwitchUserLocked(newUserId, new HashSet<>());

        verify(mPolicyWarningUIController).onSwitchUserLocked(eq(newUserId), eq(new HashSet<>()));
        verify(mPolicyWarningUIController).onSwitchUser(eq(newUserId), eq(new HashSet<>()));
        verify(mPolicyWarningUIController).onNonA11yCategoryServiceUnbound(eq(TEST_USER_ID),
                eq(TEST_COMPONENT_NAME));
    }

    @Test
    public void enableSendingNonA11yToolNotificationLocked_propagateToPolicyWarningController() {
        mA11ySecurityPolicy.setSendingNonA11yToolNotificationLocked(true);

        verify(mPolicyWarningUIController).enableSendingNonA11yToolNotification(true);
    }

    private void initServiceInfoAndConnection(ComponentName componentName,
            AccessibilityServiceConnection connection,
            boolean isAccessibilityTool) {
+80 −15
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static junit.framework.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -46,12 +47,16 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.TestableContext;
import android.util.ArraySet;

import com.google.common.collect.ImmutableSet;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
@@ -67,6 +72,8 @@ public class PolicyWarningUIControllerTest {
    private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
            "com.android.server.accessibility", "PolicyWarningUIControllerTest");

    private static final ComponentName TEST_COMPONENT_NAME2 = new ComponentName(
            "com.android.server.accessibility", "nonAccessibilityToolService");
    private final List<AccessibilityServiceInfo> mEnabledServiceList = new ArrayList<>();

    @Rule
@@ -79,15 +86,9 @@ public class PolicyWarningUIControllerTest {
    @Mock
    private StatusBarManager mStatusBarManager;
    @Mock
    private AccessibilityServiceInfo mMockA11yServiceInfo;
    @Mock
    private ResolveInfo mMockResolveInfo;
    @Mock
    private ServiceInfo mMockServiceInfo;
    @Mock
    private Context mSpyContext;
    @Mock
    private AccessibilitySecurityPolicy mAccessibilitySecurityPolicy;

    private PolicyWarningUIController mPolicyWarningUIController;
    private FakeNotificationController mFakeNotificationController;
@@ -102,21 +103,18 @@ public class PolicyWarningUIControllerTest {
        mPolicyWarningUIController = new PolicyWarningUIController(
                getInstrumentation().getTargetContext().getMainThreadHandler(), mContext,
                mFakeNotificationController);
        mPolicyWarningUIController.setAccessibilityPolicyManager(mAccessibilitySecurityPolicy);
        mPolicyWarningUIController.onSwitchUserLocked(TEST_USER_ID, new HashSet<>());
        mEnabledServiceList.clear();
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
                "", TEST_USER_ID);
        mPolicyWarningUIController.enableSendingNonA11yToolNotification(true);
        mPolicyWarningUIController.onSwitchUser(TEST_USER_ID, new HashSet<>());
        getInstrumentation().waitForIdleSync();
    }

    @Test
    public void receiveActionSendNotification_isNonA11yCategoryService_sendNotification() {
        mEnabledServiceList.add(mMockA11yServiceInfo);
        mMockResolveInfo.serviceInfo = mMockServiceInfo;
        when(mMockA11yServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
        when(mMockA11yServiceInfo.getComponentName()).thenReturn(TEST_COMPONENT_NAME);
        when(mMockA11yServiceInfo.isAccessibilityTool()).thenReturn(false);
        addEnabledServiceInfo(TEST_COMPONENT_NAME, false);

        mFakeNotificationController.onReceive(mContext,
                PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
@@ -127,6 +125,39 @@ public class PolicyWarningUIControllerTest {
                eq(NOTE_A11Y_VIEW_AND_CONTROL_ACCESS), any(Notification.class));
    }

    @Test
    public void receiveActionSendNotification_sendNotificationDisabled_doNothing() {
        mPolicyWarningUIController.enableSendingNonA11yToolNotification(false);
        addEnabledServiceInfo(TEST_COMPONENT_NAME, false);

        mFakeNotificationController.onReceive(mContext,
                PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
                        PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
                        TEST_COMPONENT_NAME));

        verify(mNotificationManager, never()).notify(eq(TEST_COMPONENT_NAME.flattenToShortString()),
                eq(NOTE_A11Y_VIEW_AND_CONTROL_ACCESS), any(Notification.class));
    }

    @Test
    public void receiveActionSendNotificationWithNotifiedService_doNothing() {
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
                TEST_COMPONENT_NAME.flattenToShortString(), TEST_USER_ID);
        mEnabledServiceList.clear();
        mPolicyWarningUIController.onSwitchUser(TEST_USER_ID, new HashSet<>());
        getInstrumentation().waitForIdleSync();
        addEnabledServiceInfo(TEST_COMPONENT_NAME, false);

        mFakeNotificationController.onReceive(mContext,
                PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
                        PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
                        TEST_COMPONENT_NAME));

        verify(mNotificationManager, never()).notify(eq(TEST_COMPONENT_NAME.flattenToShortString()),
                eq(NOTE_A11Y_VIEW_AND_CONTROL_ACCESS), any(Notification.class));
    }

    @Test
    public void receiveActionA11ySettings_launchA11ySettingsAndDismissNotification() {
        mFakeNotificationController.onReceive(mContext,
@@ -154,11 +185,11 @@ public class PolicyWarningUIControllerTest {
    public void onEnabledServicesChangedLocked_serviceDisabled_removedFromNotifiedSettings() {
        final Set<ComponentName> enabledServices = new HashSet<>();
        enabledServices.add(TEST_COMPONENT_NAME);
        mPolicyWarningUIController.onEnabledServicesChangedLocked(TEST_USER_ID, enabledServices);
        mPolicyWarningUIController.onEnabledServicesChanged(TEST_USER_ID, enabledServices);
        getInstrumentation().waitForIdleSync();
        receiveActionDismissNotification_addToNotifiedSettings();

        mPolicyWarningUIController.onEnabledServicesChangedLocked(TEST_USER_ID, new HashSet<>());
        mPolicyWarningUIController.onEnabledServicesChanged(TEST_USER_ID, new HashSet<>());
        getInstrumentation().waitForIdleSync();

        assertNotifiedSettingsEqual(TEST_USER_ID, "");
@@ -185,6 +216,29 @@ public class PolicyWarningUIControllerTest {
                        PolicyWarningUIController.ACTION_SEND_NOTIFICATION, TEST_COMPONENT_NAME)));
    }

    @Test
    public void onSwitchUserLocked_hasAlarmAndSentNotification_cancelNotification() {
        addEnabledServiceInfo(TEST_COMPONENT_NAME2, false);
        final Set<ComponentName> enabledNonA11yServices = new ArraySet<>();
        enabledNonA11yServices.add(TEST_COMPONENT_NAME);
        enabledNonA11yServices.add(TEST_COMPONENT_NAME2);
        mPolicyWarningUIController.onEnabledServicesChanged(TEST_USER_ID,
                enabledNonA11yServices);
        mPolicyWarningUIController.onNonA11yCategoryServiceBound(TEST_USER_ID, TEST_COMPONENT_NAME);
        mFakeNotificationController.onReceive(mContext,
                PolicyWarningUIController.createIntent(mContext, TEST_USER_ID,
                        PolicyWarningUIController.ACTION_SEND_NOTIFICATION,
                        TEST_COMPONENT_NAME2));
        getInstrumentation().waitForIdleSync();

        mPolicyWarningUIController.onSwitchUser(TEST_USER_ID,
                ImmutableSet.copyOf(new ArraySet<>()));
        getInstrumentation().waitForIdleSync();

        verify(mNotificationManager).cancel(TEST_COMPONENT_NAME2.flattenToShortString(),
                NOTE_A11Y_VIEW_AND_CONTROL_ACCESS);
    }

    private void assertNotifiedSettingsEqual(int userId, String settingString) {
        final String notifiedServicesSetting = Settings.Secure.getStringForUser(
                mContext.getContentResolver(),
@@ -205,6 +259,17 @@ public class PolicyWarningUIControllerTest {
        verify(mStatusBarManager).collapsePanels();
    }

    private void addEnabledServiceInfo(ComponentName componentName, boolean isAccessibilityTool) {
        final AccessibilityServiceInfo a11yServiceInfo = Mockito.mock(
                AccessibilityServiceInfo.class);
        when(a11yServiceInfo.getComponentName()).thenReturn(componentName);
        when(a11yServiceInfo.isAccessibilityTool()).thenReturn(isAccessibilityTool);
        final ResolveInfo resolveInfo = Mockito.mock(ResolveInfo.class);
        when(a11yServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
        resolveInfo.serviceInfo = mMockServiceInfo;
        mEnabledServiceList.add(a11yServiceInfo);
    }

    private class A11yTestableContext extends TestableContext {
        A11yTestableContext(Context base) {
            super(base);