Home | History | Annotate | Download | only in model
      1 package com.android.launcher3.model;
      2 
      3 import android.content.ComponentName;
      4 import android.content.ContentProviderOperation;
      5 import android.content.ContentValues;
      6 import android.content.Context;
      7 import android.content.Intent;
      8 import android.graphics.Rect;
      9 import android.net.Uri;
     10 import android.util.Pair;
     11 
     12 import com.android.launcher3.ItemInfo;
     13 import com.android.launcher3.LauncherProvider;
     14 import com.android.launcher3.LauncherSettings;
     15 import com.android.launcher3.ShortcutInfo;
     16 import com.android.launcher3.util.GridOccupancy;
     17 import com.android.launcher3.util.LongArrayMap;
     18 import com.android.launcher3.util.Provider;
     19 
     20 import org.mockito.ArgumentCaptor;
     21 
     22 import java.util.ArrayList;
     23 import java.util.List;
     24 
     25 import static org.mockito.Matchers.isNull;
     26 import static org.mockito.Mockito.any;
     27 import static org.mockito.Mockito.verify;
     28 import static org.mockito.Mockito.when;
     29 
     30 /**
     31  * Tests for {@link AddWorkspaceItemsTask}
     32  */
     33 public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
     34 
     35     private final ComponentName mComponent1 = new ComponentName("a", "b");
     36     private final ComponentName mComponent2 = new ComponentName("b", "b");
     37 
     38     private ArrayList<Long> existingScreens;
     39     private ArrayList<Long> newScreens;
     40     private LongArrayMap<GridOccupancy> screenOccupancy;
     41 
     42     @Override
     43     protected void setUp() throws Exception {
     44         super.setUp();
     45         existingScreens = new ArrayList<>();
     46         screenOccupancy = new LongArrayMap<>();
     47         newScreens = new ArrayList<>();
     48 
     49         idp.numColumns = 5;
     50         idp.numRows = 5;
     51     }
     52 
     53     private AddWorkspaceItemsTask newTask(ItemInfo... items) {
     54         List<Pair<ItemInfo, Object>> list = new ArrayList<>();
     55         for (ItemInfo item : items) {
     56             list.add(Pair.create(item, null));
     57         }
     58         return new AddWorkspaceItemsTask(Provider.of(list)) {
     59 
     60             @Override
     61             protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) { }
     62         };
     63     }
     64 
     65     public void testFindSpaceForItem_prefers_second() {
     66         // First screen has only one hole of size 1
     67         int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
     68 
     69         // Second screen has 2 holes of sizes 3x2 and 2x3
     70         setupWorkspaceWithHoles(nextId, 2, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
     71 
     72         Pair<Long, int[]> spaceFound = newTask()
     73                 .findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 1, 1);
     74         assertEquals(2L, (long) spaceFound.first);
     75         assertTrue(screenOccupancy.get(spaceFound.first)
     76                 .isRegionVacant(spaceFound.second[0], spaceFound.second[1], 1, 1));
     77 
     78         // Find a larger space
     79         spaceFound = newTask()
     80                 .findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 2, 3);
     81         assertEquals(2L, (long) spaceFound.first);
     82         assertTrue(screenOccupancy.get(spaceFound.first)
     83                 .isRegionVacant(spaceFound.second[0], spaceFound.second[1], 2, 3));
     84     }
     85 
     86     public void testFindSpaceForItem_adds_new_screen() throws Exception {
     87         // First screen has 2 holes of sizes 3x2 and 2x3
     88         setupWorkspaceWithHoles(1, 1, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
     89         commitScreensToDb();
     90 
     91         when(appState.getContext()).thenReturn(getMockContext());
     92 
     93         ArrayList<Long> oldScreens = new ArrayList<>(existingScreens);
     94         Pair<Long, int[]> spaceFound = newTask()
     95                 .findSpaceForItem(appState, bgDataModel, existingScreens, newScreens, 3, 3);
     96         assertFalse(oldScreens.contains(spaceFound.first));
     97         assertTrue(newScreens.contains(spaceFound.first));
     98     }
     99 
    100     public void testAddItem_existing_item_ignored() throws Exception {
    101         ShortcutInfo info = new ShortcutInfo();
    102         info.intent = new Intent().setComponent(mComponent1);
    103 
    104         // Setup a screen with a hole
    105         setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
    106         commitScreensToDb();
    107 
    108         when(appState.getContext()).thenReturn(getMockContext());
    109 
    110         // Nothing was added
    111         assertTrue(executeTaskForTest(newTask(info)).isEmpty());
    112     }
    113 
    114     public void testAddItem_some_items_added() throws Exception {
    115         ShortcutInfo info = new ShortcutInfo();
    116         info.intent = new Intent().setComponent(mComponent1);
    117 
    118         ShortcutInfo info2 = new ShortcutInfo();
    119         info2.intent = new Intent().setComponent(mComponent2);
    120 
    121         // Setup a screen with a hole
    122         setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
    123         commitScreensToDb();
    124 
    125         when(appState.getContext()).thenReturn(getMockContext());
    126 
    127         executeTaskForTest(newTask(info, info2)).get(0).run();
    128         ArgumentCaptor<ArrayList> notAnimated = ArgumentCaptor.forClass(ArrayList.class);
    129         ArgumentCaptor<ArrayList> animated = ArgumentCaptor.forClass(ArrayList.class);
    130 
    131         // only info2 should be added because info was already added to the workspace
    132         // in setupWorkspaceWithHoles()
    133         verify(callbacks).bindAppsAdded(any(ArrayList.class), notAnimated.capture(),
    134                 animated.capture());
    135         assertTrue(notAnimated.getValue().isEmpty());
    136 
    137         assertEquals(1, animated.getValue().size());
    138         assertTrue(animated.getValue().contains(info2));
    139     }
    140 
    141     private int setupWorkspaceWithHoles(int startId, long screenId, Rect... holes) {
    142         GridOccupancy occupancy = new GridOccupancy(idp.numColumns, idp.numRows);
    143         occupancy.markCells(0, 0, idp.numColumns, idp.numRows, true);
    144         for (Rect r : holes) {
    145             occupancy.markCells(r, false);
    146         }
    147 
    148         existingScreens.add(screenId);
    149         screenOccupancy.append(screenId, occupancy);
    150 
    151         for (int x = 0; x < idp.numColumns; x++) {
    152             for (int y = 0; y < idp.numRows; y++) {
    153                 if (!occupancy.cells[x][y]) {
    154                     continue;
    155                 }
    156 
    157                 ShortcutInfo info = new ShortcutInfo();
    158                 info.intent = new Intent().setComponent(mComponent1);
    159                 info.id = startId++;
    160                 info.screenId = screenId;
    161                 info.cellX = x;
    162                 info.cellY = y;
    163                 info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
    164                 bgDataModel.addItem(targetContext, info, false);
    165             }
    166         }
    167         return startId;
    168     }
    169 
    170     private void commitScreensToDb() throws Exception {
    171         LauncherSettings.Settings.call(getMockContentResolver(),
    172                 LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
    173 
    174         Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
    175         ArrayList<ContentProviderOperation> ops = new ArrayList<>();
    176         // Clear the table
    177         ops.add(ContentProviderOperation.newDelete(uri).build());
    178         int count = existingScreens.size();
    179         for (int i = 0; i < count; i++) {
    180             ContentValues v = new ContentValues();
    181             long screenId = existingScreens.get(i);
    182             v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
    183             v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
    184             ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
    185         }
    186         getMockContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops);
    187     }
    188 }
    189