• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3.model;
17 
18 import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
19 
20 import android.util.LongSparseArray;
21 
22 import com.android.launcher3.InvariantDeviceProfile;
23 import com.android.launcher3.LauncherAppState;
24 import com.android.launcher3.LauncherSettings;
25 import com.android.launcher3.config.FeatureFlags;
26 import com.android.launcher3.model.data.ItemInfo;
27 import com.android.launcher3.util.GridOccupancy;
28 import com.android.launcher3.util.IntArray;
29 import com.android.launcher3.util.IntSet;
30 
31 import java.util.ArrayList;
32 
33 /**
34  * Utility class to help find space for new workspace items
35  */
36 public class WorkspaceItemSpaceFinder {
37 
38     /**
39      * Find a position on the screen for the given size or adds a new screen.
40      *
41      * @return screenId and the coordinates for the item in an int array of size 3.
42      */
findSpaceForItem(LauncherAppState app, BgDataModel dataModel, IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY)43     public int[] findSpaceForItem(LauncherAppState app, BgDataModel dataModel,
44             IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) {
45         LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
46 
47         // Use sBgItemsIdMap as all the items are already loaded.
48         synchronized (dataModel) {
49             for (ItemInfo info : dataModel.itemsIdMap) {
50                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
51                     ArrayList<ItemInfo> items = screenItems.get(info.screenId);
52                     if (items == null) {
53                         items = new ArrayList<>();
54                         screenItems.put(info.screenId, items);
55                     }
56                     items.add(info);
57                 }
58             }
59         }
60 
61         // Find appropriate space for the item.
62         int screenId = 0;
63         int[] coordinates = new int[2];
64         boolean found = false;
65 
66         int screenCount = workspaceScreens.size();
67         // First check the preferred screen.
68         IntSet screensToExclude = new IntSet();
69         if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
70             screensToExclude.add(FIRST_SCREEN_ID);
71         }
72 
73         for (int screen = 0; screen < screenCount; screen++) {
74             screenId = workspaceScreens.get(screen);
75             if (!screensToExclude.contains(screenId) && findNextAvailableIconSpaceInScreen(
76                     app, screenItems.get(screenId), coordinates, spanX, spanY)) {
77                 // We found a space for it
78                 found = true;
79                 break;
80             }
81         }
82 
83         if (!found) {
84             // Still no position found. Add a new screen to the end.
85             screenId = app.getModel().getModelDbController().getNewScreenId();
86 
87             // Save the screen id for binding in the workspace
88             workspaceScreens.add(screenId);
89             addedWorkspaceScreensFinal.add(screenId);
90 
91             // If we still can't find an empty space, then God help us all!!!
92             if (!findNextAvailableIconSpaceInScreen(
93                     app, screenItems.get(screenId), coordinates, spanX, spanY)) {
94                 throw new RuntimeException("Can't find space to add the item");
95             }
96         }
97         return new int[]{screenId, coordinates[0], coordinates[1]};
98     }
99 
findNextAvailableIconSpaceInScreen( LauncherAppState app, ArrayList<ItemInfo> occupiedPos, int[] xy, int spanX, int spanY)100     private boolean findNextAvailableIconSpaceInScreen(
101             LauncherAppState app, ArrayList<ItemInfo> occupiedPos,
102             int[] xy, int spanX, int spanY) {
103         InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
104 
105         GridOccupancy occupied = new GridOccupancy(profile.numColumns, profile.numRows);
106         if (occupiedPos != null) {
107             for (ItemInfo r : occupiedPos) {
108                 occupied.markCells(r, true);
109             }
110         }
111         return occupied.findVacantCell(xy, spanX, spanY);
112     }
113 }
114