From f0ba8b7ca1dc8fd53451d3d16e9f4fc306cddcd4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 9 Sep 2016 15:47:55 -0700 Subject: Moving various runnables in LauncherModel to individual tasks > Adding tests for some of the runnable Change-Id: I1a315d38878857df3371f0e69d622a41fc3b081a --- tests/Android.mk | 3 +- tests/res/raw/cache_data_updated_task_data.txt | 28 +++ .../raw/package_install_state_change_task_data.txt | 24 +++ .../launcher3/model/AddWorkspaceItemsTaskTest.java | 190 +++++++++++++++++++ .../model/BaseModelUpdateTaskTestCase.java | 208 +++++++++++++++++++++ .../launcher3/model/CacheDataUpdatedTaskTest.java | 81 ++++++++ .../model/PackageInstallStateChangedTaskTest.java | 61 ++++++ 7 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 tests/res/raw/cache_data_updated_task_data.txt create mode 100644 tests/res/raw/package_install_state_change_task_data.txt create mode 100644 tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java create mode 100644 tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java create mode 100644 tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java create mode 100644 tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index 61ee220e8..5103ced7c 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -17,11 +17,12 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator +LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SDK_VERSION := current +LOCAL_MIN_SDK_VERSION := 21 LOCAL_PACKAGE_NAME := Launcher3Tests diff --git a/tests/res/raw/cache_data_updated_task_data.txt b/tests/res/raw/cache_data_updated_task_data.txt new file mode 100644 index 000000000..9095476f6 --- /dev/null +++ b/tests/res/raw/cache_data_updated_task_data.txt @@ -0,0 +1,28 @@ +# Model data used by CacheDataUpdatedTaskTest + +classMap s com.android.launcher3.ShortcutInfo + +# Items for the BgDataModel + +# App shortcuts +bgItem s itemType=0 title=app1-class1 intent=component=app1/class1 id=1 +bgItem s itemType=0 title=app1-class2 intent=component=app1/class2 id=2 +bgItem s itemType=0 title=app2-class1 intent=component=app2/class1 id=3 +bgItem s itemType=0 title=app2-class2 intent=component=app2/class2 id=4 + +# Auto install app shortcut +bgItem s itemType=0 status=2 title=app3-class1 intent=component=app3/class1 id=5 +bgItem s itemType=0 status=2 title=app3-class2 intent=component=app3/class2 id=6 + +# Custom shortcuts +bgItem s itemType=1 title=app1-shrt intent=component=app1/class3 id=7 +bgItem s itemType=1 title=app4-shrt intent=component=app4/class1 id=8 + +# Restored custom shortcut +bgItem s itemType=1 status=1 title=app3-shrt intent=component=app3/class3 id=9 +bgItem s itemType=1 status=1 title=app5-shrt intent=component=app5/class1 id=10 + +allApps componentName=app1/class1 +allApps componentName=app1/class2 +allApps componentName=app2/class1 +allApps componentName=app2/class2 \ No newline at end of file diff --git a/tests/res/raw/package_install_state_change_task_data.txt b/tests/res/raw/package_install_state_change_task_data.txt new file mode 100644 index 000000000..84f9c161e --- /dev/null +++ b/tests/res/raw/package_install_state_change_task_data.txt @@ -0,0 +1,24 @@ +# Model data used by PackageInstallStateChangeTaskTest + +classMap s com.android.launcher3.ShortcutInfo +classMap w com.android.launcher3.LauncherAppWidgetInfo + +# Items for the BgDataModel + +# App shortcuts +bgItem s itemType=0 title=app1-class1 intent=component=app1/class1 id=1 +bgItem s itemType=0 title=app1-class2 intent=component=app1/class2 id=2 +bgItem s itemType=0 title=app2-class1 intent=component=app2/class1 id=3 +bgItem s itemType=0 title=app2-class2 intent=component=app2/class2 id=4 + +# Promise icons for app3 +bgItem s itemType=0 status=2 title=app3-class1 intent=component=app3/class1 id=5 +bgItem s itemType=0 status=2 title=app3-class2 intent=component=app3/class2 id=6 +bgItem s itemType=1 status=1 title=app3-shrt intent=component=app3/class3 id=7 + +# Promise icon for app4 +bgItem s itemType=1 status=1 title=app4-shrt intent=component=app4/class1 id=8 + +# Widget +bgItem w providerName=app4/provider1 id=9 +bgItem w providerName=app5/provider1 id=10 \ No newline at end of file diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java new file mode 100644 index 000000000..ecb3782fc --- /dev/null +++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java @@ -0,0 +1,190 @@ +package com.android.launcher3.model; + +import android.content.ComponentName; +import android.content.ContentProviderOperation; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.net.Uri; +import android.util.Pair; + +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.config.ProviderConfig; +import com.android.launcher3.util.GridOccupancy; +import com.android.launcher3.util.LongArrayMap; + +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link AddWorkspaceItemsTask} + */ +public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase { + + private final ComponentName mComponent1 = new ComponentName("a", "b"); + private final ComponentName mComponent2 = new ComponentName("b", "b"); + + private ArrayList existingScreens; + private ArrayList newScreens; + private LongArrayMap screenOccupancy; + + @Override + protected void setUp() throws Exception { + super.setUp(); + existingScreens = new ArrayList<>(); + screenOccupancy = new LongArrayMap<>(); + newScreens = new ArrayList<>(); + + idp.numColumns = 5; + idp.numRows = 5; + } + + private AddWorkspaceItemsTask newTask(T... items) { + return new AddWorkspaceItemsTask(new ArrayList<>(Arrays.asList(items))) { + + @Override + protected void addItemToDatabase(Context context, ItemInfo item, + long screenId, int[] pos) { + item.screenId = screenId; + item.cellX = pos[0]; + item.cellY = pos[1]; + } + + @Override + protected void updateScreens(Context context, ArrayList workspaceScreens) { } + }; + } + + public void testFindSpaceForItem_prefers_second() { + // First screen has only one hole of size 1 + int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3)); + + // Second screen has 2 holes of sizes 3x2 and 2x3 + setupWorkspaceWithHoles(nextId, 2, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5)); + + Pair spaceFound = newTask() + .findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 1, 1); + assertEquals(2L, (long) spaceFound.first); + assertTrue(screenOccupancy.get(spaceFound.first) + .isRegionVacant(spaceFound.second[0], spaceFound.second[1], 1, 1)); + + // Find a larger space + spaceFound = newTask() + .findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 2, 3); + assertEquals(2L, (long) spaceFound.first); + assertTrue(screenOccupancy.get(spaceFound.first) + .isRegionVacant(spaceFound.second[0], spaceFound.second[1], 2, 3)); + } + + public void testFindSpaceForItem_adds_new_screen() throws Exception { + // First screen has 2 holes of sizes 3x2 and 2x3 + setupWorkspaceWithHoles(1, 1, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5)); + commitScreensToDb(); + + when(appState.getContext()).thenReturn(getMockContext()); + + ArrayList oldScreens = new ArrayList<>(existingScreens); + Pair spaceFound = newTask() + .findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 3, 3); + assertFalse(oldScreens.contains(spaceFound.first)); + assertTrue(newScreens.contains(spaceFound.first)); + } + + public void testAddItem_existing_item_ignored() throws Exception { + ShortcutInfo info = new ShortcutInfo(); + info.intent = new Intent().setComponent(mComponent1); + + // Setup a screen with a hole + setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3)); + commitScreensToDb(); + + when(appState.getContext()).thenReturn(getMockContext()); + + // Nothing was added + assertTrue(executeTaskForTest(newTask(info)).isEmpty()); + } + + public void testAddItem_some_items_added() throws Exception { + ShortcutInfo info = new ShortcutInfo(); + info.intent = new Intent().setComponent(mComponent1); + + ShortcutInfo info2 = new ShortcutInfo(); + info2.intent = new Intent().setComponent(mComponent2); + + // Setup a screen with a hole + setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3)); + commitScreensToDb(); + + when(appState.getContext()).thenReturn(getMockContext()); + + executeTaskForTest(newTask(info, info2)).get(0).run(); + ArgumentCaptor notAnimated = ArgumentCaptor.forClass(ArrayList.class); + ArgumentCaptor animated = ArgumentCaptor.forClass(ArrayList.class); + + // only info2 should be added because info was already added to the workspace + // in setupWorkspaceWithHoles() + verify(callbacks).bindAppsAdded(any(ArrayList.class), notAnimated.capture(), + animated.capture(), any(ArrayList.class)); + assertTrue(notAnimated.getValue().isEmpty()); + + assertEquals(1, animated.getValue().size()); + assertTrue(animated.getValue().contains(info2)); + } + + private int setupWorkspaceWithHoles(int startId, long screenId, Rect... holes) { + GridOccupancy occupancy = new GridOccupancy(idp.numColumns, idp.numRows); + occupancy.markCells(0, 0, idp.numColumns, idp.numRows, true); + for (Rect r : holes) { + occupancy.markCells(r, false); + } + + existingScreens.add(screenId); + screenOccupancy.append(screenId, occupancy); + + for (int x = 0; x < idp.numColumns; x++) { + for (int y = 0; y < idp.numRows; y++) { + if (!occupancy.cells[x][y]) { + continue; + } + + ShortcutInfo info = new ShortcutInfo(); + info.intent = new Intent().setComponent(mComponent1); + info.id = startId++; + info.screenId = screenId; + info.cellX = x; + info.cellY = y; + info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP; + bgDataModel.addItem(info, false); + } + } + return startId; + } + + private void commitScreensToDb() throws Exception { + LauncherSettings.Settings.call(getMockContentResolver(), + LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); + + Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; + ArrayList ops = new ArrayList<>(); + // Clear the table + ops.add(ContentProviderOperation.newDelete(uri).build()); + int count = existingScreens.size(); + for (int i = 0; i < count; i++) { + ContentValues v = new ContentValues(); + long screenId = existingScreens.get(i); + v.put(LauncherSettings.WorkspaceScreens._ID, screenId); + v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); + ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build()); + } + getMockContentResolver().applyBatch(ProviderConfig.AUTHORITY, ops); + } +} diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java new file mode 100644 index 000000000..5628e8291 --- /dev/null +++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java @@ -0,0 +1,208 @@ +package com.android.launcher3.model; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.support.test.InstrumentationRegistry; +import android.test.ProviderTestCase2; + +import com.android.launcher3.AllAppsList; +import com.android.launcher3.AppInfo; +import com.android.launcher3.DeferredHandler; +import com.android.launcher3.IconCache; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherModel.Callbacks; +import com.android.launcher3.LauncherModel.BaseModelUpdateTask; +import com.android.launcher3.compat.LauncherActivityInfoCompat; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.config.ProviderConfig; +import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.TestLauncherProvider; + +import org.mockito.ArgumentCaptor; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; + +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Base class for writing tests for Model update tasks. + */ +public class BaseModelUpdateTaskTestCase extends ProviderTestCase2 { + + public final HashMap> fieldCache = new HashMap<>(); + + public Context targetContext; + public UserHandleCompat myUser; + + public InvariantDeviceProfile idp; + public LauncherAppState appState; + public MyIconCache iconCache; + + public BgDataModel bgDataModel; + public AllAppsList allAppsList; + public Callbacks callbacks; + + public BaseModelUpdateTaskTestCase() { + super(TestLauncherProvider.class, ProviderConfig.AUTHORITY); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + callbacks = mock(Callbacks.class); + appState = mock(LauncherAppState.class); + myUser = UserHandleCompat.myUserHandle(); + + bgDataModel = new BgDataModel(); + targetContext = InstrumentationRegistry.getTargetContext(); + idp = new InvariantDeviceProfile(); + iconCache = new MyIconCache(targetContext, idp); + + allAppsList = new AllAppsList(iconCache, null); + + when(appState.getIconCache()).thenReturn(iconCache); + when(appState.getInvariantDeviceProfile()).thenReturn(idp); + } + + /** + * Synchronously executes the task and returns all the UI callbacks posted. + */ + public List executeTaskForTest(BaseModelUpdateTask task) throws Exception { + LauncherModel mockModel = mock(LauncherModel.class); + when(mockModel.getCallback()).thenReturn(callbacks); + + Field f = BaseModelUpdateTask.class.getDeclaredField("mModel"); + f.setAccessible(true); + f.set(task, mockModel); + + DeferredHandler mockHandler = mock(DeferredHandler.class); + f = BaseModelUpdateTask.class.getDeclaredField("mUiHandler"); + f.setAccessible(true); + f.set(task, mockHandler); + + task.execute(appState, bgDataModel, allAppsList); + ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); + verify(mockHandler, atLeast(0)).post(captor.capture()); + + return captor.getAllValues(); + } + + /** + * Initializes mock data for the test. + */ + public void initializeData(String resourceName) throws Exception { + Context myContext = InstrumentationRegistry.getContext(); + Resources res = myContext.getResources(); + int id = res.getIdentifier(resourceName, "raw", myContext.getPackageName()); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(res.openRawResource(id)))) { + String line; + HashMap classMap = new HashMap<>(); + while((line = reader.readLine()) != null) { + line = line.trim(); + if (line.startsWith("#") || line.isEmpty()) { + continue; + } + String[] commands = line.split(" "); + switch (commands[0]) { + case "classMap": + classMap.put(commands[1], Class.forName(commands[2])); + break; + case "bgItem": + bgDataModel.addItem( + (ItemInfo) initItem(classMap.get(commands[1]), commands, 2), false); + break; + case "allApps": + allAppsList.add((AppInfo) initItem(AppInfo.class, commands, 1)); + break; + } + } + } + } + + private Object initItem(Class clazz, String[] fieldDef, int startIndex) throws Exception { + HashMap cache = fieldCache.get(clazz); + if (cache == null) { + cache = new HashMap<>(); + Class c = clazz; + while (c != null) { + for (Field f : c.getDeclaredFields()) { + f.setAccessible(true); + cache.put(f.getName(), f); + } + c = c.getSuperclass(); + } + fieldCache.put(clazz, cache); + } + + Object item = clazz.newInstance(); + for (int i = startIndex; i < fieldDef.length; i++) { + String[] fieldData = fieldDef[i].split("=", 2); + Field f = cache.get(fieldData[0]); + Class type = f.getType(); + if (type == int.class || type == long.class) { + f.set(item, Integer.parseInt(fieldData[1])); + } else if (type == CharSequence.class || type == String.class) { + f.set(item, fieldData[1]); + } else if (type == Intent.class) { + if (!fieldData[1].startsWith("#Intent")) { + fieldData[1] = "#Intent;" + fieldData[1] + ";end"; + } + f.set(item, Intent.parseUri(fieldData[1], 0)); + } else if (type == ComponentName.class) { + f.set(item, ComponentName.unflattenFromString(fieldData[1])); + } else { + throw new Exception("Added parsing logic for " + + f.getName() + " of type " + f.getType()); + } + } + return item; + } + + public static class MyIconCache extends IconCache { + + private final HashMap mCache = new HashMap<>(); + + public MyIconCache(Context context, InvariantDeviceProfile idp) { + super(context, idp); + } + + @Override + protected CacheEntry cacheLocked(ComponentName componentName, + LauncherActivityInfoCompat info, UserHandleCompat user, + boolean usePackageIcon, boolean useLowResIcon) { + CacheEntry entry = mCache.get(new ComponentKey(componentName, user)); + if (entry == null) { + entry = new CacheEntry(); + entry.icon = getDefaultIcon(user); + } + return entry; + } + + public void addCache(ComponentName key, String title) { + CacheEntry entry = new CacheEntry(); + entry.icon = newIcon(); + entry.title = title; + mCache.put(new ComponentKey(key, UserHandleCompat.myUserHandle()), entry); + } + + public Bitmap newIcon() { + return Bitmap.createBitmap(1, 1, Config.ARGB_8888); + } + } +} diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java new file mode 100644 index 000000000..25b8df933 --- /dev/null +++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java @@ -0,0 +1,81 @@ +package com.android.launcher3.model; + +import com.android.launcher3.AppInfo; +import com.android.launcher3.IconCache; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.ShortcutInfo; + +import java.util.Arrays; +import java.util.HashSet; + +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link CacheDataUpdatedTask} + */ +public class CacheDataUpdatedTaskTest extends BaseModelUpdateTaskTestCase { + + private static final String NEW_LABEL_PREFIX = "new-label-"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + initializeData("cache_data_updated_task_data"); + // Add dummy entries in the cache to simulate update + for (ItemInfo info : bgDataModel.itemsIdMap) { + iconCache.addCache(info.getTargetComponent(), NEW_LABEL_PREFIX + info.id); + } + } + + private CacheDataUpdatedTask newTask(int op, String... pkg) { + return new CacheDataUpdatedTask(op, myUser, new HashSet<>(Arrays.asList(pkg))); + } + + public void testCacheUpdate_update_apps() throws Exception { + executeTaskForTest(newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, "app1")); + + // Verify that only the app icons of app1 (id 1 & 2) are updated. Custom shortcut (id 7) + // is not updated + verifyUpdate(1L, 2L); + + // Verify that only app1 var updated in allAppsList + assertFalse(allAppsList.data.isEmpty()); + for (AppInfo info : allAppsList.data) { + if (info.componentName.getPackageName().equals("app1")) { + assertNotNull(info.iconBitmap); + } else { + assertNull(info.iconBitmap); + } + } + } + + public void testSessionUpdate_ignores_normal_apps() throws Exception { + executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app1")); + + // app1 has no restored shortcuts. Verify that nothing was updated. + verifyUpdate(); + } + + public void testSessionUpdate_updates_pending_apps() throws Exception { + executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app3")); + + // app3 has only restored apps (id 5, 6) and shortcuts (id 9). Verify that only apps were + // were updated + verifyUpdate(5L, 6L); + } + + private void verifyUpdate(Long... idsUpdated) { + HashSet updates = new HashSet<>(Arrays.asList(idsUpdated)); + IconCache noOpIconCache = mock(IconCache.class); + for (ItemInfo info : bgDataModel.itemsIdMap) { + if (updates.contains(info.id)) { + assertEquals(NEW_LABEL_PREFIX + info.id, info.title); + assertNotNull(((ShortcutInfo) info).getIcon(noOpIconCache)); + } else { + assertNotSame(NEW_LABEL_PREFIX + info.id, info.title); + assertNull(((ShortcutInfo) info).getIcon(noOpIconCache)); + } + } + } +} diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java new file mode 100644 index 000000000..d6555620c --- /dev/null +++ b/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java @@ -0,0 +1,61 @@ +package com.android.launcher3.model; + +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppWidgetInfo; +import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; + +import java.util.Arrays; +import java.util.HashSet; + +/** + * Tests for {@link PackageInstallStateChangedTask} + */ +public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + initializeData("package_install_state_change_task_data"); + } + + private PackageInstallStateChangedTask newTask(String pkg, int progress) { + PackageInstallInfo installInfo = new PackageInstallInfo(pkg); + installInfo.progress = progress; + installInfo.state = PackageInstallerCompat.STATUS_INSTALLING; + return new PackageInstallStateChangedTask(installInfo); + } + + public void testSessionUpdate_ignore_installed() throws Exception { + executeTaskForTest(newTask("app1", 30)); + + // No shortcuts were updated + verifyProgressUpdate(0); + } + + public void testSessionUpdate_shortcuts_updated() throws Exception { + executeTaskForTest(newTask("app3", 30)); + + verifyProgressUpdate(30, 5L, 6L, 7L); + } + + public void testSessionUpdate_widgets_updated() throws Exception { + executeTaskForTest(newTask("app4", 30)); + + verifyProgressUpdate(30, 8L, 9L); + } + + private void verifyProgressUpdate(int progress, Long... idsUpdated) { + HashSet updates = new HashSet<>(Arrays.asList(idsUpdated)); + for (ItemInfo info : bgDataModel.itemsIdMap) { + if (info instanceof ShortcutInfo) { + assertEquals(updates.contains(info.id) ? progress: 0, + ((ShortcutInfo) info).getInstallProgress()); + } else { + assertEquals(updates.contains(info.id) ? progress: -1, + ((LauncherAppWidgetInfo) info).installProgress); + } + } + } +} -- cgit v1.2.3