blob: 9f367ef766573405ffffed74db3be1082b355960 [file] [log] [blame]
Adam Cohen2e6da152015-05-06 11:42:25 -07001/*
Thales Lima1de4d552021-10-13 16:13:25 +01002 * Copyright (C) 2021 The Android Open Source Project
Adam Cohen2e6da152015-05-06 11:42:25 -07003 *
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
17package com.android.launcher3;
18
Sunny Goyal19ff7282021-04-22 10:12:54 -070019import static com.android.launcher3.Utilities.dpiFromPx;
Andras Kloczl8e57cce2021-02-11 23:51:19 +010020import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
Sunny Goyal35c7b192021-04-20 16:51:10 -070021import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
Alex Chau6ed408f2022-03-04 12:58:05 +000022import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
Sunny Goyal19ff7282021-04-22 10:12:54 -070023import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
Sunny Goyal9c2b9602020-01-07 13:07:55 -080024import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
Sunny Goyal87dc48b2018-10-12 11:42:33 -070025
Sunny Goyalc6205602015-05-21 20:46:33 -070026import android.annotation.TargetApi;
Sunny Goyal58fa4b62019-03-22 16:23:25 -070027import android.appwidget.AppWidgetHostView;
Sunny Goyal58fa4b62019-03-22 16:23:25 -070028import android.content.ComponentName;
Adam Cohen2e6da152015-05-06 11:42:25 -070029import android.content.Context;
Sunny Goyal27835952017-01-13 12:15:53 -080030import android.content.res.Configuration;
Hyunyoung Songc55a3502018-12-04 15:43:16 -080031import android.content.res.Resources;
Sunny Goyal819e1932016-07-07 16:43:58 -070032import android.content.res.TypedArray;
33import android.content.res.XmlResourceParser;
Adam Cohen2e6da152015-05-06 11:42:25 -070034import android.graphics.Point;
Thales Lima78d00ad2021-09-30 11:29:06 +010035import android.graphics.PointF;
Sunny Goyal58fa4b62019-03-22 16:23:25 -070036import android.graphics.Rect;
Sunny Goyal415f1732018-11-29 10:33:47 -080037import android.text.TextUtils;
38import android.util.AttributeSet;
Adam Cohen2e6da152015-05-06 11:42:25 -070039import android.util.DisplayMetrics;
Thales Lima7ec83822021-08-05 13:32:10 +010040import android.util.Log;
Sunny Goyal5bc18462019-01-07 15:13:39 -080041import android.util.SparseArray;
42import android.util.TypedValue;
Sunny Goyal819e1932016-07-07 16:43:58 -070043import android.util.Xml;
Sunny Goyal9c2b9602020-01-07 13:07:55 -080044import android.view.Display;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -070045
Alex Chau1c883d82021-12-01 18:43:10 +000046import androidx.annotation.IntDef;
Sunny Goyal6fe3eec2019-08-15 14:53:41 -070047import androidx.annotation.Nullable;
48import androidx.annotation.VisibleForTesting;
49
Sunny Goyal68031ca2021-08-02 12:23:44 -070050import com.android.launcher3.model.DeviceGridState;
Alex Chau238aaee2021-10-06 16:15:24 +010051import com.android.launcher3.provider.RestoreDbTask;
Sunny Goyalfd58da62020-08-11 12:06:49 -070052import com.android.launcher3.util.DisplayController;
53import com.android.launcher3.util.DisplayController.Info;
Sunny Goyal5bc18462019-01-07 15:13:39 -080054import com.android.launcher3.util.IntArray;
Sunny Goyald0e360a2018-06-29 14:40:18 -070055import com.android.launcher3.util.MainThreadInitializedObject;
Sunny Goyal5bc18462019-01-07 15:13:39 -080056import com.android.launcher3.util.Themes;
Sunny Goyal19ff7282021-04-22 10:12:54 -070057import com.android.launcher3.util.WindowBounds;
Sunny Goyal187b16c2022-03-01 16:53:23 -080058import com.android.launcher3.util.window.WindowManagerProxy;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -070059
Sunny Goyal819e1932016-07-07 16:43:58 -070060import org.xmlpull.v1.XmlPullParser;
61import org.xmlpull.v1.XmlPullParserException;
62
63import java.io.IOException;
Alex Chau1c883d82021-12-01 18:43:10 +000064import java.lang.annotation.Retention;
65import java.lang.annotation.RetentionPolicy;
Adam Cohen2e6da152015-05-06 11:42:25 -070066import java.util.ArrayList;
Sunny Goyal6e6f7992021-08-24 16:23:29 -070067import java.util.Arrays;
Sunny Goyal6d55f662019-01-02 12:13:43 -080068import java.util.Collections;
Sunny Goyal19ff7282021-04-22 10:12:54 -070069import java.util.List;
Adam Cohen2e6da152015-05-06 11:42:25 -070070
71public class InvariantDeviceProfile {
Adam Cohen2e6da152015-05-06 11:42:25 -070072
Hyunyoung Songc55a3502018-12-04 15:43:16 -080073 public static final String TAG = "IDP";
Sunny Goyald0e360a2018-06-29 14:40:18 -070074 // We do not need any synchronization for this variable as its only written on UI thread.
75 public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
Sunny Goyal87dc48b2018-10-12 11:42:33 -070076 new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
Adam Cohen2e6da152015-05-06 11:42:25 -070077
Alex Chau1c883d82021-12-01 18:43:10 +000078 @Retention(RetentionPolicy.SOURCE)
79 @IntDef({TYPE_PHONE, TYPE_MULTI_DISPLAY, TYPE_TABLET})
80 public @interface DeviceType{}
81 public static final int TYPE_PHONE = 0;
82 public static final int TYPE_MULTI_DISPLAY = 1;
83 public static final int TYPE_TABLET = 2;
84
Hyunyoung Songc55a3502018-12-04 15:43:16 -080085 private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
Sunny Goyal415f1732018-11-29 10:33:47 -080086
Sunny Goyal53d7ee42015-05-22 12:25:45 -070087 private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
88
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -070089 // Constants that affects the interpolation curve between statically defined device profile
90 // buckets.
Hyunyoung Songc55a3502018-12-04 15:43:16 -080091 private static final float KNEARESTNEIGHBOR = 3;
92 private static final float WEIGHT_POWER = 5;
Adam Cohen2e6da152015-05-06 11:42:25 -070093
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -070094 // used to offset float not being able to express extremely small weights in extreme cases.
Hyunyoung Songc55a3502018-12-04 15:43:16 -080095 private static final float WEIGHT_EFFICIENT = 100000f;
96
Thales Lima83bedbf2021-10-05 17:47:39 +010097 // Used for arrays to specify different sizes (e.g. border spaces, width/height) in different
98 // constraints
Thales Limabb7d3882021-12-22 12:56:29 +000099 static final int COUNT_SIZES = 4;
Thales Lima83bedbf2021-10-05 17:47:39 +0100100 static final int INDEX_DEFAULT = 0;
101 static final int INDEX_LANDSCAPE = 1;
102 static final int INDEX_TWO_PANEL_PORTRAIT = 2;
103 static final int INDEX_TWO_PANEL_LANDSCAPE = 3;
Thales Lima83bedbf2021-10-05 17:47:39 +0100104
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700105 /**
106 * Number of icons per row and column in the workspace.
107 */
Adam Cohen2e6da152015-05-06 11:42:25 -0700108 public int numRows;
109 public int numColumns;
Alex Chau9fee3fd2021-12-01 18:43:10 +0000110 public int numSearchContainerColumns;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700111
112 /**
113 * Number of icons per row and column in the folder.
114 */
Adam Cohen2e6da152015-05-06 11:42:25 -0700115 public int numFolderRows;
116 public int numFolderColumns;
Thales Lima83bedbf2021-10-05 17:47:39 +0100117 public float[] iconSize;
118 public float[] iconTextSize;
Sunny Goyalfc218302015-09-17 14:59:10 -0700119 public int iconBitmapSize;
120 public int fillResIconDpi;
Alex Chau1c883d82021-12-01 18:43:10 +0000121 public @DeviceType int deviceType;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700122
Thales Lima83bedbf2021-10-05 17:47:39 +0100123 public PointF[] minCellSize;
Thales Lima78d00ad2021-09-30 11:29:06 +0100124
Thales Lima83bedbf2021-10-05 17:47:39 +0100125 public PointF[] borderSpaces;
Thales Lima78d00ad2021-09-30 11:29:06 +0100126 public float folderBorderSpace;
Thales Lima6e7f36c2022-01-04 12:14:11 +0000127 public float[] hotseatBorderSpaces;
Thales Lima78d00ad2021-09-30 11:29:06 +0100128
Thales Lima83bedbf2021-10-05 17:47:39 +0100129 public float[] horizontalMargin;
Jon Mirandae126d722021-02-25 10:45:20 -0500130
Thales Limab7ef5692022-03-10 10:32:36 +0000131 public PointF[] allAppsCellSize;
Thales Limabb7d3882021-12-22 12:56:29 +0000132 public float[] allAppsIconSize;
133 public float[] allAppsIconTextSize;
134 public PointF[] allAppsBorderSpaces;
135
Sunny Goyal5bc18462019-01-07 15:13:39 -0800136 private SparseArray<TypedValue> mExtraAttrs;
137
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700138 /**
139 * Number of icons inside the hotseat area.
140 */
Jon Mirandafd48b0c2022-01-31 16:25:22 -0800141 public int numShownHotseatIcons;
Tony Wickhamb87f3cd2021-04-07 15:02:37 -0700142
143 /**
Alex Chau6ed408f2022-03-04 12:58:05 +0000144 * Number of icons inside the hotseat area when using 3 buttons navigation.
145 */
146 public int numShrunkenHotseatIcons;
147
148 /**
Tony Wickhamb87f3cd2021-04-07 15:02:37 -0700149 * Number of icons inside the hotseat area that is stored in the database. This is greater than
150 * or equal to numnShownHotseatIcons, allowing for a seamless transition between two hotseat
151 * sizes that share the same DB.
152 */
153 public int numDatabaseHotseatIcons;
Adam Cohen27824492017-09-22 17:10:55 -0700154
Jon Miranda6f7e9702019-09-16 14:44:14 -0700155 /**
156 * Number of columns in the all apps list.
157 */
158 public int numAllAppsColumns;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700159 public int numDatabaseAllAppsColumns;
Jon Miranda6f7e9702019-09-16 14:44:14 -0700160
Jon Mirandae126d722021-02-25 10:45:20 -0500161 /**
162 * Do not query directly. see {@link DeviceProfile#isScalableGrid}.
163 */
164 protected boolean isScalable;
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400165 public int devicePaddingId;
Jon Mirandae126d722021-02-25 10:45:20 -0500166
Tracy Zhou7df93d22020-01-27 13:44:06 -0800167 public String dbFile;
Sunny Goyal415f1732018-11-29 10:33:47 -0800168 public int defaultLayoutId;
Adam Cohen27824492017-09-22 17:10:55 -0700169 int demoModeLayoutId;
Thales Lima12d0eff2022-03-25 17:06:11 +0000170 boolean[] inlineQsb = new boolean[COUNT_SIZES];
Adam Cohen2e6da152015-05-06 11:42:25 -0700171
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000172 /**
173 * An immutable list of supported profiles.
174 */
175 public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST;
Sunny Goyalc6205602015-05-21 20:46:33 -0700176
sfufa@google.comde013292021-09-21 18:22:44 -0700177 @Nullable
178 public DevicePaddings devicePaddings;
Jon Miranda228877d2021-02-09 11:05:00 -0500179
Sunny Goyal6f866092016-03-17 17:04:15 -0700180 public Point defaultWallpaperSize;
Sunny Goyal58fa4b62019-03-22 16:23:25 -0700181 public Rect defaultWidgetPadding;
Sunny Goyal6f866092016-03-17 17:04:15 -0700182
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700183 private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700184
Sunny Goyalf633ef52018-03-13 09:57:05 -0700185 @VisibleForTesting
Sunny Goyal187b16c2022-03-01 16:53:23 -0800186 public InvariantDeviceProfile() { }
Adam Cohen2e6da152015-05-06 11:42:25 -0700187
Sunny Goyalbbf01842015-10-08 07:41:15 -0700188 @TargetApi(23)
Sunny Goyald0e360a2018-06-29 14:40:18 -0700189 private InvariantDeviceProfile(Context context) {
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700190 String gridName = getCurrentGridName(context);
191 String newGridName = initGrid(context, gridName);
192 if (!newGridName.equals(gridName)) {
193 Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply();
194 }
Sunny Goyal68031ca2021-08-02 12:23:44 -0700195 new DeviceGridState(this).writeToPrefs(context);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700196
Tracy Zhouc8beebf2021-09-23 10:18:11 -0700197 DisplayController.INSTANCE.get(context).setPriorityListener(
Alex Chaufd6d9422021-04-22 19:10:21 +0100198 (displayContext, info, flags) -> {
Alex Chau6ed408f2022-03-04 12:58:05 +0000199 if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS
200 | CHANGE_NAVIGATION_MODE)) != 0) {
Alex Chaufd6d9422021-04-22 19:10:21 +0100201 onConfigChanged(displayContext);
Sunny Goyal35c7b192021-04-20 16:51:10 -0700202 }
203 });
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700204 }
205
Hyunyoung Songe11eb472019-03-19 15:05:21 -0700206 /**
207 * This constructor should NOT have any monitors by design.
208 */
Sunny Goyaleff44f32019-01-09 17:29:49 -0800209 public InvariantDeviceProfile(Context context, String gridName) {
210 String newName = initGrid(context, gridName);
211 if (newName == null || !newName.equals(gridName)) {
212 throw new IllegalArgumentException("Unknown grid name");
213 }
214 }
215
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700216 /**
Sunny Goyal9c2b9602020-01-07 13:07:55 -0800217 * This constructor should NOT have any monitors by design.
218 */
219 public InvariantDeviceProfile(Context context, Display display) {
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700220 // Ensure that the main device profile is initialized
Alex Chaufd6d9422021-04-22 19:10:21 +0100221 INSTANCE.get(context);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700222 String gridName = getCurrentGridName(context);
223
224 // Get the display info based on default display and interpolate it to existing display
Alex Chau1c883d82021-12-01 18:43:10 +0000225 Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
226 @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700227 DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
Alex Chau1c883d82021-12-01 18:43:10 +0000228 defaultInfo,
229 getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
230 /*allowDisabledGrid=*/false),
231 defaultDeviceType);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700232
Alex Chau417bd722021-01-26 15:22:18 +0000233 Info myInfo = new Info(context, display);
Alex Chau1c883d82021-12-01 18:43:10 +0000234 @DeviceType int deviceType = getDeviceType(myInfo);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700235 DisplayOption myDisplayOption = invDistWeightedInterpolate(
Alex Chau1c883d82021-12-01 18:43:10 +0000236 myInfo,
237 getPredefinedDeviceProfiles(context, gridName, deviceType,
238 /*allowDisabledGrid=*/false),
239 deviceType);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700240
241 DisplayOption result = new DisplayOption(defaultDisplayOption.grid)
242 .add(myDisplayOption);
Thales Lima83bedbf2021-10-05 17:47:39 +0100243 result.iconSizes[INDEX_DEFAULT] =
244 defaultDisplayOption.iconSizes[INDEX_DEFAULT];
245 for (int i = 1; i < COUNT_SIZES; i++) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700246 result.iconSizes[i] = Math.min(
247 defaultDisplayOption.iconSizes[i], myDisplayOption.iconSizes[i]);
Alex Chau7c439722021-03-24 11:32:44 +0000248 }
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700249
Thales Lima83bedbf2021-10-05 17:47:39 +0100250 System.arraycopy(defaultDisplayOption.minCellSize, 0, result.minCellSize, 0,
251 COUNT_SIZES);
252 System.arraycopy(defaultDisplayOption.borderSpaces, 0, result.borderSpaces, 0,
253 COUNT_SIZES);
Thales Lima12d0eff2022-03-25 17:06:11 +0000254 System.arraycopy(defaultDisplayOption.inlineQsb, 0, result.inlineQsb, 0,
255 COUNT_SIZES);
Jon Miranda228877d2021-02-09 11:05:00 -0500256
Alex Chau1c883d82021-12-01 18:43:10 +0000257 initGrid(context, myInfo, result, deviceType);
Sunny Goyal9c2b9602020-01-07 13:07:55 -0800258 }
259
Alex Chau238aaee2021-10-06 16:15:24 +0100260 /**
261 * Reinitialize the current grid after a restore, where some grids might now be disabled.
262 */
263 public void reinitializeAfterRestore(Context context) {
Alex Chau29a96ad2022-02-10 13:12:20 +0000264 String currentGridName = getCurrentGridName(context);
Alex Chau238aaee2021-10-06 16:15:24 +0100265 String currentDbFile = dbFile;
Alex Chau29a96ad2022-02-10 13:12:20 +0000266 String newGridName = initGrid(context, currentGridName);
267 String newDbFile = dbFile;
268 if (!newDbFile.equals(currentDbFile)) {
269 Log.d(TAG, "Restored grid is disabled : " + currentGridName
Alex Chau238aaee2021-10-06 16:15:24 +0100270 + ", migrating to: " + newGridName
271 + ", removing all other grid db files");
272 for (String gridDbFile : LauncherFiles.GRID_DB_FILES) {
273 if (gridDbFile.equals(currentDbFile)) {
274 continue;
275 }
276 if (context.getDatabasePath(gridDbFile).delete()) {
277 Log.d(TAG, "Removed old grid db file: " + gridDbFile);
278 }
279 }
Alex Chau29a96ad2022-02-10 13:12:20 +0000280 setCurrentGrid(context, newGridName);
Alex Chau238aaee2021-10-06 16:15:24 +0100281 }
282 }
283
Alex Chau1c883d82021-12-01 18:43:10 +0000284 private static @DeviceType int getDeviceType(Info displayInfo) {
Sunny Goyal187b16c2022-03-01 16:53:23 -0800285 int flagPhone = 1 << 0;
286 int flagTablet = 1 << 1;
287
288 int type = displayInfo.supportedBounds.stream()
289 .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
290 .reduce(0, (a, b) -> a | b);
291 if ((type == (flagPhone | flagTablet)) && ENABLE_TWO_PANEL_HOME.get()) {
292 // device has profiles supporting both phone and table modes
Alex Chau1c883d82021-12-01 18:43:10 +0000293 return TYPE_MULTI_DISPLAY;
Sunny Goyal187b16c2022-03-01 16:53:23 -0800294 } else if (type == flagTablet) {
Alex Chau1c883d82021-12-01 18:43:10 +0000295 return TYPE_TABLET;
296 } else {
297 return TYPE_PHONE;
298 }
299 }
300
Tracy Zhou42255d22020-03-13 00:38:11 -0700301 public static String getCurrentGridName(Context context) {
Tracy Zhouc6060e62020-04-27 13:05:34 -0700302 return Utilities.isGridOptionsEnabled(context)
303 ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null) : null;
Tracy Zhou42255d22020-03-13 00:38:11 -0700304 }
305
Sunny Goyaleff44f32019-01-09 17:29:49 -0800306 private String initGrid(Context context, String gridName) {
Sunny Goyal35c7b192021-04-20 16:51:10 -0700307 Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
Alex Chau1c883d82021-12-01 18:43:10 +0000308 @DeviceType int deviceType = getDeviceType(displayInfo);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700309
310 ArrayList<DisplayOption> allOptions =
Alex Chau1c883d82021-12-01 18:43:10 +0000311 getPredefinedDeviceProfiles(context, gridName, deviceType,
Alex Chau238aaee2021-10-06 16:15:24 +0100312 RestoreDbTask.isPending(context));
Sunny Goyal19ff7282021-04-22 10:12:54 -0700313 DisplayOption displayOption =
Alex Chau1c883d82021-12-01 18:43:10 +0000314 invDistWeightedInterpolate(displayInfo, allOptions, deviceType);
315 initGrid(context, displayInfo, displayOption, deviceType);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700316 return displayOption.grid.name;
Sunny Goyal9c2b9602020-01-07 13:07:55 -0800317 }
Adam Cohen2e6da152015-05-06 11:42:25 -0700318
Alex Chau1c883d82021-12-01 18:43:10 +0000319 private void initGrid(Context context, Info displayInfo, DisplayOption displayOption,
320 @DeviceType int deviceType) {
Sunny Goyal35c7b192021-04-20 16:51:10 -0700321 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700322 GridOption closestProfile = displayOption.grid;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000323 numRows = closestProfile.numRows;
324 numColumns = closestProfile.numColumns;
Alex Chau9fee3fd2021-12-01 18:43:10 +0000325 numSearchContainerColumns = closestProfile.numSearchContainerColumns;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000326 dbFile = closestProfile.dbFile;
327 defaultLayoutId = closestProfile.defaultLayoutId;
328 demoModeLayoutId = closestProfile.demoModeLayoutId;
329 numFolderRows = closestProfile.numFolderRows;
330 numFolderColumns = closestProfile.numFolderColumns;
Jon Mirandae126d722021-02-25 10:45:20 -0500331 isScalable = closestProfile.isScalable;
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400332 devicePaddingId = closestProfile.devicePaddingId;
Alex Chau1c883d82021-12-01 18:43:10 +0000333 this.deviceType = deviceType;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000334
335 mExtraAttrs = closestProfile.extraAttrs;
336
Thales Lima83bedbf2021-10-05 17:47:39 +0100337 iconSize = displayOption.iconSizes;
Thales Lima6e0005a2021-10-27 15:53:41 +0100338 float maxIconSize = iconSize[0];
339 for (int i = 1; i < iconSize.length; i++) {
340 maxIconSize = Math.max(maxIconSize, iconSize[i]);
341 }
342 iconBitmapSize = ResourceUtils.pxFromDp(maxIconSize, metrics);
Sunny Goyalae190ff2020-04-14 00:19:01 +0000343 fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
344
Thales Lima83bedbf2021-10-05 17:47:39 +0100345 iconTextSize = displayOption.textSizes;
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700346
Thales Lima83bedbf2021-10-05 17:47:39 +0100347 minCellSize = displayOption.minCellSize;
Thales Lima78d00ad2021-09-30 11:29:06 +0100348
Thales Lima83bedbf2021-10-05 17:47:39 +0100349 borderSpaces = displayOption.borderSpaces;
Thales Lima78d00ad2021-09-30 11:29:06 +0100350 folderBorderSpace = displayOption.folderBorderSpace;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700351
Thales Limad90faab2021-09-21 17:18:47 +0100352 horizontalMargin = displayOption.horizontalMargin;
Thales Limad90faab2021-09-21 17:18:47 +0100353
Sunny Goyal19ff7282021-04-22 10:12:54 -0700354 numShownHotseatIcons = closestProfile.numHotseatIcons;
Alex Chau6ed408f2022-03-04 12:58:05 +0000355 numShrunkenHotseatIcons = closestProfile.numShrunkenHotseatIcons;
Alex Chau1c883d82021-12-01 18:43:10 +0000356 numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
Sunny Goyal19ff7282021-04-22 10:12:54 -0700357 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
Thales Lima6e7f36c2022-01-04 12:14:11 +0000358 hotseatBorderSpaces = displayOption.hotseatBorderSpaces;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700359
360 numAllAppsColumns = closestProfile.numAllAppsColumns;
Alex Chau1c883d82021-12-01 18:43:10 +0000361 numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
Sunny Goyal19ff7282021-04-22 10:12:54 -0700362 ? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
Jon Mirandae126d722021-02-25 10:45:20 -0500363
Thales Limab7ef5692022-03-10 10:32:36 +0000364 allAppsCellSize = displayOption.allAppsCellSize;
Thales Limabb7d3882021-12-22 12:56:29 +0000365 allAppsBorderSpaces = displayOption.allAppsBorderSpaces;
366 allAppsIconSize = displayOption.allAppsIconSizes;
367 allAppsIconTextSize = displayOption.allAppsIconTextSizes;
Thales Lima83bedbf2021-10-05 17:47:39 +0100368 if (!Utilities.isGridOptionsEnabled(context)) {
Thales Limabb7d3882021-12-22 12:56:29 +0000369 allAppsIconSize = iconSize;
370 allAppsIconTextSize = iconTextSize;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000371 }
372
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400373 if (devicePaddingId != 0) {
374 devicePaddings = new DevicePaddings(context, devicePaddingId);
375 }
376
Thales Lima12d0eff2022-03-25 17:06:11 +0000377 inlineQsb = displayOption.inlineQsb;
378
Sunny Goyalae190ff2020-04-14 00:19:01 +0000379 // If the partner customization apk contains any grid overrides, apply them
380 // Supported overrides: numRows, numColumns, iconSize
Sunny Goyal35c7b192021-04-20 16:51:10 -0700381 applyPartnerDeviceProfileOverrides(context, metrics);
Sunny Goyalc6205602015-05-21 20:46:33 -0700382
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000383 final List<DeviceProfile> localSupportedProfiles = new ArrayList<>();
Sunny Goyal19ff7282021-04-22 10:12:54 -0700384 defaultWallpaperSize = new Point(displayInfo.currentSize);
385 for (WindowBounds bounds : displayInfo.supportedBounds) {
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000386 localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo)
Alex Chau1c883d82021-12-01 18:43:10 +0000387 .setUseTwoPanels(deviceType == TYPE_MULTI_DISPLAY)
Alex Chau6ed408f2022-03-04 12:58:05 +0000388 .setWindowBounds(bounds)
389 .build());
Sunny Goyalc6205602015-05-21 20:46:33 -0700390
Sunny Goyal19ff7282021-04-22 10:12:54 -0700391 // Wallpaper size should be the maximum of the all possible sizes Launcher expects
392 int displayWidth = bounds.bounds.width();
393 int displayHeight = bounds.bounds.height();
394 defaultWallpaperSize.y = Math.max(defaultWallpaperSize.y, displayHeight);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700395
Sunny Goyal19ff7282021-04-22 10:12:54 -0700396 // We need to ensure that there is enough extra space in the wallpaper
397 // for the intended parallax effects
398 float parallaxFactor =
399 dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.densityDpi) < 720
400 ? 2
401 : wallpaperTravelToScreenWidthRatio(displayWidth, displayHeight);
402 defaultWallpaperSize.x =
403 Math.max(defaultWallpaperSize.x, Math.round(parallaxFactor * displayWidth));
Sunny Goyal6f866092016-03-17 17:04:15 -0700404 }
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000405 supportedProfiles = Collections.unmodifiableList(localSupportedProfiles);
Sunny Goyal58fa4b62019-03-22 16:23:25 -0700406
407 ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
408 defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
Adam Cohen2e6da152015-05-06 11:42:25 -0700409 }
410
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700411 public void addOnChangeListener(OnIDPChangeListener listener) {
412 mChangeListeners.add(listener);
413 }
414
Hyunyoung Songb4d1ca42019-01-08 17:15:16 -0800415 public void removeOnChangeListener(OnIDPChangeListener listener) {
416 mChangeListeners.remove(listener);
417 }
418
Hyunyoung Songc55a3502018-12-04 15:43:16 -0800419
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800420 public void setCurrentGrid(Context context, String gridName) {
421 Context appContext = context.getApplicationContext();
422 Utilities.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply();
Sunny Goyal6fe3eec2019-08-15 14:53:41 -0700423 MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext));
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800424 }
425
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700426 private Object[] toModelState() {
sfufa@google.comde013292021-09-21 18:22:44 -0700427 return new Object[]{
Alex Chau9fee3fd2021-12-01 18:43:10 +0000428 numColumns, numRows, numSearchContainerColumns, numDatabaseHotseatIcons,
429 iconBitmapSize, fillResIconDpi, numDatabaseAllAppsColumns, dbFile};
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700430 }
431
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700432 private void onConfigChanged(Context context) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700433 Object[] oldState = toModelState();
434
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700435 // Re-init grid
Tracy Zhouc6060e62020-04-27 13:05:34 -0700436 String gridName = getCurrentGridName(context);
Jon Miranda6f7e9702019-09-16 14:44:14 -0700437 initGrid(context, gridName);
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700438
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700439 boolean modelPropsChanged = !Arrays.equals(oldState, toModelState());
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700440 for (OnIDPChangeListener listener : mChangeListeners) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700441 listener.onIdpChanged(modelPropsChanged);
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700442 }
443 }
444
Alex Chau1c883d82021-12-01 18:43:10 +0000445 private static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context,
446 String gridName, @DeviceType int deviceType, boolean allowDisabledGrid) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800447 ArrayList<DisplayOption> profiles = new ArrayList<>();
Thales Lima1de4d552021-10-13 16:13:25 +0100448
Alex Chau1c883d82021-12-01 18:43:10 +0000449 try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
Sunny Goyal819e1932016-07-07 16:43:58 -0700450 final int depth = parser.getDepth();
451 int type;
Sunny Goyal819e1932016-07-07 16:43:58 -0700452 while (((type = parser.next()) != XmlPullParser.END_TAG ||
453 parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800454 if ((type == XmlPullParser.START_TAG)
455 && GridOption.TAG_NAME.equals(parser.getName())) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800456
Alex Chau1c883d82021-12-01 18:43:10 +0000457 GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser),
458 deviceType);
Alex Chau238aaee2021-10-06 16:15:24 +0100459 if (gridOption.isEnabled || allowDisabledGrid) {
Thales Lima7ec83822021-08-05 13:32:10 +0100460 final int displayDepth = parser.getDepth();
461 while (((type = parser.next()) != XmlPullParser.END_TAG
462 || parser.getDepth() > displayDepth)
463 && type != XmlPullParser.END_DOCUMENT) {
464 if ((type == XmlPullParser.START_TAG) && "display-option".equals(
465 parser.getName())) {
466 profiles.add(new DisplayOption(gridOption, context,
Thales Lima1de4d552021-10-13 16:13:25 +0100467 Xml.asAttributeSet(parser)));
Thales Lima7ec83822021-08-05 13:32:10 +0100468 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800469 }
470 }
Sunny Goyal819e1932016-07-07 16:43:58 -0700471 }
472 }
sfufa@google.comde013292021-09-21 18:22:44 -0700473 } catch (IOException | XmlPullParserException e) {
Sunny Goyal819e1932016-07-07 16:43:58 -0700474 throw new RuntimeException(e);
475 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800476
Sunny Goyalae190ff2020-04-14 00:19:01 +0000477 ArrayList<DisplayOption> filteredProfiles = new ArrayList<>();
Sunny Goyal415f1732018-11-29 10:33:47 -0800478 if (!TextUtils.isEmpty(gridName)) {
479 for (DisplayOption option : profiles) {
Alex Chau238aaee2021-10-06 16:15:24 +0100480 if (gridName.equals(option.grid.name)
481 && (option.grid.isEnabled || allowDisabledGrid)) {
Sunny Goyalae190ff2020-04-14 00:19:01 +0000482 filteredProfiles.add(option);
Sunny Goyal415f1732018-11-29 10:33:47 -0800483 }
484 }
485 }
Sunny Goyalae190ff2020-04-14 00:19:01 +0000486 if (filteredProfiles.isEmpty()) {
487 // No grid found, use the default options
488 for (DisplayOption option : profiles) {
489 if (option.canBeDefault) {
490 filteredProfiles.add(option);
491 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800492 }
493 }
Sunny Goyalae190ff2020-04-14 00:19:01 +0000494 if (filteredProfiles.isEmpty()) {
495 throw new RuntimeException("No display option with canBeDefault=true");
496 }
497 return filteredProfiles;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700498 }
499
Thales Lima7ec83822021-08-05 13:32:10 +0100500 /**
501 * @return all the grid options that can be shown on the device
502 */
503 public List<GridOption> parseAllGridOptions(Context context) {
504 List<GridOption> result = new ArrayList<>();
Thales Lima1de4d552021-10-13 16:13:25 +0100505
Alex Chau1c883d82021-12-01 18:43:10 +0000506 try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
Thales Lima7ec83822021-08-05 13:32:10 +0100507 final int depth = parser.getDepth();
508 int type;
509 while (((type = parser.next()) != XmlPullParser.END_TAG
510 || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
511 if ((type == XmlPullParser.START_TAG)
512 && GridOption.TAG_NAME.equals(parser.getName())) {
513 GridOption option =
Alex Chau1c883d82021-12-01 18:43:10 +0000514 new GridOption(context, Xml.asAttributeSet(parser), deviceType);
Thales Lima7ec83822021-08-05 13:32:10 +0100515 if (option.isEnabled) {
516 result.add(option);
517 }
518 }
519 }
520 } catch (IOException | XmlPullParserException e) {
521 Log.e(TAG, "Error parsing device profile", e);
522 return Collections.emptyList();
523 }
524 return result;
525 }
526
Sunny Goyal53d7ee42015-05-22 12:25:45 -0700527 private int getLauncherIconDensity(int requiredSize) {
528 // Densities typically defined by an app.
sfufa@google.comde013292021-09-21 18:22:44 -0700529 int[] densityBuckets = new int[]{
Sunny Goyal53d7ee42015-05-22 12:25:45 -0700530 DisplayMetrics.DENSITY_LOW,
531 DisplayMetrics.DENSITY_MEDIUM,
532 DisplayMetrics.DENSITY_TV,
533 DisplayMetrics.DENSITY_HIGH,
534 DisplayMetrics.DENSITY_XHIGH,
535 DisplayMetrics.DENSITY_XXHIGH,
536 DisplayMetrics.DENSITY_XXXHIGH
537 };
538
539 int density = DisplayMetrics.DENSITY_XXXHIGH;
540 for (int i = densityBuckets.length - 1; i >= 0; i--) {
541 float expectedSize = ICON_SIZE_DEFINED_IN_APP_DP * densityBuckets[i]
542 / DisplayMetrics.DENSITY_DEFAULT;
543 if (expectedSize >= requiredSize) {
544 density = densityBuckets[i];
545 }
546 }
547
548 return density;
549 }
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700550
Adam Cohen2e6da152015-05-06 11:42:25 -0700551 /**
552 * Apply any Partner customization grid overrides.
553 *
554 * Currently we support: all apps row / column count.
555 */
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700556 private void applyPartnerDeviceProfileOverrides(Context context, DisplayMetrics dm) {
557 Partner p = Partner.get(context.getPackageManager());
Adam Cohen2e6da152015-05-06 11:42:25 -0700558 if (p != null) {
559 p.applyInvariantDeviceProfileOverrides(this, dm);
560 }
561 }
562
Sunny Goyal415f1732018-11-29 10:33:47 -0800563 private static float dist(float x0, float y0, float x1, float y1) {
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700564 return (float) Math.hypot(x1 - x0, y1 - y0);
Adam Cohen2e6da152015-05-06 11:42:25 -0700565 }
566
Sunny Goyal19ff7282021-04-22 10:12:54 -0700567 private static DisplayOption invDistWeightedInterpolate(
Alex Chau1c883d82021-12-01 18:43:10 +0000568 Info displayInfo, ArrayList<DisplayOption> points, @DeviceType int deviceType) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700569 int minWidthPx = Integer.MAX_VALUE;
570 int minHeightPx = Integer.MAX_VALUE;
571 for (WindowBounds bounds : displayInfo.supportedBounds) {
572 boolean isTablet = displayInfo.isTablet(bounds);
Alex Chau1c883d82021-12-01 18:43:10 +0000573 if (isTablet && deviceType == TYPE_MULTI_DISPLAY) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700574 // For split displays, take half width per page
575 minWidthPx = Math.min(minWidthPx, bounds.availableSize.x / 2);
576 minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700577
Sunny Goyal19ff7282021-04-22 10:12:54 -0700578 } else if (!isTablet && bounds.isLandscape()) {
579 // We will use transposed layout in this case
580 minWidthPx = Math.min(minWidthPx, bounds.availableSize.y);
581 minHeightPx = Math.min(minHeightPx, bounds.availableSize.x);
582 } else {
583 minWidthPx = Math.min(minWidthPx, bounds.availableSize.x);
584 minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
585 }
586 }
587
588 float width = dpiFromPx(minWidthPx, displayInfo.densityDpi);
589 float height = dpiFromPx(minHeightPx, displayInfo.densityDpi);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700590
591 // Sort the profiles based on the closeness to the device size
592 Collections.sort(points, (a, b) ->
593 Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
594 dist(width, height, b.minWidthDps, b.minHeightDps)));
595
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700596 DisplayOption closestPoint = points.get(0);
597 GridOption closestOption = closestPoint.grid;
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700598 float weights = 0;
599
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700600 if (dist(width, height, closestPoint.minWidthDps, closestPoint.minHeightDps) == 0) {
601 return closestPoint;
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700602 }
603
604 DisplayOption out = new DisplayOption(closestOption);
605 for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700606 DisplayOption p = points.get(i);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700607 float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER);
608 weights += w;
609 out.add(new DisplayOption().add(p).multiply(w));
610 }
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700611 out.multiply(1.0f / weights);
612
Thales Lima6e0005a2021-10-27 15:53:41 +0100613 // Since the bitmaps are persisted, ensure that all bitmap sizes are not larger than
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700614 // predefined size to avoid cache invalidation
Thales Lima6e0005a2021-10-27 15:53:41 +0100615 for (int i = INDEX_DEFAULT; i < COUNT_SIZES; i++) {
616 out.iconSizes[i] = Math.min(out.iconSizes[i], closestPoint.iconSizes[i]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700617 }
618
619 return out;
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700620 }
621
Sunny Goyal27835952017-01-13 12:15:53 -0800622 public DeviceProfile getDeviceProfile(Context context) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700623 Resources res = context.getResources();
624 Configuration config = context.getResources().getConfiguration();
625
Sunny Goyal3e9a29c2021-09-07 15:53:09 -0400626 float screenWidth = config.screenWidthDp * res.getDisplayMetrics().density;
627 float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
Sunny Goyal187b16c2022-03-01 16:53:23 -0800628 return getBestMatch(screenWidth, screenHeight,
629 WindowManagerProxy.INSTANCE.get(context).getRotation(context));
Sunny Goyal3e9a29c2021-09-07 15:53:09 -0400630 }
Sunny Goyal19ff7282021-04-22 10:12:54 -0700631
Sunny Goyal187b16c2022-03-01 16:53:23 -0800632 /**
633 * Returns the device profile matching the provided screen configuration
634 */
635 public DeviceProfile getBestMatch(float screenWidth, float screenHeight, int rotation) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700636 DeviceProfile bestMatch = supportedProfiles.get(0);
637 float minDiff = Float.MAX_VALUE;
638
639 for (DeviceProfile profile : supportedProfiles) {
Sunny Goyal3e9a29c2021-09-07 15:53:09 -0400640 float diff = Math.abs(profile.widthPx - screenWidth)
641 + Math.abs(profile.heightPx - screenHeight);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700642 if (diff < minDiff) {
643 minDiff = diff;
644 bestMatch = profile;
Sunny Goyal187b16c2022-03-01 16:53:23 -0800645 } else if (diff == minDiff && profile.rotationHint == rotation) {
646 bestMatch = profile;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700647 }
648 }
649 return bestMatch;
Sunny Goyal27835952017-01-13 12:15:53 -0800650 }
651
Sunny Goyal415f1732018-11-29 10:33:47 -0800652 private static float weight(float x0, float y0, float x1, float y1, float pow) {
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700653 float d = dist(x0, y0, x1, y1);
654 if (Float.compare(d, 0f) == 0) {
655 return Float.POSITIVE_INFINITY;
656 }
657 return (float) (WEIGHT_EFFICIENT / Math.pow(d, pow));
658 }
Sunny Goyal6f866092016-03-17 17:04:15 -0700659
660 /**
661 * As a ratio of screen height, the total distance we want the parallax effect to span
662 * horizontally
663 */
664 private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
665 float aspectRatio = width / (float) height;
666
667 // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
668 // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
669 // We will use these two data points to extrapolate how much the wallpaper parallax effect
670 // to span (ie travel) at any aspect ratio:
671
sfufa@google.comde013292021-09-21 18:22:44 -0700672 final float ASPECT_RATIO_LANDSCAPE = 16 / 10f;
673 final float ASPECT_RATIO_PORTRAIT = 10 / 16f;
Sunny Goyal6f866092016-03-17 17:04:15 -0700674 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
675 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
676
677 // To find out the desired width at different aspect ratios, we use the following two
678 // formulas, where the coefficient on x is the aspect ratio (width/height):
679 // (16/10)x + y = 1.5
680 // (10/16)x + y = 1.2
681 // We solve for x and y and end up with a final formula:
682 final float x =
sfufa@google.comde013292021-09-21 18:22:44 -0700683 (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE
684 - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
Sunny Goyal6f866092016-03-17 17:04:15 -0700685 (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
686 final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
687 return x * aspectRatio + y;
688 }
689
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700690 public interface OnIDPChangeListener {
691
Sunny Goyalb47172b2021-05-03 19:59:51 -0700692 /**
693 * Called when the device provide changes
694 */
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700695 void onIdpChanged(boolean modelPropertiesChanged);
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700696 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800697
698
Sunny Goyaleff44f32019-01-09 17:29:49 -0800699 public static final class GridOption {
Sunny Goyal415f1732018-11-29 10:33:47 -0800700
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800701 public static final String TAG_NAME = "grid-option";
702
Alex Chau1c883d82021-12-01 18:43:10 +0000703 private static final int DEVICE_CATEGORY_PHONE = 1 << 0;
704 private static final int DEVICE_CATEGORY_TABLET = 1 << 1;
705 private static final int DEVICE_CATEGORY_MULTI_DISPLAY = 1 << 2;
706 private static final int DEVICE_CATEGORY_ALL =
707 DEVICE_CATEGORY_PHONE | DEVICE_CATEGORY_TABLET | DEVICE_CATEGORY_MULTI_DISPLAY;
708
Sunny Goyaleff44f32019-01-09 17:29:49 -0800709 public final String name;
710 public final int numRows;
711 public final int numColumns;
Alex Chau9fee3fd2021-12-01 18:43:10 +0000712 public final int numSearchContainerColumns;
Thales Lima7ec83822021-08-05 13:32:10 +0100713 public final boolean isEnabled;
Sunny Goyal415f1732018-11-29 10:33:47 -0800714
715 private final int numFolderRows;
716 private final int numFolderColumns;
717
Sunny Goyal19ff7282021-04-22 10:12:54 -0700718 private final int numAllAppsColumns;
719 private final int numDatabaseAllAppsColumns;
720 private final int numHotseatIcons;
Alex Chau6ed408f2022-03-04 12:58:05 +0000721 private final int numShrunkenHotseatIcons;
Tony Wickhamb87f3cd2021-04-07 15:02:37 -0700722 private final int numDatabaseHotseatIcons;
Sunny Goyal415f1732018-11-29 10:33:47 -0800723
Tracy Zhou7df93d22020-01-27 13:44:06 -0800724 private final String dbFile;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000725
Sunny Goyal415f1732018-11-29 10:33:47 -0800726 private final int defaultLayoutId;
727 private final int demoModeLayoutId;
728
Jon Mirandae126d722021-02-25 10:45:20 -0500729 private final boolean isScalable;
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400730 private final int devicePaddingId;
Jon Mirandae126d722021-02-25 10:45:20 -0500731
Sunny Goyal5bc18462019-01-07 15:13:39 -0800732 private final SparseArray<TypedValue> extraAttrs;
733
Alex Chau1c883d82021-12-01 18:43:10 +0000734 public GridOption(Context context, AttributeSet attrs, @DeviceType int deviceType) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800735 TypedArray a = context.obtainStyledAttributes(
736 attrs, R.styleable.GridDisplayOption);
737 name = a.getString(R.styleable.GridDisplayOption_name);
738 numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0);
739 numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0);
Alex Chau9fee3fd2021-12-01 18:43:10 +0000740 numSearchContainerColumns = a.getInt(
741 R.styleable.GridDisplayOption_numSearchContainerColumns, numColumns);
Sunny Goyal415f1732018-11-29 10:33:47 -0800742
Tracy Zhou7df93d22020-01-27 13:44:06 -0800743 dbFile = a.getString(R.styleable.GridDisplayOption_dbFile);
Alex Chau1c883d82021-12-01 18:43:10 +0000744 defaultLayoutId = a.getResourceId(deviceType == TYPE_MULTI_DISPLAY && a.hasValue(
Alex Chau1e448462021-08-13 21:48:35 +0100745 R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId)
746 ? R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId
747 : R.styleable.GridDisplayOption_defaultLayoutId, 0);
Sunny Goyal415f1732018-11-29 10:33:47 -0800748 demoModeLayoutId = a.getResourceId(
749 R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700750
751 numAllAppsColumns = a.getInt(
752 R.styleable.GridDisplayOption_numAllAppsColumns, numColumns);
753 numDatabaseAllAppsColumns = a.getInt(
754 R.styleable.GridDisplayOption_numExtendedAllAppsColumns, 2 * numAllAppsColumns);
755
756 numHotseatIcons = a.getInt(
Sunny Goyal415f1732018-11-29 10:33:47 -0800757 R.styleable.GridDisplayOption_numHotseatIcons, numColumns);
Alex Chau6ed408f2022-03-04 12:58:05 +0000758 numShrunkenHotseatIcons = a.getInt(
759 R.styleable.GridDisplayOption_numShrunkenHotseatIcons, numHotseatIcons / 2);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700760 numDatabaseHotseatIcons = a.getInt(
761 R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons);
762
Sunny Goyal415f1732018-11-29 10:33:47 -0800763 numFolderRows = a.getInt(
764 R.styleable.GridDisplayOption_numFolderRows, numRows);
765 numFolderColumns = a.getInt(
766 R.styleable.GridDisplayOption_numFolderColumns, numColumns);
Jon Miranda6f7e9702019-09-16 14:44:14 -0700767
Jon Mirandae126d722021-02-25 10:45:20 -0500768 isScalable = a.getBoolean(
769 R.styleable.GridDisplayOption_isScalable, false);
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400770 devicePaddingId = a.getResourceId(
771 R.styleable.GridDisplayOption_devicePaddingId, 0);
Jon Mirandae126d722021-02-25 10:45:20 -0500772
Alex Chau1c883d82021-12-01 18:43:10 +0000773 int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
774 DEVICE_CATEGORY_ALL);
775 isEnabled = (deviceType == TYPE_PHONE
776 && ((deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE))
777 || (deviceType == TYPE_TABLET
778 && ((deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET))
779 || (deviceType == TYPE_MULTI_DISPLAY
780 && ((deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
781 == DEVICE_CATEGORY_MULTI_DISPLAY));
Thales Lima7ec83822021-08-05 13:32:10 +0100782
Sunny Goyal415f1732018-11-29 10:33:47 -0800783 a.recycle();
Sunny Goyal5bc18462019-01-07 15:13:39 -0800784 extraAttrs = Themes.createValueMap(context, attrs,
785 IntArray.wrap(R.styleable.GridDisplayOption));
Sunny Goyal415f1732018-11-29 10:33:47 -0800786 }
787 }
788
Sunny Goyal19ff7282021-04-22 10:12:54 -0700789 @VisibleForTesting
790 static final class DisplayOption {
Thales Lima12d0eff2022-03-25 17:06:11 +0000791 private static final int INLINE_QSB_FOR_PORTRAIT = 1 << 0;
792 private static final int INLINE_QSB_FOR_LANDSCAPE = 1 << 1;
793 private static final int INLINE_QSB_FOR_TWO_PANEL_PORTRAIT = 1 << 2;
794 private static final int INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE = 1 << 3;
795 private static final int DONT_INLINE_QSB = 0;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700796
797 public final GridOption grid;
Sunny Goyal415f1732018-11-29 10:33:47 -0800798
Sunny Goyal415f1732018-11-29 10:33:47 -0800799 private final float minWidthDps;
800 private final float minHeightDps;
801 private final boolean canBeDefault;
Thales Lima12d0eff2022-03-25 17:06:11 +0000802 private final boolean[] inlineQsb = new boolean[COUNT_SIZES];
Sunny Goyal415f1732018-11-29 10:33:47 -0800803
Thales Lima83bedbf2021-10-05 17:47:39 +0100804 private final PointF[] minCellSize = new PointF[COUNT_SIZES];
Thales Lima78d00ad2021-09-30 11:29:06 +0100805
806 private float folderBorderSpace;
807 private final PointF[] borderSpaces = new PointF[COUNT_SIZES];
Thales Lima83bedbf2021-10-05 17:47:39 +0100808 private final float[] horizontalMargin = new float[COUNT_SIZES];
Thales Lima6e7f36c2022-01-04 12:14:11 +0000809 private final float[] hotseatBorderSpaces = new float[COUNT_SIZES];
Thales Limad90faab2021-09-21 17:18:47 +0100810
Thales Lima78d00ad2021-09-30 11:29:06 +0100811 private final float[] iconSizes = new float[COUNT_SIZES];
812 private final float[] textSizes = new float[COUNT_SIZES];
Sunny Goyal415f1732018-11-29 10:33:47 -0800813
Thales Limab7ef5692022-03-10 10:32:36 +0000814 private final PointF[] allAppsCellSize = new PointF[COUNT_SIZES];
Thales Limabb7d3882021-12-22 12:56:29 +0000815 private final float[] allAppsIconSizes = new float[COUNT_SIZES];
816 private final float[] allAppsIconTextSizes = new float[COUNT_SIZES];
817 private final PointF[] allAppsBorderSpaces = new PointF[COUNT_SIZES];
818
Thales Lima1de4d552021-10-13 16:13:25 +0100819 DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800820 this.grid = grid;
821
Thales Lima1de4d552021-10-13 16:13:25 +0100822 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProfileDisplayOption);
Sunny Goyal415f1732018-11-29 10:33:47 -0800823
Sunny Goyal415f1732018-11-29 10:33:47 -0800824 minWidthDps = a.getFloat(R.styleable.ProfileDisplayOption_minWidthDps, 0);
825 minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700826
Thales Lima1de4d552021-10-13 16:13:25 +0100827 canBeDefault = a.getBoolean(R.styleable.ProfileDisplayOption_canBeDefault, false);
Sunny Goyal415f1732018-11-29 10:33:47 -0800828
Thales Lima12d0eff2022-03-25 17:06:11 +0000829 int inlineForRotation = a.getInt(R.styleable.ProfileDisplayOption_inlineQsb,
830 DONT_INLINE_QSB);
831 inlineQsb[INDEX_DEFAULT] =
832 (inlineForRotation & INLINE_QSB_FOR_PORTRAIT) == INLINE_QSB_FOR_PORTRAIT;
833 inlineQsb[INDEX_LANDSCAPE] =
834 (inlineForRotation & INLINE_QSB_FOR_LANDSCAPE) == INLINE_QSB_FOR_LANDSCAPE;
835 inlineQsb[INDEX_TWO_PANEL_PORTRAIT] =
836 (inlineForRotation & INLINE_QSB_FOR_TWO_PANEL_PORTRAIT)
837 == INLINE_QSB_FOR_TWO_PANEL_PORTRAIT;
838 inlineQsb[INDEX_TWO_PANEL_LANDSCAPE] =
839 (inlineForRotation & INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE)
840 == INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE;
841
Thales Lima83bedbf2021-10-05 17:47:39 +0100842 float x;
843 float y;
844
Thales Lima85c942f2021-12-31 13:04:20 +0000845 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidth, 0);
846 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeight, 0);
Thales Lima83bedbf2021-10-05 17:47:39 +0100847 minCellSize[INDEX_DEFAULT] = new PointF(x, y);
Thales Limadd027342022-01-07 12:54:37 +0000848
849 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthLandscape,
850 minCellSize[INDEX_DEFAULT].x);
851 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightLandscape,
852 minCellSize[INDEX_DEFAULT].y);
Thales Lima83bedbf2021-10-05 17:47:39 +0100853 minCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
Thales Lima83bedbf2021-10-05 17:47:39 +0100854
Thales Lima85c942f2021-12-31 13:04:20 +0000855 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthTwoPanelPortrait,
Thales Lima83bedbf2021-10-05 17:47:39 +0100856 minCellSize[INDEX_DEFAULT].x);
Thales Lima85c942f2021-12-31 13:04:20 +0000857 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightTwoPanelPortrait,
Thales Lima83bedbf2021-10-05 17:47:39 +0100858 minCellSize[INDEX_DEFAULT].y);
859 minCellSize[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
860
Thales Lima85c942f2021-12-31 13:04:20 +0000861 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100862 minCellSize[INDEX_DEFAULT].x);
Thales Lima85c942f2021-12-31 13:04:20 +0000863 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100864 minCellSize[INDEX_DEFAULT].y);
865 minCellSize[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
Thales Lima78d00ad2021-09-30 11:29:06 +0100866
Thales Lima85c942f2021-12-31 13:04:20 +0000867 float borderSpace = a.getFloat(R.styleable.ProfileDisplayOption_borderSpace, 0);
Thales Lima44cc3a22022-03-18 14:28:24 +0000868 float borderSpaceLandscape = a.getFloat(
869 R.styleable.ProfileDisplayOption_borderSpaceLandscape, borderSpace);
Thales Lima85c942f2021-12-31 13:04:20 +0000870 float borderSpaceTwoPanelPortrait = a.getFloat(
871 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelPortrait, borderSpace);
872 float borderSpaceTwoPanelLandscape = a.getFloat(
873 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelLandscape, borderSpace);
Thales Lima78d00ad2021-09-30 11:29:06 +0100874
Thales Lima85c942f2021-12-31 13:04:20 +0000875 x = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceHorizontal, borderSpace);
876 y = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceVertical, borderSpace);
Thales Lima78d00ad2021-09-30 11:29:06 +0100877 borderSpaces[INDEX_DEFAULT] = new PointF(x, y);
Thales Lima44cc3a22022-03-18 14:28:24 +0000878
879 x = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceLandscapeHorizontal,
880 borderSpaceLandscape);
881 y = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceLandscapeVertical,
882 borderSpaceLandscape);
Thales Lima78d00ad2021-09-30 11:29:06 +0100883 borderSpaces[INDEX_LANDSCAPE] = new PointF(x, y);
884
885 x = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000886 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelPortraitHorizontal,
887 borderSpaceTwoPanelPortrait);
Thales Lima78d00ad2021-09-30 11:29:06 +0100888 y = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000889 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelPortraitVertical,
890 borderSpaceTwoPanelPortrait);
Thales Lima78d00ad2021-09-30 11:29:06 +0100891 borderSpaces[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
892
893 x = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000894 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelLandscapeHorizontal,
895 borderSpaceTwoPanelLandscape);
Thales Lima78d00ad2021-09-30 11:29:06 +0100896 y = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000897 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelLandscapeVertical,
898 borderSpaceTwoPanelLandscape);
Thales Lima78d00ad2021-09-30 11:29:06 +0100899 borderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
900
Thales Limabb7d3882021-12-22 12:56:29 +0000901 folderBorderSpace = borderSpace;
902
Thales Limab7ef5692022-03-10 10:32:36 +0000903 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidth,
904 minCellSize[INDEX_DEFAULT].x);
905 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeight,
906 minCellSize[INDEX_DEFAULT].y);
907 allAppsCellSize[INDEX_DEFAULT] = new PointF(x, y);
908
909 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthLandscape,
910 allAppsCellSize[INDEX_DEFAULT].x);
911 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightLandscape,
912 allAppsCellSize[INDEX_DEFAULT].y);
913 allAppsCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
914
915 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelPortrait,
916 allAppsCellSize[INDEX_DEFAULT].x);
917 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelPortrait,
918 allAppsCellSize[INDEX_DEFAULT].y);
919 allAppsCellSize[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
920
921 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelLandscape,
922 allAppsCellSize[INDEX_DEFAULT].x);
923 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelLandscape,
924 allAppsCellSize[INDEX_DEFAULT].y);
925 allAppsCellSize[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
926
Thales Lima85c942f2021-12-31 13:04:20 +0000927 x = y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpace,
Thales Lima78d00ad2021-09-30 11:29:06 +0100928 borderSpace);
Thales Limabb7d3882021-12-22 12:56:29 +0000929 allAppsBorderSpaces[INDEX_DEFAULT] = new PointF(x, y);
Thales Limab7ef5692022-03-10 10:32:36 +0000930 x = y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceLandscape,
931 allAppsBorderSpaces[INDEX_DEFAULT].x);
Thales Limabb7d3882021-12-22 12:56:29 +0000932 allAppsBorderSpaces[INDEX_LANDSCAPE] = new PointF(x, y);
933 x = y = a.getFloat(
934 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelPortrait,
935 allAppsBorderSpaces[INDEX_DEFAULT].x);
936 allAppsBorderSpaces[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
937 x = y = a.getFloat(
938 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelLandscape,
939 allAppsBorderSpaces[INDEX_DEFAULT].x);
940 allAppsBorderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
Jon Mirandae126d722021-02-25 10:45:20 -0500941
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700942 iconSizes[INDEX_DEFAULT] =
943 a.getFloat(R.styleable.ProfileDisplayOption_iconImageSize, 0);
944 iconSizes[INDEX_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +0000945 a.getFloat(R.styleable.ProfileDisplayOption_iconSizeLandscape,
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700946 iconSizes[INDEX_DEFAULT]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700947 iconSizes[INDEX_TWO_PANEL_PORTRAIT] =
Thales Lima85c942f2021-12-31 13:04:20 +0000948 a.getFloat(R.styleable.ProfileDisplayOption_iconSizeTwoPanelPortrait,
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700949 iconSizes[INDEX_DEFAULT]);
950 iconSizes[INDEX_TWO_PANEL_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +0000951 a.getFloat(R.styleable.ProfileDisplayOption_iconSizeTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100952 iconSizes[INDEX_DEFAULT]);
Jon Miranda6f7e9702019-09-16 14:44:14 -0700953
Thales Limabb7d3882021-12-22 12:56:29 +0000954 allAppsIconSizes[INDEX_DEFAULT] = a.getFloat(
955 R.styleable.ProfileDisplayOption_allAppsIconSize, iconSizes[INDEX_DEFAULT]);
956 allAppsIconSizes[INDEX_LANDSCAPE] = allAppsIconSizes[INDEX_DEFAULT];
957 allAppsIconSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
958 R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelPortrait,
959 allAppsIconSizes[INDEX_DEFAULT]);
960 allAppsIconSizes[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
961 R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelLandscape,
962 allAppsIconSizes[INDEX_DEFAULT]);
963
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700964 textSizes[INDEX_DEFAULT] =
965 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
966 textSizes[INDEX_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +0000967 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSizeLandscape,
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700968 textSizes[INDEX_DEFAULT]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700969 textSizes[INDEX_TWO_PANEL_PORTRAIT] =
Thales Lima85c942f2021-12-31 13:04:20 +0000970 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSizeTwoPanelPortrait,
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700971 textSizes[INDEX_DEFAULT]);
972 textSizes[INDEX_TWO_PANEL_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +0000973 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSizeTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100974 textSizes[INDEX_DEFAULT]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700975
Thales Limabb7d3882021-12-22 12:56:29 +0000976 allAppsIconTextSizes[INDEX_DEFAULT] = a.getFloat(
977 R.styleable.ProfileDisplayOption_allAppsIconTextSize, textSizes[INDEX_DEFAULT]);
978 allAppsIconTextSizes[INDEX_LANDSCAPE] = allAppsIconTextSizes[INDEX_DEFAULT];
979 allAppsIconTextSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
980 R.styleable.ProfileDisplayOption_allAppsIconTextSizeTwoPanelPortrait,
981 allAppsIconTextSizes[INDEX_DEFAULT]);
982 allAppsIconTextSizes[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
983 R.styleable.ProfileDisplayOption_allAppsIconTextSizeTwoPanelLandscape,
984 allAppsIconTextSizes[INDEX_DEFAULT]);
985
Thales Lima83bedbf2021-10-05 17:47:39 +0100986 horizontalMargin[INDEX_DEFAULT] = a.getFloat(
987 R.styleable.ProfileDisplayOption_horizontalMargin, 0);
Thales Limadd027342022-01-07 12:54:37 +0000988 horizontalMargin[INDEX_LANDSCAPE] = a.getFloat(
989 R.styleable.ProfileDisplayOption_horizontalMarginLandscape,
990 horizontalMargin[INDEX_DEFAULT]);
Thales Lima83bedbf2021-10-05 17:47:39 +0100991 horizontalMargin[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000992 R.styleable.ProfileDisplayOption_horizontalMarginTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100993 horizontalMargin[INDEX_DEFAULT]);
994 horizontalMargin[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000995 R.styleable.ProfileDisplayOption_horizontalMarginTwoPanelPortrait,
Thales Lima83bedbf2021-10-05 17:47:39 +0100996 horizontalMargin[INDEX_DEFAULT]);
Thales Limad90faab2021-09-21 17:18:47 +0100997
Thales Lima6e7f36c2022-01-04 12:14:11 +0000998 hotseatBorderSpaces[INDEX_DEFAULT] = a.getFloat(
999 R.styleable.ProfileDisplayOption_hotseatBorderSpace, borderSpace);
Thales Limadd027342022-01-07 12:54:37 +00001000 hotseatBorderSpaces[INDEX_LANDSCAPE] = a.getFloat(
1001 R.styleable.ProfileDisplayOption_hotseatBorderSpaceLandscape,
1002 hotseatBorderSpaces[INDEX_DEFAULT]);
Thales Lima6e7f36c2022-01-04 12:14:11 +00001003 hotseatBorderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
1004 R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelLandscape,
1005 hotseatBorderSpaces[INDEX_DEFAULT]);
1006 hotseatBorderSpaces[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
1007 R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelPortrait,
1008 hotseatBorderSpaces[INDEX_DEFAULT]);
1009
Sunny Goyal415f1732018-11-29 10:33:47 -08001010 a.recycle();
1011 }
1012
1013 DisplayOption() {
Sunny Goyal0e7a3382020-04-13 17:15:05 -07001014 this(null);
1015 }
1016
1017 DisplayOption(GridOption grid) {
1018 this.grid = grid;
Sunny Goyal415f1732018-11-29 10:33:47 -08001019 minWidthDps = 0;
1020 minHeightDps = 0;
1021 canBeDefault = false;
Thales Lima78d00ad2021-09-30 11:29:06 +01001022 for (int i = 0; i < COUNT_SIZES; i++) {
1023 iconSizes[i] = 0;
1024 textSizes[i] = 0;
1025 borderSpaces[i] = new PointF();
Thales Lima83bedbf2021-10-05 17:47:39 +01001026 minCellSize[i] = new PointF();
Thales Limab7ef5692022-03-10 10:32:36 +00001027 allAppsCellSize[i] = new PointF();
Thales Limabb7d3882021-12-22 12:56:29 +00001028 allAppsIconSizes[i] = 0;
1029 allAppsIconTextSizes[i] = 0;
1030 allAppsBorderSpaces[i] = new PointF();
Thales Lima12d0eff2022-03-25 17:06:11 +00001031 inlineQsb[i] = false;
Thales Lima78d00ad2021-09-30 11:29:06 +01001032 }
Sunny Goyal415f1732018-11-29 10:33:47 -08001033 }
1034
1035 private DisplayOption multiply(float w) {
Thales Lima78d00ad2021-09-30 11:29:06 +01001036 for (int i = 0; i < COUNT_SIZES; i++) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001037 iconSizes[i] *= w;
1038 textSizes[i] *= w;
Thales Lima83bedbf2021-10-05 17:47:39 +01001039 borderSpaces[i].x *= w;
1040 borderSpaces[i].y *= w;
1041 minCellSize[i].x *= w;
1042 minCellSize[i].y *= w;
1043 horizontalMargin[i] *= w;
Thales Lima6e7f36c2022-01-04 12:14:11 +00001044 hotseatBorderSpaces[i] *= w;
Thales Limab7ef5692022-03-10 10:32:36 +00001045 allAppsCellSize[i].x *= w;
1046 allAppsCellSize[i].y *= w;
Thales Limabb7d3882021-12-22 12:56:29 +00001047 allAppsIconSizes[i] *= w;
1048 allAppsIconTextSizes[i] *= w;
1049 allAppsBorderSpaces[i].x *= w;
1050 allAppsBorderSpaces[i].y *= w;
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001051 }
Thales Lima78d00ad2021-09-30 11:29:06 +01001052
1053 folderBorderSpace *= w;
1054
Sunny Goyal415f1732018-11-29 10:33:47 -08001055 return this;
1056 }
1057
1058 private DisplayOption add(DisplayOption p) {
Thales Lima78d00ad2021-09-30 11:29:06 +01001059 for (int i = 0; i < COUNT_SIZES; i++) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001060 iconSizes[i] += p.iconSizes[i];
1061 textSizes[i] += p.textSizes[i];
Thales Lima83bedbf2021-10-05 17:47:39 +01001062 borderSpaces[i].x += p.borderSpaces[i].x;
1063 borderSpaces[i].y += p.borderSpaces[i].y;
1064 minCellSize[i].x += p.minCellSize[i].x;
1065 minCellSize[i].y += p.minCellSize[i].y;
1066 horizontalMargin[i] += p.horizontalMargin[i];
Thales Lima6e7f36c2022-01-04 12:14:11 +00001067 hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i];
Thales Limab7ef5692022-03-10 10:32:36 +00001068 allAppsCellSize[i].x += p.allAppsCellSize[i].x;
1069 allAppsCellSize[i].y += p.allAppsCellSize[i].y;
Thales Limabb7d3882021-12-22 12:56:29 +00001070 allAppsIconSizes[i] += p.allAppsIconSizes[i];
1071 allAppsIconTextSizes[i] += p.allAppsIconTextSizes[i];
1072 allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
1073 allAppsBorderSpaces[i].y += p.allAppsBorderSpaces[i].y;
Thales Lima12d0eff2022-03-25 17:06:11 +00001074 inlineQsb[i] |= p.inlineQsb[i];
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001075 }
Thales Lima78d00ad2021-09-30 11:29:06 +01001076
1077 folderBorderSpace += p.folderBorderSpace;
1078
Sunny Goyal415f1732018-11-29 10:33:47 -08001079 return this;
1080 }
1081 }
Sunny Goyalae190ff2020-04-14 00:19:01 +00001082}