/* * Copyright (C) 2019 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.documentsui; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.om.OverlayInfo; import android.content.om.OverlayManager; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.UserHandle; import androidx.core.util.Consumer; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.documentsui.theme.ThemeOverlayManager; import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @SmallTest @RunWith(AndroidJUnit4.class) public class ThemeOverlayManagerTest { private static final String TEST_DISABLED_PREFIX = "com.example."; private static final String TEST_ENABLED_PREFIX = "com.example.enabled."; private static final String TEST_OVERLAY_PACKAGE = "test.overlay"; private static final String TEST_TARGET_PACKAGE = "test.target"; @Mock OverlayManager mOverlayManager; @Mock PackageManager mPackageManager; Consumer mCallback; Context mContext; CountDownLatch mLatch; ThemeOverlayManager mThemeOverlayManager; UserHandle mUserHandle; @Before public void setUp() throws Exception { InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( "android.permission.CHANGE_OVERLAY_PACKAGES"); MockitoAnnotations.initMocks(this); mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); mLatch = new CountDownLatch(1); mUserHandle = UserHandle.of(UserHandle.myUserId()); mCallback = result -> mLatch.countDown(); when(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(), mUserHandle)).thenReturn(Lists.newArrayList( createOverlayInfo(getOverlayPackageId(), getEnabledTargetPackageId(), true))); when(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId(), mUserHandle)).thenReturn(Lists.newArrayList( createOverlayInfo(getOverlayPackageId(), getDisabledTargetPackageId(), false))); } @Test public void testApplyOverlays_shouldSetEnabled() throws Exception { final boolean enabled = true; mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getDisabledTargetPackageId()); mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback); mLatch.await(5, TimeUnit.SECONDS); verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled, mUserHandle); } @Test public void testApplyOverlays_shouldGetOverlayInfo() throws Exception { mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getEnabledTargetPackageId()); mThemeOverlayManager.applyOverlays(mContext, true /* enabled */, mCallback); mLatch.await(5, TimeUnit.SECONDS); verify(mOverlayManager, times(1)).getOverlayInfosForTarget(getEnabledTargetPackageId(), mUserHandle); } @Test public void testApplyOverlays_shouldCheckEnabled_beforeSetEnabled() { final boolean enabled = true; mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getEnabledTargetPackageId()); mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback); verify(mOverlayManager, never()).setEnabled(getOverlayPackageId(), enabled, mUserHandle); } @Test public void testDefaultDisabled_applyOverlays_shouldEnabled() throws Exception { final boolean enabled = true; assertThat(mOverlayManager.getOverlayInfosForTarget(getDisabledTargetPackageId(), mUserHandle).get(0).isEnabled()).isEqualTo(!enabled); mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getDisabledTargetPackageId()); mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback); mLatch.await(5, TimeUnit.SECONDS); verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled, mUserHandle); } @Test public void testDefaultEnabled_applyOverlays_shouldDisabled() throws Exception { final boolean enabled = false; assertThat(mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(), mUserHandle).get(0).isEnabled()).isEqualTo(!enabled); mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getEnabledTargetPackageId()); mThemeOverlayManager.applyOverlays(mContext, enabled, mCallback); mLatch.await(5, TimeUnit.SECONDS); verify(mOverlayManager, times(1)).setEnabled(getOverlayPackageId(), enabled, mUserHandle); } @Test public void testDefaultEnabled_launchDocumentsUI_shouldSuccess() throws Exception { final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); final Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent); assertThat(activity).isNotNull(); if (activity != null) { activity.finish(); } } @Test public void testGetValidOverlay_system_valid() throws Exception { mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getEnabledTargetPackageId()); ApplicationInfo ai = mock(ApplicationInfo.class); ai.flags |= ApplicationInfo.FLAG_SYSTEM; when(mPackageManager.getApplicationInfo(getOverlayPackageId(), 0)).thenReturn(ai); assertThat(mThemeOverlayManager.getValidOverlay(mPackageManager)).isEqualTo( mOverlayManager.getOverlayInfosForTarget(getEnabledTargetPackageId(), mUserHandle).iterator().next()); } @Test public void testGetValidOverlay_data_invalid() throws Exception { mThemeOverlayManager = new ThemeOverlayManager(mOverlayManager, getEnabledTargetPackageId()); ApplicationInfo ai = mock(ApplicationInfo.class); String path = "/data/app/DocumentUIOverlay/DocumentUIOverlay.apk"; ai.sourceDir = path; when(mPackageManager.getApplicationInfo(getOverlayPackageId(), 0)).thenReturn(ai); assertThat(mThemeOverlayManager.getValidOverlay(mPackageManager)).isEqualTo(null); } private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName, boolean enabled) { return new OverlayInfo(packageName, targetPackageName, null, null, "", enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false); } private static String getDisabledTargetPackageId() { return TEST_DISABLED_PREFIX + TEST_TARGET_PACKAGE; } private static String getEnabledTargetPackageId() { return TEST_ENABLED_PREFIX + TEST_TARGET_PACKAGE; } private static String getOverlayPackageId() { return TEST_DISABLED_PREFIX + TEST_OVERLAY_PACKAGE; } }