• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 
17 package com.android.launcher3.folder;
18 
19 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
20 
21 import android.graphics.Point;
22 import android.util.Log;
23 
24 import com.android.launcher3.DeviceProfile;
25 import com.android.launcher3.model.data.FolderInfo;
26 import com.android.launcher3.model.data.ItemInfo;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 /**
32  * Utility class for managing item positions in a folder based on rank
33  */
34 public class FolderGridOrganizer {
35 
36     private final Point mPoint = new Point();
37     private final int mMaxCountX;
38     private final int mMaxCountY;
39     private final int mMaxItemsPerPage;
40 
41     private int mNumItemsInFolder;
42     private int mCountX;
43     private int mCountY;
44     private boolean mDisplayingUpperLeftQuadrant = false;
45     private static final int PREVIEW_MAX_ROWS = 2;
46     private static final int PREVIEW_MAX_COLUMNS = 2;
47 
48     /**
49      * Note: must call {@link #setFolderInfo(FolderInfo)} manually for verifier to work.
50      */
FolderGridOrganizer(int maxCountX, int maxCountY)51     public FolderGridOrganizer(int maxCountX, int maxCountY) {
52         mMaxCountX = maxCountX;
53         mMaxCountY = maxCountY;
54         mMaxItemsPerPage = mMaxCountX * mMaxCountY;
55     }
56 
57     /**
58      * Creates a FolderGridOrganizer for the given DeviceProfile
59      */
createFolderGridOrganizer(DeviceProfile profile)60     public static FolderGridOrganizer createFolderGridOrganizer(DeviceProfile profile) {
61         return new FolderGridOrganizer(profile.numFolderColumns, profile.numFolderRows);
62     }
63 
64     /**
65      * Updates the organizer with the provided folder info
66      */
setFolderInfo(FolderInfo info)67     public FolderGridOrganizer setFolderInfo(FolderInfo info) {
68         return setContentSize(info.getContents().size());
69     }
70 
71     /**
72      * Updates the organizer to reflect the content size
73      */
setContentSize(int contentSize)74     public FolderGridOrganizer setContentSize(int contentSize) {
75         if (contentSize != mNumItemsInFolder) {
76             calculateGridSize(contentSize);
77 
78             mDisplayingUpperLeftQuadrant = contentSize > MAX_NUM_ITEMS_IN_PREVIEW;
79             mNumItemsInFolder = contentSize;
80         }
81         return this;
82     }
83 
getCountX()84     public int getCountX() {
85         return mCountX;
86     }
87 
getCountY()88     public int getCountY() {
89         return mCountY;
90     }
91 
getMaxItemsPerPage()92     public int getMaxItemsPerPage() {
93         return mMaxItemsPerPage;
94     }
95 
96     /**
97      * Calculates the grid size such that {@param count} items can fit in the grid.
98      * The grid size is calculated such that countY <= countX and countX = ceil(sqrt(count)) while
99      * maintaining the restrictions of {@link #mMaxCountX} &amp; {@link #mMaxCountY}.
100      */
calculateGridSize(int count)101     private void calculateGridSize(int count) {
102         boolean done;
103         int gridCountX = mCountX;
104         int gridCountY = mCountY;
105 
106         if (count >= mMaxItemsPerPage) {
107             gridCountX = mMaxCountX;
108             gridCountY = mMaxCountY;
109             done = true;
110         } else {
111             done = false;
112         }
113 
114         while (!done) {
115             int oldCountX = gridCountX;
116             int oldCountY = gridCountY;
117             if (gridCountX * gridCountY < count) {
118                 // Current grid is too small, expand it
119                 if ((gridCountX <= gridCountY || gridCountY == mMaxCountY)
120                         && gridCountX < mMaxCountX) {
121                     gridCountX++;
122                 } else if (gridCountY < mMaxCountY) {
123                     gridCountY++;
124                 }
125                 if (gridCountY == 0) gridCountY++;
126             } else if ((gridCountY - 1) * gridCountX >= count && gridCountY >= gridCountX) {
127                 gridCountY = Math.max(0, gridCountY - 1);
128             } else if ((gridCountX - 1) * gridCountY >= count) {
129                 gridCountX = Math.max(0, gridCountX - 1);
130             }
131             done = gridCountX == oldCountX && gridCountY == oldCountY;
132         }
133 
134         mCountX = gridCountX;
135         mCountY = gridCountY;
136     }
137 
138     /**
139      * Updates the item's cellX, cellY and rank corresponding to the provided rank.
140      *
141      * @return true if there was any change
142      */
updateRankAndPos(ItemInfo item, int rank)143     public boolean updateRankAndPos(ItemInfo item, int rank) {
144         Point pos = getPosForRank(rank);
145         if (!pos.equals(item.cellX, item.cellY) || rank != item.rank) {
146             item.rank = rank;
147             item.cellX = pos.x;
148             item.cellY = pos.y;
149             return true;
150         }
151         return false;
152     }
153 
154     /**
155      * Returns the position of the item in the grid
156      */
getPosForRank(int rank)157     public Point getPosForRank(int rank) {
158         int pagePos = rank % mMaxItemsPerPage;
159         mPoint.x = pagePos % mCountX;
160         mPoint.y = pagePos / mCountX;
161         return mPoint;
162     }
163 
164     /**
165      * Returns the preview items for the provided pageNo using the full list of contents
166      */
previewItemsForPage(int page, List<T> contents)167     public <T, R extends T> ArrayList<R> previewItemsForPage(int page, List<T> contents) {
168         ArrayList<R> result = new ArrayList<>();
169         int itemsPerPage = mCountX * mCountY;
170         int start = itemsPerPage * page;
171         int end = Math.min(start + itemsPerPage, contents.size());
172 
173         for (int i = start, rank = 0; i < end; i++, rank++) {
174             if (isItemInPreview(page, rank)) {
175                 result.add((R) contents.get(i));
176             }
177 
178             if (result.size() == MAX_NUM_ITEMS_IN_PREVIEW) {
179                 break;
180             }
181         }
182 
183         if (result.isEmpty()) {
184             // Log specifics since we are getting empty result
185             Log.d("b/383526431", "previewItemsForPage: "
186                     + "mCountX = " + mCountX
187                     + ", mCountY = " + mCountY
188                     + ", content size = " + contents.size());
189         }
190         return result;
191     }
192 
193     /**
194      * Returns whether the item with rank is in the default Folder icon preview.
195      */
isItemInPreview(int rank)196     public boolean isItemInPreview(int rank) {
197         return isItemInPreview(0, rank);
198     }
199 
200     /**
201      * @param page The page the item is on.
202      * @param rank The rank of the item.
203      * @return True iff the icon is in the 2x2 upper left quadrant of the Folder.
204      */
isItemInPreview(int page, int rank)205     public boolean isItemInPreview(int page, int rank) {
206         // First page items are laid out such that the first 4 items are always in the upper
207         // left quadrant. For all other pages, we need to check the row and col.
208         if (page > 0 || mDisplayingUpperLeftQuadrant) {
209             int col = rank % mCountX;
210             int row = rank / mCountX;
211             return col < PREVIEW_MAX_COLUMNS && row < PREVIEW_MAX_ROWS;
212         }
213         // If we have less than 4 items do this
214         return rank < MAX_NUM_ITEMS_IN_PREVIEW;
215     }
216 }
217