Merge "Migrate model tests to multivalent" into main

This commit is contained in:
Uwais Ashraf
2024-08-21 10:05:40 +00:00
committed by Android (Google) Code Review
27 changed files with 673 additions and 193 deletions
+11 -2
View File
@@ -160,7 +160,7 @@ android_library {
}
filegroup {
name: "launcher-testing-helpers",
name: "launcher-testing-helpers-multivalent",
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -174,11 +174,20 @@ filegroup {
// Test classes
"src/**/*Test.java",
"src/**/*Test.kt",
"src/**/RoboApiWrapper.kt",
"multivalentTests/src/**/*Test.java",
"multivalentTests/src/**/*Test.kt",
],
}
filegroup {
name: "launcher-testing-helpers",
srcs: [
":launcher-testing-helpers-multivalent",
"src/**/RoboApiWrapper.kt",
],
}
android_robolectric_test {
enabled: true,
name: "Launcher3RoboTests",
@@ -186,7 +195,7 @@ android_robolectric_test {
":launcher3-robo-src",
// Test util classes
":launcher-testing-helpers",
":launcher-testing-helpers-multivalent",
":launcher-testing-shared",
],
exclude_srcs: [
@@ -24,15 +24,15 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.PathInterpolator;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.CellLayout;
import com.android.launcher3.util.LauncherMultivalentJUnit;
import org.junit.Before;
import org.junit.Test;
@@ -41,8 +41,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@UiThreadTest
@RunWith(LauncherMultivalentJUnit.class)
public class PreviewBackgroundTest {
private static final float REST_SCALE = 1f;
@@ -29,6 +29,7 @@ import com.android.launcher3.graphics.PreloadIconDrawable
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.FastBitmapDrawable
import com.android.launcher3.icons.UserBadgeDrawable
import com.android.launcher3.model.ModelTestRule
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED
@@ -44,6 +45,7 @@ import com.android.launcher3.util.UserIconInfo
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -52,6 +54,8 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class PreviewItemManagerTest {
@get:Rule val modelTestRule = ModelTestRule()
private lateinit var previewItemManager: PreviewItemManager
private lateinit var context: Context
private lateinit var folderItems: ArrayList<ItemInfo>
@@ -27,6 +27,7 @@ import com.android.launcher3.util.TestUtil.runOnExecutorSync
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.times
@@ -43,6 +44,8 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
@get:Rule val modelTestRule = ModelTestRule()
private lateinit var mDataModelCallbacks: MyCallbacks
private val mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder = mock()
@@ -64,6 +64,8 @@ class AsyncBindingTest {
@get:Rule val setFlagsRule = SetFlagsRule()
@get:Rule val modelTestRule = ModelTestRule()
@Spy private var callbacks = MyCallbacks()
@Mock private lateinit var itemInflater: ItemInflater<*>
@@ -1,3 +1,18 @@
/*
* Copyright (C) 2024 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.launcher3.model;
import static android.os.Process.myUserHandle;
@@ -11,10 +26,13 @@ import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.pm.PackageInstaller;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -49,6 +67,9 @@ public class CacheDataUpdatedTaskTest {
@Rule(order = 0)
public TestRule testStabilityRule = new TestStabilityRule();
@Rule(order = 1)
public ModelTestRule mModelTestRule = new ModelTestRule();
private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
@@ -128,10 +149,13 @@ public class CacheDataUpdatedTaskTest {
@Test
public void testSessionUpdate_updates_pending_apps() {
// Run on model executor so that no other task runs in the middle.
PackageInstaller.SessionInfo sessionInfo = ApplicationProvider.getApplicationContext()
.getPackageManager().getPackageInstaller().getSessionInfo(mSession1);
assertNotNull(sessionInfo);
runOnExecutorSync(MODEL_EXECUTOR, () -> {
LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
new PackageUserKey(PENDING_APP_1, myUserHandle()),
mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession1));
sessionInfo);
// Clear all icons from apps list so that its easy to check what was updated
allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
@@ -22,11 +22,11 @@ import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -39,6 +39,7 @@ import com.android.launcher3.util.LauncherModelHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,8 +50,10 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DefaultLayoutProviderTest {
@Rule public ModelTestRule rule = new ModelTestRule();
private LauncherModelHelper mModelHelper;
private Context mTargetContext;
private LauncherModelHelper.SandboxModelContext mTargetContext;
@Before
public void setUp() {
@@ -114,8 +117,10 @@ public class DefaultLayoutProviderTest {
SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(pendingAppPkg);
params.setAppIcon(BitmapInfo.LOW_RES_ICON);
params.installerPackageName = ApplicationProvider.getApplicationContext().getPackageName();
PackageInstaller installer = mTargetContext.getPackageManager().getPackageInstaller();
PackageInstaller installer = ApplicationProvider.getApplicationContext().getPackageManager()
.getPackageInstaller();
installer.createSession(params);
writeLayoutAndLoad(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
@@ -21,6 +21,7 @@ import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageInstaller.SessionInfo
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
@@ -33,14 +34,20 @@ import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
import junit.framework.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class FirstScreenBroadcastHelperTest {
@get:Rule val modelTestRule = ModelTestRule()
private val context = spy(InstrumentationRegistry.getInstrumentation().targetContext)
private val mockPmHelper = mock<PackageManagerHelper>()
private val expectedAppPackage = "appPackageExpected"
@@ -23,12 +23,14 @@ import com.android.launcher3.util.Executors
import com.android.launcher3.util.LauncherLayoutBuilder
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.LauncherModelHelper.*
import com.android.launcher3.util.RoboApiWrapper
import com.android.launcher3.util.TestUtil
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.concurrent.CountDownLatch
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,6 +38,9 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class FolderIconLoadTest {
@get:Rule(order = 0) val modelTestRule = ModelTestRule()
private lateinit var modelHelper: LauncherModelHelper
private val uniqueActivities =
@@ -145,6 +150,7 @@ class FolderIconLoadTest {
while (cache.isIconUpdateInProgress) {
val wait = CountDownLatch(1)
Executors.MODEL_EXECUTOR.handler.postDelayed({ wait.countDown() }, 10)
RoboApiWrapper.waitForLooperSync(Executors.MODEL_EXECUTOR.handler.looper)
wait.await()
}
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { cache.clearMemoryCache() }
@@ -67,6 +67,7 @@ import com.android.launcher3.util.PackageManagerHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -77,6 +78,8 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class LoaderCursorTest {
@Rule public ModelTestRule rule = new ModelTestRule();
private LauncherModelHelper mModelHelper;
private LauncherAppState mApp;
private PackageManagerHelper mPmHelper;
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2024 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.launcher3.model
import com.android.launcher3.util.RoboApiWrapper
import org.junit.rules.TestWatcher
import org.junit.runner.Description
class ModelTestRule : TestWatcher() {
override fun starting(description: Description?) {
RoboApiWrapper.initialize()
}
}
@@ -1,3 +1,18 @@
/*
* Copyright (C) 2024 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.launcher3.model;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -22,6 +37,7 @@ import com.android.launcher3.util.LauncherModelHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,6 +48,8 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class PackageInstallStateChangedTaskTest {
@Rule public ModelTestRule mModelTestRule = new ModelTestRule();
private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
@@ -25,10 +25,9 @@ import android.content.pm.PackageInstaller
import android.content.pm.ShortcutInfo
import android.os.Process
import android.os.UserHandle
import android.platform.test.annotations.EnableFlags
import android.util.LongSparseArray
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
@@ -36,7 +35,6 @@ import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_INFO
@@ -46,7 +44,6 @@ import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.IconRequestInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.pm.UserCache
@@ -57,11 +54,12 @@ import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.UserIconInfo
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
import com.android.launcher3.widget.WidgetInflater
import com.android.launcher3.widget.WidgetSections
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.RETURNS_DEEP_STUBS
@@ -74,10 +72,12 @@ import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class)
class WorkspaceItemProcessorTest {
@get:Rule val modelTestRule = ModelTestRule()
@Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
@Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
@Mock private lateinit var mockBgDataModel: BgDataModel
@@ -122,6 +122,7 @@ class WorkspaceItemProcessorTest {
mock<Context>().apply {
whenever(packageManager).thenReturn(mock())
whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
}
mockAppState =
mock<LauncherAppState>().apply {
@@ -665,142 +666,6 @@ class WorkspaceItemProcessorTest {
)
}
@Test
fun `When Pending App Widget has not started restore then update db and add item`() {
val mockitoSession =
ExtendedMockito.mockitoSession()
.strictness(Strictness.LENIENT)
.mockStatic(WidgetSections::class.java)
.startMocking()
try {
// Given
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
val expectedComponentName =
ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
val expectedAppWidgetId = 0
mockCursor.apply {
itemType = ITEM_TYPE_APPWIDGET
user = mUserHandle
restoreFlag = FLAG_UI_NOT_READY
container = CONTAINER_DESKTOP
whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
whenever(appWidgetProvider).thenReturn(expectedProvider)
whenever(appWidgetId).thenReturn(expectedAppWidgetId)
whenever(spanX).thenReturn(2)
whenever(spanY).thenReturn(1)
whenever(options).thenReturn(0)
whenever(appWidgetSource).thenReturn(20)
whenever(applyCommonProperties(any())).thenCallRealMethod()
whenever(
updater()
.put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
.put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
.put(Favorites.RESTORED, expectedRestoreStatus)
.commit()
)
.thenReturn(1)
}
val inflationResult =
WidgetInflater.InflationResult(
type = WidgetInflater.TYPE_PENDING,
widgetInfo = null
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
whenever(inflateAppWidget(any())).thenReturn(inflationResult)
}
val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
// When
itemProcessorUnderTest =
createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
itemProcessorUnderTest.processItem()
// Then
val expectedWidgetInfo =
LauncherAppWidgetInfo().apply {
appWidgetId = expectedAppWidgetId
providerName = ComponentName.unflattenFromString(expectedProvider)
restoreStatus = expectedRestoreStatus
}
verify(
mockCursor
.updater()
.put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
.put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
.put(Favorites.RESTORED, expectedRestoreStatus)
)
.commit()
val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
val actualWidgetInfo = widgetInfoCaptor.value
with(actualWidgetInfo) {
assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
}
} finally {
mockitoSession.finishMocking()
}
}
@Test
@EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
fun `When Archived Pending App Widget then checkAndAddItem`() {
val mockitoSession =
ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
try {
// Given
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
val expectedPackage = expectedComponentName!!.packageName
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(isAppArchived(expectedPackage)).thenReturn(true)
}
mockCursor =
mock<LoaderCursor>().apply {
itemType = ITEM_TYPE_APPWIDGET
id = 1
user = UserHandle(1)
restoreFlag = FLAG_UI_NOT_READY
container = CONTAINER_DESKTOP
whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
whenever(appWidgetProvider).thenReturn(expectedProvider)
whenever(appWidgetId).thenReturn(0)
whenever(spanX).thenReturn(2)
whenever(spanY).thenReturn(1)
whenever(options).thenReturn(0)
whenever(appWidgetSource).thenReturn(20)
whenever(applyCommonProperties(any())).thenCallRealMethod()
}
mInstallingPkgs = hashMapOf()
val inflationResult =
WidgetInflater.InflationResult(
type = WidgetInflater.TYPE_PENDING,
widgetInfo = null
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
whenever(inflateAppWidget(any())).thenReturn(inflationResult)
}
itemProcessorUnderTest =
createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
// When
itemProcessorUnderTest.processItem()
// Then
verify(mockCursor).checkAndAddItem(any(), any())
} finally {
mockitoSession.finishMocking()
}
}
@Test
fun `When widget inflation result is TYPE_DELETE then mark deleted`() {
// Given
@@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,6 +30,8 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
@get:Rule val modelTestRule = ModelTestRule()
private val mItemSpaceFinder = WorkspaceItemSpaceFinder()
@Before
@@ -26,6 +26,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
import com.android.launcher3.model.ModelTestRule
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.PackageUserKey
@@ -35,6 +36,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
@@ -43,7 +45,9 @@ import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
class InstallSessionTrackerTest {
@get:Rule val setFlagsRule = SetFlagsRule()
@get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
@get:Rule(order = 1) val modelTestRule = ModelTestRule()
private val mockInstallSessionHelper: InstallSessionHelper = mock()
private val mockCallback: InstallSessionTracker.Callback = mock()
@@ -200,13 +204,9 @@ class InstallSessionTrackerTest {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
fun `register triggers registerPackageInstallerSessionCallback for versions from Q`() {
// Given
whenever(
launcherApps.registerPackageInstallerSessionCallback(
MODEL_EXECUTOR,
installSessionTracker
)
)
.then { /* no-op */ }
doNothing()
.whenever(launcherApps)
.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, installSessionTracker)
// When
installSessionTracker.register()
// Then
@@ -218,8 +218,9 @@ class InstallSessionTrackerTest {
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
fun `unregister triggers unregisterPackageInstallerSessionCallback for versions from Q`() {
// Given
whenever(launcherApps.unregisterPackageInstallerSessionCallback(installSessionTracker))
.then { /* no-op */ }
doNothing()
.whenever(launcherApps)
.unregisterPackageInstallerSessionCallback(installSessionTracker)
// When
installSessionTracker.unregister()
// Then
@@ -20,6 +20,7 @@ import android.os.Process.myUserHandle
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.model.ModelTestRule
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.TestUtil
@@ -27,11 +28,15 @@ import com.android.launcher3.util.UserIconInfo
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class UserCacheTest {
@get:Rule val modelTestRule = ModelTestRule()
private val launcherModelHelper = LauncherModelHelper()
private val sandboxContext = launcherModelHelper.sandboxContext
private lateinit var userCache: UserCache
@@ -26,6 +26,7 @@ import static com.android.launcher3.BubbleTextView.DISPLAY_ALL_APPS;
import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT;
import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT_SMALL;
import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
import static com.android.launcher3.Flags.FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS;
import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
@@ -416,7 +417,7 @@ public class BubbleTextViewTest {
assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(false);
}
@EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
@EnableFlags({FLAG_ENABLE_SUPPORT_FOR_ARCHIVING, FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS})
@Test
public void applyIconAndLabel_setsImageSpan_whenInactiveArchivedApp() {
// Given
@@ -452,7 +453,7 @@ public class BubbleTextViewTest {
assertThat(actualSpan.getVerticalAlignment()).isEqualTo(ALIGN_CENTER);
}
@EnableFlags(FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS)
@EnableFlags({FLAG_ENABLE_SUPPORT_FOR_ARCHIVING, FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS})
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.S)
@Test
public void applyIconAndLabel_setsBoldDrawable_whenBoldedTextForArchivedApp() {
@@ -45,21 +45,24 @@ import android.test.mock.MockContentResolver;
import android.util.ArrayMap;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.testing.TestInformationProvider;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@@ -85,6 +88,23 @@ public class LauncherModelHelper {
public static final String TEST_ACTIVITY13 = "com.android.launcher3.tests.Activity14";
public static final String TEST_ACTIVITY14 = "com.android.launcher3.tests.Activity15";
public static final List<String> ACTIVITY_LIST = Arrays.asList(
TEST_ACTIVITY,
TEST_ACTIVITY2,
TEST_ACTIVITY3,
TEST_ACTIVITY4,
TEST_ACTIVITY5,
TEST_ACTIVITY6,
TEST_ACTIVITY7,
TEST_ACTIVITY8,
TEST_ACTIVITY9,
TEST_ACTIVITY10,
TEST_ACTIVITY11,
TEST_ACTIVITY12,
TEST_ACTIVITY13,
TEST_ACTIVITY14
);
// Authority for providing a test default-workspace-layout data.
private static final String TEST_PROVIDER_AUTHORITY =
LauncherModelHelper.class.getName().toLowerCase();
@@ -128,7 +148,9 @@ public class LauncherModelHelper {
icon.eraseColor(Color.RED);
sp.setAppIcon(icon);
sp.setAppLabel(pkg);
PackageInstaller pi = sandboxContext.getPackageManager().getPackageInstaller();
sp.setInstallerPackageName(ApplicationProvider.getApplicationContext().getPackageName());
PackageInstaller pi = ApplicationProvider.getApplicationContext().getPackageManager()
.getPackageInstaller();
int sessionId = pi.createSession(sp);
mDestroyTask.add(() -> pi.abandonSession(sessionId));
return sessionId;
@@ -164,11 +186,19 @@ public class LauncherModelHelper {
public LauncherModelHelper setupDefaultLayoutProvider(LauncherLayoutBuilder builder)
throws Exception {
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(sandboxContext);
idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
if (idp.numRows == 0 && idp.numColumns == 0) {
idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE;
}
if (idp.iconBitmapSize == 0) {
idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
}
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
"settings put secure launcher3.layout.provider " + TEST_PROVIDER_AUTHORITY);
Settings.Secure.putString(sandboxContext.getContentResolver(), "launcher3.layout.provider",
TEST_PROVIDER_AUTHORITY);
// TODO: use a wrapper class to differentiate the behavior
ByteArrayOutputStream bos = new ByteArrayOutputStream();
builder.build(new OutputStreamWriter(bos));
ContentProvider cp = new TestInformationProvider() {
@Override
@@ -177,8 +207,6 @@ public class LauncherModelHelper {
try {
ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
AutoCloseOutputStream outputStream = new AutoCloseOutputStream(pipe[1]);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
builder.build(new OutputStreamWriter(bos));
outputStream.write(bos.toByteArray());
outputStream.flush();
outputStream.close();
@@ -189,9 +217,13 @@ public class LauncherModelHelper {
}
};
setupProvider(TEST_PROVIDER_AUTHORITY, cp);
RoboApiWrapper.INSTANCE.registerInputStream(sandboxContext.getContentResolver(),
ModelDbController.getLayoutUri(TEST_PROVIDER_AUTHORITY, sandboxContext),
()-> new ByteArrayInputStream(bos.toByteArray()));
mDestroyTask.add(() -> runOnExecutorSync(MODEL_EXECUTOR, () ->
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
"settings delete secure launcher3.layout.provider")));
Settings.Secure.putString(sandboxContext.getContentResolver(),
"launcher3.layout.provider", "")));
return this;
}
@@ -203,7 +235,7 @@ public class LauncherModelHelper {
MAIN_EXECUTOR.submit(() -> getModel().addCallbacksAndLoad(mockCb)).get();
Executors.MODEL_EXECUTOR.submit(() -> { }).get();
MAIN_EXECUTOR.submit(() -> { }).get();
getInstrumentation().waitForIdleSync();
MAIN_EXECUTOR.submit(() -> getModel().removeCallbacks(mockCb)).get();
}
@@ -32,7 +32,7 @@ import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.reset
import org.mockito.kotlin.same
import org.mockito.kotlin.verifyZeroInteractions
import org.mockito.kotlin.verifyNoMoreInteractions
@RunWith(AndroidJUnit4::class)
class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
@@ -77,8 +77,8 @@ class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
underTest.attachTo(launcher)
verify(workspace).addOnAttachStateChangeListener(same(underTest))
verifyZeroInteractions(viewTreeObserver)
verifyZeroInteractions(rootView)
verifyNoMoreInteractions(viewTreeObserver)
verifyNoMoreInteractions(rootView)
}
@Test
@@ -100,8 +100,8 @@ class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
underTest.onViewAttachedToWindow(rootView)
verifyZeroInteractions(viewTreeObserver)
verifyZeroInteractions(rootView)
verifyNoMoreInteractions(viewTreeObserver)
verifyNoMoreInteractions(rootView)
}
@Test
@@ -117,10 +117,10 @@ class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
fun run_before_onDraw_noOp() {
underTest.run()
verifyZeroInteractions(runnable)
verifyZeroInteractions(viewTreeObserver)
verifyZeroInteractions(workspace)
verifyZeroInteractions(consumer)
verifyNoMoreInteractions(runnable)
verifyNoMoreInteractions(viewTreeObserver)
verifyNoMoreInteractions(workspace)
verifyNoMoreInteractions(consumer)
}
@Test
@@ -148,10 +148,10 @@ class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
underTest.run()
verifyZeroInteractions(runnable)
verifyZeroInteractions(viewTreeObserver)
verifyZeroInteractions(workspace)
verifyZeroInteractions(consumer)
verifyNoMoreInteractions(runnable)
verifyNoMoreInteractions(viewTreeObserver)
verifyNoMoreInteractions(workspace)
verifyNoMoreInteractions(consumer)
}
@Test
@@ -160,7 +160,7 @@ class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
verify(runnable).run()
verify(consumer).accept(underTest)
verifyZeroInteractions(workspace)
verifyNoMoreInteractions(workspace)
}
@Test
@@ -179,8 +179,8 @@ class ViewOnDrawExecutorTest<T> where T : View, T : PageIndicator {
fun cancel_notRun() {
underTest.cancel()
verifyZeroInteractions(runnable)
verifyNoMoreInteractions(runnable)
verify(consumer).accept(underTest)
verifyZeroInteractions(workspace)
verifyNoMoreInteractions(workspace)
}
}
@@ -58,7 +58,8 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class PackageUpdatedTaskTest {
@get:Rule val setFlagsRule = SetFlagsRule()
@get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
@get:Rule(order = 1) val modelTestRule = ModelTestRule()
private val mUser = UserHandle(0)
private val mDataModel: BgDataModel = BgDataModel()
@@ -0,0 +1,338 @@
/*
* Copyright (C) 2024 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.launcher3.model
import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.content.pm.PackageInstaller
import android.content.pm.ShortcutInfo
import android.os.UserHandle
import android.platform.test.annotations.EnableFlags
import android.util.LongSparseArray
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
import com.android.launcher3.Utilities
import com.android.launcher3.model.data.IconRequestInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.pm.UserCache
import com.android.launcher3.shortcuts.ShortcutKey
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.UserIconInfo
import com.android.launcher3.widget.WidgetInflater
import com.android.launcher3.widget.WidgetSections
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.RETURNS_DEEP_STUBS
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class)
class WorkspaceItemProcessorExtraTest {
@Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
@Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
@Mock private lateinit var mockBgDataModel: BgDataModel
@Mock private lateinit var mockContext: Context
@Mock private lateinit var mockAppState: LauncherAppState
@Mock private lateinit var mockPmHelper: PackageManagerHelper
@Mock private lateinit var mockLauncherApps: LauncherApps
@Mock private lateinit var mockCursor: LoaderCursor
@Mock private lateinit var mockUserCache: UserCache
@Mock private lateinit var mockUserManagerState: UserManagerState
@Mock private lateinit var mockWidgetInflater: WidgetInflater
private var intent: Intent = Intent()
private var mUserHandle: UserHandle = UserHandle(0)
private var mIconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf()
private var mComponentName: ComponentName = ComponentName("package", "class")
private var mUnlockedUsersArray: LongSparseArray<Boolean> = LongSparseArray()
private var mKeyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo> = mutableMapOf()
private var mInstallingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf()
private var mAllDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
private var mWidgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> =
mutableMapOf()
private var mPendingPackages: MutableSet<PackageUserKey> = mutableSetOf()
private lateinit var itemProcessorUnderTest: WorkspaceItemProcessor
@Before
fun setup() {
mUserHandle = UserHandle(0)
mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
mockWorkspaceInfo = mock<WorkspaceItemInfo>()
mockBgDataModel = mock<BgDataModel>()
mComponentName = ComponentName("package", "class")
mUnlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
intent =
Intent().apply {
component = mComponentName
`package` = "pkg"
putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
}
mockContext =
mock<Context>().apply {
whenever(packageManager).thenReturn(mock())
whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
}
mockAppState =
mock<LauncherAppState>().apply {
whenever(context).thenReturn(mockContext)
whenever(iconCache).thenReturn(mock())
whenever(iconCache.getShortcutIcon(any(), any(), any())).then {}
}
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
.thenReturn(intent)
}
mockLauncherApps =
mock<LauncherApps>().apply {
whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
}
mockCursor =
Mockito.mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
user = mUserHandle
itemType = ITEM_TYPE_APPLICATION
id = 1
restoreFlag = 1
serialNumber = 101
whenever(parseIntent()).thenReturn(intent)
whenever(markRestored()).doAnswer { restoreFlag = 0 }
whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
whenever(getAppShortcutInfo(any(), any(), any(), any()))
.thenReturn(mockWorkspaceInfo)
whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
}
mockUserCache =
mock<UserCache>().apply {
val userIconInfo =
mock<UserIconInfo>().apply { whenever(isPrivate).thenReturn(false) }
whenever(getUserInfo(any())).thenReturn(userIconInfo)
}
mockUserManagerState = mock<UserManagerState>()
mockWidgetInflater = mock<WidgetInflater>()
mKeyToPinnedShortcutsMap = mutableMapOf()
mInstallingPkgs = hashMapOf()
mAllDeepShortcuts = mutableListOf()
mWidgetProvidersMap = mutableMapOf()
mIconRequestInfos = mutableListOf()
mPendingPackages = mutableSetOf()
}
@Test
fun `When Pending App Widget has not started restore then update db and add item`() {
val mockitoSession =
ExtendedMockito.mockitoSession()
.strictness(Strictness.LENIENT)
.mockStatic(WidgetSections::class.java)
.startMocking()
try {
// Given
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
val expectedComponentName =
ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
val expectedAppWidgetId = 0
mockCursor.apply {
itemType = ITEM_TYPE_APPWIDGET
user = mUserHandle
restoreFlag = FLAG_UI_NOT_READY
container = CONTAINER_DESKTOP
whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
whenever(appWidgetProvider).thenReturn(expectedProvider)
whenever(appWidgetId).thenReturn(expectedAppWidgetId)
whenever(spanX).thenReturn(2)
whenever(spanY).thenReturn(1)
whenever(options).thenReturn(0)
whenever(appWidgetSource).thenReturn(20)
whenever(applyCommonProperties(any())).thenCallRealMethod()
whenever(
updater()
.put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
.put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
.put(Favorites.RESTORED, expectedRestoreStatus)
.commit()
)
.thenReturn(1)
}
val inflationResult =
WidgetInflater.InflationResult(
type = WidgetInflater.TYPE_PENDING,
widgetInfo = null
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
whenever(inflateAppWidget(any())).thenReturn(inflationResult)
}
val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
// When
itemProcessorUnderTest =
createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
itemProcessorUnderTest.processItem()
// Then
val expectedWidgetInfo =
LauncherAppWidgetInfo().apply {
appWidgetId = expectedAppWidgetId
providerName = ComponentName.unflattenFromString(expectedProvider)
restoreStatus = expectedRestoreStatus
}
verify(
mockCursor
.updater()
.put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
.put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
.put(Favorites.RESTORED, expectedRestoreStatus)
)
.commit()
val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
val actualWidgetInfo = widgetInfoCaptor.value
with(actualWidgetInfo) {
assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
}
} finally {
mockitoSession.finishMocking()
}
}
@Test
@EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
fun `When Archived Pending App Widget then checkAndAddItem`() {
val mockitoSession =
ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
try {
// Given
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
val expectedPackage = expectedComponentName!!.packageName
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(isAppArchived(expectedPackage)).thenReturn(true)
}
mockCursor =
mock<LoaderCursor>().apply {
itemType = ITEM_TYPE_APPWIDGET
id = 1
user = UserHandle(1)
restoreFlag = FLAG_UI_NOT_READY
container = CONTAINER_DESKTOP
whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
whenever(appWidgetProvider).thenReturn(expectedProvider)
whenever(appWidgetId).thenReturn(0)
whenever(spanX).thenReturn(2)
whenever(spanY).thenReturn(1)
whenever(options).thenReturn(0)
whenever(appWidgetSource).thenReturn(20)
whenever(applyCommonProperties(any())).thenCallRealMethod()
}
mInstallingPkgs = hashMapOf()
val inflationResult =
WidgetInflater.InflationResult(
type = WidgetInflater.TYPE_PENDING,
widgetInfo = null
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
whenever(inflateAppWidget(any())).thenReturn(inflationResult)
}
itemProcessorUnderTest =
createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
// When
itemProcessorUnderTest.processItem()
// Then
verify(mockCursor).checkAndAddItem(any(), any())
} finally {
mockitoSession.finishMocking()
}
}
private fun createWorkspaceItemProcessorUnderTest(
cursor: LoaderCursor = mockCursor,
memoryLogger: LoaderMemoryLogger? = null,
userCache: UserCache = mockUserCache,
userManagerState: UserManagerState = mockUserManagerState,
launcherApps: LauncherApps = mockLauncherApps,
shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mKeyToPinnedShortcutsMap,
app: LauncherAppState = mockAppState,
bgDataModel: BgDataModel = mockBgDataModel,
widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mWidgetProvidersMap,
widgetInflater: WidgetInflater = mockWidgetInflater,
pmHelper: PackageManagerHelper = mockPmHelper,
iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mIconRequestInfos,
isSdCardReady: Boolean = false,
pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
) =
WorkspaceItemProcessor(
c = cursor,
memoryLogger = memoryLogger,
userCache = userCache,
userManagerState = userManagerState,
launcherApps = launcherApps,
app = app,
bgDataModel = bgDataModel,
widgetProvidersMap = widgetProvidersMap,
widgetInflater = widgetInflater,
pmHelper = pmHelper,
unlockedUsers = unlockedUsers,
iconRequestInfos = iconRequestInfos,
pendingPackages = pendingPackages,
isSdCardReady = isSdCardReady,
shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
installingPkgs = installingPkgs,
allDeepShortcuts = allDeepShortcuts
)
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2024 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.launcher3.util
import android.content.ContentResolver
import android.net.Uri
import android.os.Looper
import java.io.InputStream
import java.util.function.Supplier
object RoboApiWrapper {
fun initialize() {}
fun registerInputStream(
contentResolver: ContentResolver,
uri: Uri,
inputStreamSupplier: Supplier<InputStream>
) {}
fun waitForLooperSync(looper: Looper) {}
}
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2024 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.launcher3.util
import android.content.ComponentName
import android.content.ContentResolver
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.net.Uri
import android.os.Looper
import android.os.Process
import androidx.test.platform.app.InstrumentationRegistry
import java.io.InputStream
import java.util.function.Supplier
import org.mockito.Mockito
import org.mockito.kotlin.whenever
import org.robolectric.RuntimeEnvironment
import org.robolectric.Shadows
object RoboApiWrapper {
fun initialize() {
Shadows.shadowOf(
RuntimeEnvironment.getApplication().getSystemService(LauncherApps::class.java)
)
.addEnabledPackage(
Process.myUserHandle(),
InstrumentationRegistry.getInstrumentation().context.packageName
)
LauncherModelHelper.ACTIVITY_LIST.forEach {
installApp(ComponentName(InstrumentationRegistry.getInstrumentation().context, it))
}
}
private fun installApp(componentName: ComponentName) {
val app = RuntimeEnvironment.getApplication()
val user = Process.myUserHandle()
val pm = Shadows.shadowOf(app.packageManager)
val ai = pm.addActivityIfNotPresent(componentName)
pm.addIntentFilterForActivity(
componentName,
IntentFilter(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
)
val li = Mockito.mock(LauncherActivityInfo::class.java)
val appInfo = ApplicationInfo().apply { flags = 0 }
Mockito.doReturn(ai).whenever(li).activityInfo
Mockito.doReturn(appInfo).whenever(li).applicationInfo
Mockito.doReturn(user).whenever(li).user
Mockito.doReturn(1f).whenever(li).loadingProgress
Mockito.doReturn(componentName).whenever(li).componentName
Shadows.shadowOf(app.getSystemService(LauncherApps::class.java)).apply {
addActivity(user, li)
addEnabledPackage(user, componentName.packageName)
setActivityEnabled(user, componentName)
addApplicationInfo(user, componentName.packageName, ai.applicationInfo)
}
}
fun registerInputStream(
contentResolver: ContentResolver,
uri: Uri,
inputStreamSupplier: Supplier<InputStream>
) {
Shadows.shadowOf(contentResolver).registerInputStreamSupplier(uri, inputStreamSupplier)
}
fun waitForLooperSync(looper: Looper) {
Shadows.shadowOf(looper).runToEndOfTasks()
}
}