Migrate model tests to multivalent
Also migrating some other tests that have been verified
Test: SysUI studio
Test: atest NexusLauncherRoboTests
Flag: TEST_ONLY
Change-Id: I072201b8e7b98945ca88657fe813fef4727f16e4
diff --git a/tests/Android.bp b/tests/Android.bp
index c99f656..9945570 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -160,7 +160,7 @@
}
filegroup {
- name: "launcher-testing-helpers",
+ name: "launcher-testing-helpers-multivalent",
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -174,11 +174,20 @@
// 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 @@
":launcher3-robo-src",
// Test util classes
- ":launcher-testing-helpers",
+ ":launcher-testing-helpers-multivalent",
":launcher-testing-shared",
],
exclude_srcs: [
diff --git a/tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
diff --git a/tests/src/com/android/launcher3/folder/FolderPagedViewTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderPagedViewTest.kt
diff --git a/tests/src/com/android/launcher3/folder/FolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/folder/FolderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/FolderTest.kt
diff --git a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
rename to tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
index 7242e9c..b9b7d6a 100644
--- a/tests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewBackgroundTest.java
@@ -24,15 +24,15 @@
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.MockitoAnnotations;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@UiThreadTest
+@RunWith(LauncherMultivalentJUnit.class)
public class PreviewBackgroundTest {
private static final float REST_SCALE = 1f;
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 7c9f99a..d236551 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -29,6 +29,7 @@
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.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 @@
@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>
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 370af0c..43dc36b 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -27,6 +27,7 @@
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 @@
@RunWith(AndroidJUnit4::class)
class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
+ @get:Rule val modelTestRule = ModelTestRule()
+
private lateinit var mDataModelCallbacks: MyCallbacks
private val mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder = mock()
diff --git a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
similarity index 99%
rename from tests/src/com/android/launcher3/model/AsyncBindingTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
index af367a8..dce75b9 100644
--- a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
@@ -64,6 +64,8 @@
@get:Rule val setFlagsRule = SetFlagsRule()
+ @get:Rule val modelTestRule = ModelTestRule()
+
@Spy private var callbacks = MyCallbacks()
@Mock private lateinit var itemInflater: ItemInflater<*>
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
similarity index 84%
rename from tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 328558d..535080a 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -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 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 @@
@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 @@
@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);
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
similarity index 93%
rename from tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 10785f7..e14e145 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -22,11 +22,11 @@
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 org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,8 +50,10 @@
@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 @@
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)
diff --git a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
index aadf72e..d2d9512 100644
--- a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
@@ -21,6 +21,7 @@
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.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"
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
similarity index 96%
rename from tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index c4a4c9b..d002493 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -23,12 +23,14 @@
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 @@
@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 @@
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() }
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/model/LoaderCursorTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
index b4945d7..ac911b3 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -67,6 +67,7 @@
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 @@
@RunWith(AndroidJUnit4.class)
public class LoaderCursorTest {
+ @Rule public ModelTestRule rule = new ModelTestRule();
+
private LauncherModelHelper mModelHelper;
private LauncherAppState mApp;
private PackageManagerHelper mPmHelper;
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt b/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt
new file mode 100644
index 0000000..ad2c2a4
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/model/ModelTestRule.kt
@@ -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()
+ }
+}
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
similarity index 87%
rename from tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
rename to tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index 4ba61ac..a0d9da9 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -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 org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,6 +48,8 @@
@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";
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
similarity index 81%
rename from tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 6cf3b19..1d9c161 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -25,10 +25,9 @@
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_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.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.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.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 @@
mock<Context>().apply {
whenever(packageManager).thenReturn(mock())
whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+ whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
}
mockAppState =
mock<LauncherAppState>().apply {
@@ -666,142 +667,6 @@
}
@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
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
index b3d02be..ae8e966 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
@@ -21,6 +21,7 @@
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 @@
@RunWith(AndroidJUnit4::class)
class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
+ @get:Rule val modelTestRule = ModelTestRule()
+
private val mItemSpaceFinder = WorkspaceItemSpaceFinder()
@Before
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt b/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
index b531adb..d860710 100644
--- a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
@@ -26,6 +26,7 @@
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.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 @@
@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 @@
@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 @@
@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
diff --git a/tests/src/com/android/launcher3/pm/UserCacheTest.kt b/tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
similarity index 97%
rename from tests/src/com/android/launcher3/pm/UserCacheTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
index b21219e..482dced 100644
--- a/tests/src/com/android/launcher3/pm/UserCacheTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/pm/UserCacheTest.kt
@@ -20,6 +20,7 @@
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.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
diff --git a/tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/TouchEventGenerator.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index aa7f388..b933ed2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -26,6 +26,7 @@
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 @@
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 @@
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() {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index f18c02b..2d53e29 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -45,21 +45,24 @@
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 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 @@
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 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 @@
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 @@
}
};
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 @@
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();
}
diff --git a/tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
similarity index 86%
rename from tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
index 011d138..d26c4d4 100644
--- a/tests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ViewOnDrawExecutorTest.kt
@@ -32,7 +32,7 @@
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 @@
underTest.attachTo(launcher)
verify(workspace).addOnAttachStateChangeListener(same(underTest))
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(rootView)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(rootView)
}
@Test
@@ -100,8 +100,8 @@
underTest.onViewAttachedToWindow(rootView)
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(rootView)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(rootView)
}
@Test
@@ -117,10 +117,10 @@
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 @@
underTest.run()
- verifyZeroInteractions(runnable)
- verifyZeroInteractions(viewTreeObserver)
- verifyZeroInteractions(workspace)
- verifyZeroInteractions(consumer)
+ verifyNoMoreInteractions(runnable)
+ verifyNoMoreInteractions(viewTreeObserver)
+ verifyNoMoreInteractions(workspace)
+ verifyNoMoreInteractions(consumer)
}
@Test
@@ -160,7 +160,7 @@
verify(runnable).run()
verify(consumer).accept(underTest)
- verifyZeroInteractions(workspace)
+ verifyNoMoreInteractions(workspace)
}
@Test
@@ -179,8 +179,8 @@
fun cancel_notRun() {
underTest.cancel()
- verifyZeroInteractions(runnable)
+ verifyNoMoreInteractions(runnable)
verify(consumer).accept(underTest)
- verifyZeroInteractions(workspace)
+ verifyNoMoreInteractions(workspace)
}
}
diff --git a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt b/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
index d9af07a..05f626d 100644
--- a/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/PackageUpdatedTaskTest.kt
@@ -58,7 +58,8 @@
@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()
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
new file mode 100644
index 0000000..b93c305
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
@@ -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
+ )
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
similarity index 100%
rename from tests/multivalentTests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
rename to tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
diff --git a/tests/src/com/android/launcher3/util/RoboApiWrapper.kt b/tests/src/com/android/launcher3/util/RoboApiWrapper.kt
new file mode 100644
index 0000000..583652d
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/RoboApiWrapper.kt
@@ -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) {}
+}
diff --git a/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt b/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt
new file mode 100644
index 0000000..9232268
--- /dev/null
+++ b/tests/src_deviceless/com/android/launcher3/util/RoboApiWrapper.kt
@@ -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()
+ }
+}