1 package com.android.launcher3.model; 2 3 import android.content.ComponentName; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.database.MatrixCursor; 7 import android.graphics.Bitmap; 8 import android.os.Process; 9 import android.support.test.InstrumentationRegistry; 10 import android.support.test.filters.SmallTest; 11 import android.support.test.runner.AndroidJUnit4; 12 13 import com.android.launcher3.IconCache; 14 import com.android.launcher3.InvariantDeviceProfile; 15 import com.android.launcher3.ItemInfo; 16 import com.android.launcher3.LauncherAppState; 17 import com.android.launcher3.ShortcutInfo; 18 import com.android.launcher3.Utilities; 19 import com.android.launcher3.compat.LauncherAppsCompat; 20 21 import org.junit.Before; 22 import org.junit.Test; 23 import org.junit.runner.RunWith; 24 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 28 import static com.android.launcher3.LauncherSettings.BaseLauncherColumns.INTENT; 29 import static com.android.launcher3.LauncherSettings.Favorites.CELLX; 30 import static com.android.launcher3.LauncherSettings.Favorites.CELLY; 31 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER; 32 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; 33 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; 34 import static com.android.launcher3.LauncherSettings.Favorites.ICON; 35 import static com.android.launcher3.LauncherSettings.Favorites.ICON_PACKAGE; 36 import static com.android.launcher3.LauncherSettings.Favorites.ICON_RESOURCE; 37 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE; 38 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; 39 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; 40 import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID; 41 import static com.android.launcher3.LauncherSettings.Favorites.RESTORED; 42 import static com.android.launcher3.LauncherSettings.Favorites.SCREEN; 43 import static com.android.launcher3.LauncherSettings.Favorites.TITLE; 44 import static com.android.launcher3.LauncherSettings.Favorites._ID; 45 import static junit.framework.Assert.assertEquals; 46 import static junit.framework.Assert.assertFalse; 47 import static junit.framework.Assert.assertNotNull; 48 import static junit.framework.Assert.assertNull; 49 import static junit.framework.Assert.assertTrue; 50 import static org.mockito.Mockito.eq; 51 import static org.mockito.Mockito.mock; 52 import static org.mockito.Mockito.when; 53 54 /** 55 * Tests for {@link LoaderCursor} 56 */ 57 @SmallTest 58 @RunWith(AndroidJUnit4.class) 59 public class LoaderCursorTest { 60 61 private LauncherAppState mMockApp; 62 private IconCache mMockIconCache; 63 64 private MatrixCursor mCursor; 65 private InvariantDeviceProfile mIDP; 66 private Context mContext; 67 private LauncherAppsCompat mLauncherApps; 68 69 private LoaderCursor mLoaderCursor; 70 71 @Before 72 public void setup() { 73 mIDP = new InvariantDeviceProfile(); 74 mCursor = new MatrixCursor(new String[] { 75 ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE, 76 _ID, CONTAINER, ITEM_TYPE, PROFILE_ID, 77 SCREEN, CELLX, CELLY, RESTORED, INTENT 78 }); 79 mContext = InstrumentationRegistry.getTargetContext(); 80 81 mMockApp = mock(LauncherAppState.class); 82 mMockIconCache = mock(IconCache.class); 83 when(mMockApp.getIconCache()).thenReturn(mMockIconCache); 84 when(mMockApp.getInvariantDeviceProfile()).thenReturn(mIDP); 85 when(mMockApp.getContext()).thenReturn(mContext); 86 mLauncherApps = LauncherAppsCompat.getInstance(mContext); 87 88 mLoaderCursor = new LoaderCursor(mCursor, mMockApp); 89 mLoaderCursor.allUsers.put(0, Process.myUserHandle()); 90 } 91 92 private void initCursor(int itemType, String title) { 93 mCursor.newRow() 94 .add(_ID, 1) 95 .add(PROFILE_ID, 0) 96 .add(ITEM_TYPE, itemType) 97 .add(TITLE, title) 98 .add(CONTAINER, CONTAINER_DESKTOP); 99 } 100 101 @Test 102 public void getAppShortcutInfo_dontAllowMissing_invalidComponent() { 103 initCursor(ITEM_TYPE_APPLICATION, ""); 104 assertTrue(mLoaderCursor.moveToNext()); 105 ComponentName cn = new ComponentName(mContext.getPackageName(), "dummy-do"); 106 assertNull(mLoaderCursor.getAppShortcutInfo( 107 new Intent().setComponent(cn), false /* allowMissingTarget */, true)); 108 } 109 110 @Test 111 public void getAppShortcutInfo_dontAllowMissing_validComponent() { 112 initCursor(ITEM_TYPE_APPLICATION, ""); 113 assertTrue(mLoaderCursor.moveToNext()); 114 115 ComponentName cn = mLauncherApps.getActivityList(null, mLoaderCursor.user) 116 .get(0).getComponentName(); 117 ShortcutInfo info = mLoaderCursor.getAppShortcutInfo( 118 new Intent().setComponent(cn), false /* allowMissingTarget */, true); 119 assertNotNull(info); 120 assertTrue(Utilities.isLauncherAppTarget(info.intent)); 121 } 122 123 @Test 124 public void getAppShortcutInfo_allowMissing_invalidComponent() { 125 initCursor(ITEM_TYPE_APPLICATION, ""); 126 assertTrue(mLoaderCursor.moveToNext()); 127 128 ComponentName cn = new ComponentName(mContext.getPackageName(), "dummy-do"); 129 ShortcutInfo info = mLoaderCursor.getAppShortcutInfo( 130 new Intent().setComponent(cn), true /* allowMissingTarget */, true); 131 assertNotNull(info); 132 assertTrue(Utilities.isLauncherAppTarget(info.intent)); 133 } 134 135 @Test 136 public void loadSimpleShortcut() { 137 initCursor(ITEM_TYPE_SHORTCUT, "my-shortcut"); 138 assertTrue(mLoaderCursor.moveToNext()); 139 140 Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); 141 when(mMockIconCache.getDefaultIcon(eq(mLoaderCursor.user))).thenReturn(icon); 142 ShortcutInfo info = mLoaderCursor.loadSimpleShortcut(); 143 assertEquals(icon, info.iconBitmap); 144 assertEquals("my-shortcut", info.title); 145 assertEquals(ITEM_TYPE_SHORTCUT, info.itemType); 146 } 147 148 @Test 149 public void checkItemPlacement_wrongWorkspaceScreen() { 150 ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 3L)); 151 mIDP.numRows = 4; 152 mIDP.numColumns = 4; 153 mIDP.numHotseatIcons = 3; 154 155 // Item on unknown screen are not placed 156 assertFalse(mLoaderCursor.checkItemPlacement( 157 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 4L), workspaceScreens)); 158 assertFalse(mLoaderCursor.checkItemPlacement( 159 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 5L), workspaceScreens)); 160 assertFalse(mLoaderCursor.checkItemPlacement( 161 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens)); 162 163 assertTrue(mLoaderCursor.checkItemPlacement( 164 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); 165 assertTrue(mLoaderCursor.checkItemPlacement( 166 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 3L), workspaceScreens)); 167 168 } 169 @Test 170 public void checkItemPlacement_outsideBounds() { 171 ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L)); 172 mIDP.numRows = 4; 173 mIDP.numColumns = 4; 174 mIDP.numHotseatIcons = 3; 175 176 // Item outside screen bounds are not placed 177 assertFalse(mLoaderCursor.checkItemPlacement( 178 newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); 179 } 180 181 @Test 182 public void checkItemPlacement_overlappingItems() { 183 ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L)); 184 mIDP.numRows = 4; 185 mIDP.numColumns = 4; 186 mIDP.numHotseatIcons = 3; 187 188 // Overlapping items are not placed 189 assertTrue(mLoaderCursor.checkItemPlacement( 190 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); 191 assertFalse(mLoaderCursor.checkItemPlacement( 192 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); 193 194 assertTrue(mLoaderCursor.checkItemPlacement( 195 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens)); 196 assertFalse(mLoaderCursor.checkItemPlacement( 197 newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens)); 198 199 assertTrue(mLoaderCursor.checkItemPlacement( 200 newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens)); 201 assertTrue(mLoaderCursor.checkItemPlacement( 202 newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1L), workspaceScreens)); 203 204 assertFalse(mLoaderCursor.checkItemPlacement( 205 newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1L), workspaceScreens)); 206 } 207 208 @Test 209 public void checkItemPlacement_hotseat() { 210 ArrayList<Long> workspaceScreens = new ArrayList<>(); 211 mIDP.numRows = 4; 212 mIDP.numColumns = 4; 213 mIDP.numHotseatIcons = 3; 214 215 // Hotseat items are only placed based on screenId 216 assertTrue(mLoaderCursor.checkItemPlacement( 217 newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1L), workspaceScreens)); 218 assertTrue(mLoaderCursor.checkItemPlacement( 219 newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2L), workspaceScreens)); 220 221 assertFalse(mLoaderCursor.checkItemPlacement( 222 newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3L), workspaceScreens)); 223 } 224 225 private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY, 226 long container, long screenId) { 227 ItemInfo info = new ItemInfo(); 228 info.cellX = cellX; 229 info.cellY = cellY; 230 info.spanX = spanX; 231 info.spanY = spanY; 232 info.container = container; 233 info.screenId = screenId; 234 return info; 235 } 236 } 237