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