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