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

Commit 5d331bec authored by Hiroki Sato's avatar Hiroki Sato
Browse files

Add display related tests in AccessibilityManagerServiceTest

With this change, the test starts to use a real instance of
AccessibilityDisplayListener. Because DisplayManager class is a final
class and is hard to mock in service tests, this introduces a wrapper
for it.

Bug: 400872190
Test: AccessibilityManagerServiceTest
Flag: TEST_ONLY
Change-Id: I7b425727110ede3ca0601b6dc6c7acd85bb91a75
parent 4186f36e
Loading
Loading
Loading
Loading
+36 −6
Original line number Diff line number Diff line
@@ -531,7 +531,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            AccessibilitySecurityPolicy securityPolicy,
            SystemActionPerformer systemActionPerformer,
            AccessibilityWindowManager a11yWindowManager,
            AccessibilityDisplayListener a11yDisplayListener,
            AccessibilityDisplayListener.DisplayManagerWrapper displayManagerWrapper,
            MagnificationController magnificationController,
            @Nullable AccessibilityInputFilter inputFilter,
            ProxyManager proxyManager,
@@ -550,7 +550,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
        mSecurityPolicy = securityPolicy;
        mSystemActionPerformer = systemActionPerformer;
        mA11yWindowManager = a11yWindowManager;
        mA11yDisplayListener = a11yDisplayListener;
        mA11yDisplayListener = new AccessibilityDisplayListener(displayManagerWrapper,
                new MainHandler(Looper.getMainLooper()));
        mMagnificationController = magnificationController;
        mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
        mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
@@ -596,7 +597,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                this, LocalServices.getService(PackageManagerInternal.class));
        mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
                mWindowManagerService, this, mSecurityPolicy, this, mTraceManager);
        mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
        mA11yDisplayListener = new AccessibilityDisplayListener(
                new AccessibilityDisplayListener.DisplayManagerWrapper(mContext), mMainHandler);
        mMagnificationController = new MagnificationController(
                this,
                mLock,
@@ -5457,11 +5459,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
     * A Utility class to handle display state.
     */
    public class AccessibilityDisplayListener implements DisplayManager.DisplayListener {
        private final DisplayManager mDisplayManager;
        private final DisplayManagerWrapper mDisplayManager;
        private final ArrayList<Display> mDisplaysList = new ArrayList<>();
        private int mSystemUiUid = 0;

        AccessibilityDisplayListener(Context context, Handler handler) {
        AccessibilityDisplayListener(DisplayManagerWrapper displayManager, Handler handler) {
            // Avoid concerns about one thread adding displays while another thread removes
            // them by ensuring the looper is the main looper and the DisplayListener
            // callbacks are always executed on the one main thread.
@@ -5474,7 +5476,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
                Slog.e(LOG_TAG, errorMessage);
            }

            mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
            mDisplayManager = displayManager;
            mDisplayManager.registerDisplayListener(this, handler);
            initializeDisplayList();

@@ -5626,6 +5628,34 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
            }
            return true;
        }

        /** Wrapper of DisplayManager for testing. */
        @VisibleForTesting
        static class DisplayManagerWrapper {
            private final DisplayManager mDm;

            DisplayManagerWrapper(Context context) {
                mDm = context.getSystemService(DisplayManager.class);
            }

            /**
             * @see DisplayManager#registerDisplayListener(DisplayManager.DisplayListener, Handler)
             */
            public void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
                    @Nullable Handler handler) {
                mDm.registerDisplayListener(listener, handler);
            }

            /** @see DisplayManager#getDisplays() */
            public Display[] getDisplays() {
                return mDm.getDisplays();
            }

            /** @see DisplayManager#getDisplay(int) */
            public Display getDisplay(int displayId) {
                return mDm.getDisplay(displayId);
            }
        }
    }

    /** Represents an {@link AccessibilityManager} */
+142 −11
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -66,6 +67,7 @@ import android.Manifest;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.RemoteAction;
@@ -77,10 +79,12 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Icon;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.input.KeyGestureEvent;
import android.net.Uri;
@@ -114,6 +118,7 @@ import android.view.accessibility.IUserInitializationCompleteCallback;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.compatibility.common.util.TestUtils;
import com.android.internal.R;
@@ -136,6 +141,8 @@ import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;

import com.google.common.truth.Correspondence;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -188,6 +195,8 @@ public class AccessibilityManagerServiceTest {
            DESCRIPTION,
            TEST_PENDING_INTENT);

    private static final int FAKE_SYSTEMUI_UID = 1000;

    private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1;
    private static final String TARGET_MAGNIFICATION = MAGNIFICATION_CONTROLLER_NAME;
    private static final ComponentName TARGET_ALWAYS_ON_A11Y_SERVICE =
@@ -207,11 +216,12 @@ public class AccessibilityManagerServiceTest {
    @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
    @Mock private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
    @Mock private PackageManager mMockPackageManager;
    @Mock
    private PackageManagerInternal mMockPackageManagerInternal;
    @Mock private WindowManagerInternal mMockWindowManagerService;
    @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
    @Mock private SystemActionPerformer mMockSystemActionPerformer;
    @Mock private AccessibilityWindowManager mMockA11yWindowManager;
    @Mock private AccessibilityDisplayListener mMockA11yDisplayListener;
    @Mock private ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
    @Mock private UserManagerInternal mMockUserManagerInternal;
    @Mock private IBinder mMockBinder;
@@ -234,6 +244,7 @@ public class AccessibilityManagerServiceTest {
    private TestableLooper mTestableLooper;
    private Handler mHandler;
    private FakePermissionEnforcer mFakePermissionEnforcer;
    private TestDisplayManagerWrapper mTestDisplayManagerWrapper;

    @Before
    public void setUp() throws Exception {
@@ -246,6 +257,7 @@ public class AccessibilityManagerServiceTest {
        LocalServices.removeServiceForTest(UserManagerInternal.class);
        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
        LocalServices.removeServiceForTest(PermissionEnforcer.class);
        LocalServices.removeServiceForTest(PackageManagerInternal.class);
        LocalServices.addService(
                WindowManagerInternal.class, mMockWindowManagerService);
        LocalServices.addService(
@@ -256,6 +268,12 @@ public class AccessibilityManagerServiceTest {
        mInputFilter = mock(FakeInputFilter.class);
        mTestableContext.addMockSystemService(DevicePolicyManager.class, mDevicePolicyManager);

        when(mMockPackageManagerInternal.getSystemUiServiceComponent()).thenReturn(
                new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService"));
        when(mMockPackageManagerInternal.getPackageUid(eq("com.android.systemui"), anyLong(),
                anyInt())).thenReturn(FAKE_SYSTEMUI_UID);
        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);

        when(mMockMagnificationController.getMagnificationConnectionManager()).thenReturn(
                mMockMagnificationConnectionManager);
        when(mMockMagnificationController.getFullScreenMagnificationController()).thenReturn(
@@ -273,15 +291,9 @@ public class AccessibilityManagerServiceTest {
                eq(UserHandle.USER_CURRENT)))
                .thenReturn(mTestableContext.getUserId());

        final ArrayList<Display> displays = new ArrayList<>();
        final Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(),
                Display.DEFAULT_DISPLAY, new DisplayInfo(),
                DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
        final Display testDisplay = new Display(DisplayManagerGlobal.getInstance(), TEST_DISPLAY,
                new DisplayInfo(), DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
        displays.add(defaultDisplay);
        displays.add(testDisplay);
        when(mMockA11yDisplayListener.getValidDisplayList()).thenReturn(displays);
        mTestDisplayManagerWrapper = new TestDisplayManagerWrapper(mTestableContext);
        mTestDisplayManagerWrapper.mDisplays = createFakeDisplayList(Display.TYPE_INTERNAL,
                Display.TYPE_EXTERNAL);

        mA11yms = new AccessibilityManagerService(
                mTestableContext,
@@ -290,7 +302,7 @@ public class AccessibilityManagerServiceTest {
                mMockSecurityPolicy,
                mMockSystemActionPerformer,
                mMockA11yWindowManager,
                mMockA11yDisplayListener,
                mTestDisplayManagerWrapper,
                mMockMagnificationController,
                mInputFilter,
                mProxyManager,
@@ -2309,6 +2321,73 @@ public class AccessibilityManagerServiceTest {
                mA11yms.getCurrentUserIdLocked())).isEmpty();
    }

    @Test
    public void displayListReturnsDisplays() {
        mTestDisplayManagerWrapper.mDisplays = createFakeDisplayList(
                        Display.TYPE_INTERNAL,
                        Display.TYPE_EXTERNAL,
                        Display.TYPE_WIFI,
                        Display.TYPE_OVERLAY,
                        Display.TYPE_VIRTUAL
        );
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            // In #setUp() we already have TYPE_INTERNAL and TYPE_EXTERNAL. Call the rest.
            for (int i = 2; i < mTestDisplayManagerWrapper.mDisplays.size(); i++) {
                mTestDisplayManagerWrapper.mRegisteredListener.onDisplayAdded(
                        mTestDisplayManagerWrapper.mDisplays.get(i).getDisplayId());
            }
        });

        List<Display> displays = mA11yms.getValidDisplayList();
        assertThat(displays).hasSize(5);
        assertThat(displays)
                .comparingElementsUsing(
                        Correspondence.transforming(Display::getType, "has a type of"))
                .containsExactly(Display.TYPE_INTERNAL,
                        Display.TYPE_EXTERNAL,
                        Display.TYPE_WIFI,
                        Display.TYPE_OVERLAY,
                        Display.TYPE_VIRTUAL);
    }

    @Test
    public void displayListReturnsDisplays_excludesVirtualPrivate() {
        // Add a private virtual display whose uid is different from systemui.
        final List<Display> displays = createFakeDisplayList(Display.TYPE_INTERNAL,
                Display.TYPE_EXTERNAL);
        displays.add(createFakeVirtualPrivateDisplay(/* displayId= */ 2, FAKE_SYSTEMUI_UID + 100));
        mTestDisplayManagerWrapper.mDisplays = displays;
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mTestDisplayManagerWrapper.mRegisteredListener.onDisplayAdded(2);
        });

        List<Display> validDisplays = mA11yms.getValidDisplayList();
        assertThat(validDisplays).hasSize(2);
        assertThat(validDisplays)
                .comparingElementsUsing(
                        Correspondence.transforming(Display::getType, "has a type of"))
                .doesNotContain(Display.TYPE_VIRTUAL);
    }

    @Test
    public void displayListReturnsDisplays_includesVirtualSystemUIPrivate() {
        // Add a private virtual display whose uid is systemui.
        final List<Display> displays = createFakeDisplayList(Display.TYPE_INTERNAL,
                Display.TYPE_EXTERNAL);
        displays.add(createFakeVirtualPrivateDisplay(/* displayId= */ 2, FAKE_SYSTEMUI_UID));
        mTestDisplayManagerWrapper.mDisplays = displays;
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            mTestDisplayManagerWrapper.mRegisteredListener.onDisplayAdded(2);
        });

        List<Display> validDisplays = mA11yms.getValidDisplayList();
        assertThat(validDisplays).hasSize(3);
        assertThat(validDisplays)
                .comparingElementsUsing(
                        Correspondence.transforming(Display::getType, "has a type of"))
                .contains(Display.TYPE_VIRTUAL);
    }

    private Set<String> readStringsFromSetting(String setting) {
        final Set<String> result = new ArraySet<>();
        mA11yms.readColonDelimitedSettingToSet(
@@ -2422,6 +2501,27 @@ public class AccessibilityManagerServiceTest {
                });
    }

    private static List<Display> createFakeDisplayList(int... types) {
        final ArrayList<Display> displays = new ArrayList<>();
        for (int i = 0; i < types.length; i++) {
            final DisplayInfo info = new DisplayInfo();
            info.type = types[i];
            final Display display = new Display(DisplayManagerGlobal.getInstance(),
                    i, info, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
            displays.add(display);
        }
        return displays;
    }

    private static Display createFakeVirtualPrivateDisplay(int displayId, int uid) {
        final DisplayInfo info = new DisplayInfo();
        info.type = Display.TYPE_VIRTUAL;
        info.flags |= Display.FLAG_PRIVATE;
        info.ownerUid = uid;
        return new Display(DisplayManagerGlobal.getInstance(),
                displayId, info, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
    }

    public static class FakeInputFilter extends AccessibilityInputFilter {
        FakeInputFilter(Context context,
                AccessibilityManagerService service) {
@@ -2506,4 +2606,35 @@ public class AccessibilityManagerServiceTest {
        Set<String> setting = readStringsFromSetting(ShortcutUtils.convertToKey(shortcutType));
        assertThat(setting).containsExactlyElementsIn(value);
    }

    private static class TestDisplayManagerWrapper extends
            AccessibilityDisplayListener.DisplayManagerWrapper {
        List<Display> mDisplays;
        DisplayManager.DisplayListener mRegisteredListener;

        TestDisplayManagerWrapper(Context context) {
            super(context);
        }

        @Override
        public Display[] getDisplays() {
            return mDisplays.toArray(new Display[0]);
        }

        @Override
        public Display getDisplay(int displayId) {
            for (final Display display : mDisplays) {
                if (display.getDisplayId() == displayId) {
                    return display;
                }
            }
            return null;
        }

        @Override
        public void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
                @Nullable Handler handler) {
            mRegisteredListener = listener;
        }
    }
}