diff options
author | Hyunyoung Song <hyunyoungs@google.com> | 2017-05-10 13:53:50 -0700 |
---|---|---|
committer | Hyunyoung Song <hyunyoungs@google.com> | 2017-05-10 16:52:47 -0700 |
commit | 311ec8962bef83bc240809e8365722a3a57dfec0 (patch) | |
tree | 001a6636ce1d55bd2e31ea69aa4ed2202591795d /tests/src/com/android/launcher3/model | |
parent | 090ce68ceecc09780db4797277a3aaf8c7546a0b (diff) | |
parent | 5cfde85cb6d095585b932d9e3e2c4fe78aa0dafe (diff) | |
download | android_packages_apps_Trebuchet-311ec8962bef83bc240809e8365722a3a57dfec0.tar.gz android_packages_apps_Trebuchet-311ec8962bef83bc240809e8365722a3a57dfec0.tar.bz2 android_packages_apps_Trebuchet-311ec8962bef83bc240809e8365722a3a57dfec0.zip |
merged ub-launcher3-dorval, and resolved conflicts
Bug: 36904684
Bug: 37929893
Bug: 36068989
Test: make -j 32 dist checkbuild
Change-Id: If9b11b212852cb1048d54db2224dab4acf2d93e0
Diffstat (limited to 'tests/src/com/android/launcher3/model')
5 files changed, 788 insertions, 0 deletions
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..d0ba9074c --- /dev/null +++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java @@ -0,0 +1,183 @@ +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 com.android.launcher3.util.Provider; + +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<Long> existingScreens; + private ArrayList<Long> newScreens; + private LongArrayMap<GridOccupancy> 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(ItemInfo... items) { + return new AddWorkspaceItemsTask(Provider.of(Arrays.asList(items))) { + + @Override + protected void updateScreens(Context context, ArrayList<Long> 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<Long, int[]> 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<Long> oldScreens = new ArrayList<>(existingScreens); + Pair<Long, int[]> 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<ArrayList> notAnimated = ArgumentCaptor.forClass(ArrayList.class); + ArgumentCaptor<ArrayList> 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(targetContext, 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<ContentProviderOperation> 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..b9944db98 --- /dev/null +++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java @@ -0,0 +1,226 @@ +package com.android.launcher3.model; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.LauncherActivityInfo; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.os.Process; +import android.os.UserHandle; +import android.support.annotation.NonNull; +import android.support.test.InstrumentationRegistry; +import android.test.ProviderTestCase2; + +import com.android.launcher3.AllAppsList; +import com.android.launcher3.AppFilter; +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.BaseModelUpdateTask; +import com.android.launcher3.LauncherModel.Callbacks; +import com.android.launcher3.config.ProviderConfig; +import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.Provider; +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.Matchers.anyBoolean; +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<TestLauncherProvider> { + + public final HashMap<Class, HashMap<String, Field>> fieldCache = new HashMap<>(); + + public Context targetContext; + public UserHandle myUser; + + public InvariantDeviceProfile idp; + public LauncherAppState appState; + public LauncherModel model; + public ModelWriter modelWriter; + 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); + model = mock(LauncherModel.class); + modelWriter = mock(ModelWriter.class); + when(appState.getModel()).thenReturn(model); + when(model.getWriter(anyBoolean())).thenReturn(modelWriter); + + myUser = Process.myUserHandle(); + + bgDataModel = new BgDataModel(); + targetContext = InstrumentationRegistry.getTargetContext(); + idp = new InvariantDeviceProfile(); + iconCache = new MyIconCache(targetContext, idp); + + allAppsList = new AllAppsList(iconCache, new AppFilter()); + + when(appState.getIconCache()).thenReturn(iconCache); + when(appState.getInvariantDeviceProfile()).thenReturn(idp); + } + + /** + * Synchronously executes the task and returns all the UI callbacks posted. + */ + public List<Runnable> 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<Runnable> 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<String, Class> 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(targetContext, + (ItemInfo) initItem(classMap.get(commands[1]), commands, 2), false); + break; + case "allApps": + allAppsList.add((AppInfo) initItem(AppInfo.class, commands, 1), null); + break; + } + } + } + } + + private Object initItem(Class clazz, String[] fieldDef, int startIndex) throws Exception { + HashMap<String, Field> 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<ComponentKey, CacheEntry> mCache = new HashMap<>(); + + public MyIconCache(Context context, InvariantDeviceProfile idp) { + super(context, idp); + } + + @Override + protected CacheEntry cacheLocked( + @NonNull ComponentName componentName, + @NonNull Provider<LauncherActivityInfo> infoProvider, + UserHandle 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, Process.myUserHandle()), entry); + } + + public Bitmap newIcon() { + return Bitmap.createBitmap(1, 1, Config.ARGB_8888); + } + + @Override + protected Bitmap makeDefaultIcon(UserHandle user) { + return newIcon(); + } + } +} 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..d595e6cf1 --- /dev/null +++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java @@ -0,0 +1,82 @@ +package com.android.launcher3.model; + +import com.android.launcher3.AppInfo; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.ShortcutInfo; + +import java.util.Arrays; +import java.util.HashSet; + +/** + * 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 { + // Clear all icons from apps list so that its easy to check what was updated + for (AppInfo info : allAppsList.data) { + info.iconBitmap = null; + } + + 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<Long> updates = new HashSet<>(Arrays.asList(idsUpdated)); + for (ItemInfo info : bgDataModel.itemsIdMap) { + if (updates.contains(info.id)) { + assertEquals(NEW_LABEL_PREFIX + info.id, info.title); + assertNotNull(((ShortcutInfo) info).iconBitmap); + } else { + assertNotSame(NEW_LABEL_PREFIX + info.id, info.title); + assertNull(((ShortcutInfo) info).iconBitmap); + } + } + } +} diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java new file mode 100644 index 000000000..173c55621 --- /dev/null +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -0,0 +1,236 @@ +package com.android.launcher3.model; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.database.MatrixCursor; +import android.graphics.Bitmap; +import android.os.Process; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.launcher3.IconCache; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.Utilities; +import com.android.launcher3.compat.LauncherAppsCompat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; + +import static com.android.launcher3.LauncherSettings.BaseLauncherColumns.INTENT; +import static com.android.launcher3.LauncherSettings.Favorites.CELLX; +import static com.android.launcher3.LauncherSettings.Favorites.CELLY; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; +import static com.android.launcher3.LauncherSettings.Favorites.ICON; +import static com.android.launcher3.LauncherSettings.Favorites.ICON_PACKAGE; +import static com.android.launcher3.LauncherSettings.Favorites.ICON_RESOURCE; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; +import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID; +import static com.android.launcher3.LauncherSettings.Favorites.RESTORED; +import static com.android.launcher3.LauncherSettings.Favorites.SCREEN; +import static com.android.launcher3.LauncherSettings.Favorites.TITLE; +import static com.android.launcher3.LauncherSettings.Favorites._ID; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests for {@link LoaderCursor} + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class LoaderCursorTest { + + private LauncherAppState mMockApp; + private IconCache mMockIconCache; + + private MatrixCursor mCursor; + private InvariantDeviceProfile mIDP; + private Context mContext; + private LauncherAppsCompat mLauncherApps; + + private LoaderCursor mLoaderCursor; + + @Before + public void setup() { + mIDP = new InvariantDeviceProfile(); + mCursor = new MatrixCursor(new String[] { + ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE, + _ID, CONTAINER, ITEM_TYPE, PROFILE_ID, + SCREEN, CELLX, CELLY, RESTORED, INTENT + }); + mContext = InstrumentationRegistry.getTargetContext(); + + mMockApp = mock(LauncherAppState.class); + mMockIconCache = mock(IconCache.class); + when(mMockApp.getIconCache()).thenReturn(mMockIconCache); + when(mMockApp.getInvariantDeviceProfile()).thenReturn(mIDP); + when(mMockApp.getContext()).thenReturn(mContext); + mLauncherApps = LauncherAppsCompat.getInstance(mContext); + + mLoaderCursor = new LoaderCursor(mCursor, mMockApp); + mLoaderCursor.allUsers.put(0, Process.myUserHandle()); + } + + private void initCursor(int itemType, String title) { + mCursor.newRow() + .add(_ID, 1) + .add(PROFILE_ID, 0) + .add(ITEM_TYPE, itemType) + .add(TITLE, title) + .add(CONTAINER, CONTAINER_DESKTOP); + } + + @Test + public void getAppShortcutInfo_dontAllowMissing_invalidComponent() { + initCursor(ITEM_TYPE_APPLICATION, ""); + assertTrue(mLoaderCursor.moveToNext()); + ComponentName cn = new ComponentName(mContext.getPackageName(), "dummy-do"); + assertNull(mLoaderCursor.getAppShortcutInfo( + new Intent().setComponent(cn), false /* allowMissingTarget */, true)); + } + + @Test + public void getAppShortcutInfo_dontAllowMissing_validComponent() { + initCursor(ITEM_TYPE_APPLICATION, ""); + assertTrue(mLoaderCursor.moveToNext()); + + ComponentName cn = mLauncherApps.getActivityList(null, mLoaderCursor.user) + .get(0).getComponentName(); + ShortcutInfo info = mLoaderCursor.getAppShortcutInfo( + new Intent().setComponent(cn), false /* allowMissingTarget */, true); + assertNotNull(info); + assertTrue(Utilities.isLauncherAppTarget(info.intent)); + } + + @Test + public void getAppShortcutInfo_allowMissing_invalidComponent() { + initCursor(ITEM_TYPE_APPLICATION, ""); + assertTrue(mLoaderCursor.moveToNext()); + + ComponentName cn = new ComponentName(mContext.getPackageName(), "dummy-do"); + ShortcutInfo info = mLoaderCursor.getAppShortcutInfo( + new Intent().setComponent(cn), true /* allowMissingTarget */, true); + assertNotNull(info); + assertTrue(Utilities.isLauncherAppTarget(info.intent)); + } + + @Test + public void loadSimpleShortcut() { + initCursor(ITEM_TYPE_SHORTCUT, "my-shortcut"); + assertTrue(mLoaderCursor.moveToNext()); + + Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); + when(mMockIconCache.getDefaultIcon(eq(mLoaderCursor.user))).thenReturn(icon); + ShortcutInfo info = mLoaderCursor.loadSimpleShortcut(); + assertEquals(icon, info.iconBitmap); + assertEquals("my-shortcut", info.title); + assertEquals(ITEM_TYPE_SHORTCUT, info.itemType); + } + + @Test + public void checkItemPlacement_wrongWorkspaceScreen() { + ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 3L)); + mIDP.numRows = 4; + mIDP.numColumns = 4; + mIDP.numHotseatIcons = 3; + + // Item on unknown screen are not placed + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 4L), workspaceScreens)); + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 5L), workspaceScreens)); + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens)); + + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 3L), workspaceScreens)); + + } + @Test + public void checkItemPlacement_outsideBounds() { + ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L)); + mIDP.numRows = 4; + mIDP.numColumns = 4; + mIDP.numHotseatIcons = 3; + + // Item outside screen bounds are not placed + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); + } + + @Test + public void checkItemPlacement_overlappingItems() { + ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L)); + mIDP.numRows = 4; + mIDP.numColumns = 4; + mIDP.numHotseatIcons = 3; + + // Overlapping items are not placed + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); + + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens)); + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens)); + + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1L), workspaceScreens)); + + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1L), workspaceScreens)); + } + + @Test + public void checkItemPlacement_hotseat() { + ArrayList<Long> workspaceScreens = new ArrayList<>(); + mIDP.numRows = 4; + mIDP.numColumns = 4; + mIDP.numHotseatIcons = 3; + + // Hotseat items are only placed based on screenId + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1L), workspaceScreens)); + assertTrue(mLoaderCursor.checkItemPlacement( + newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2L), workspaceScreens)); + + assertFalse(mLoaderCursor.checkItemPlacement( + newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3L), workspaceScreens)); + } + + private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY, + long container, long screenId) { + ItemInfo info = new ItemInfo(); + info.cellX = cellX; + info.cellY = cellY; + info.spanX = spanX; + info.spanY = spanY; + info.container = container; + info.screenId = screenId; + return info; + } +} 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<Long> 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); + } + } + } +} |