blob: 1f920793fdc360e32d5bdb95b0ee9d4199edff04 [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 Chaud3e8cc42022-05-03 17:45:34 +010064import java.io.PrintWriter;
65import java.io.StringWriter;
Alex Chau1c883d82021-12-01 18:43:10 +000066import java.lang.annotation.Retention;
67import java.lang.annotation.RetentionPolicy;
Adam Cohen2e6da152015-05-06 11:42:25 -070068import java.util.ArrayList;
Sunny Goyal6e6f7992021-08-24 16:23:29 -070069import java.util.Arrays;
Sunny Goyal6d55f662019-01-02 12:13:43 -080070import java.util.Collections;
Sunny Goyal19ff7282021-04-22 10:12:54 -070071import java.util.List;
Adam Cohen2e6da152015-05-06 11:42:25 -070072
73public class InvariantDeviceProfile {
Adam Cohen2e6da152015-05-06 11:42:25 -070074
Hyunyoung Songc55a3502018-12-04 15:43:16 -080075 public static final String TAG = "IDP";
Sunny Goyald0e360a2018-06-29 14:40:18 -070076 // We do not need any synchronization for this variable as its only written on UI thread.
77 public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
Sunny Goyal87dc48b2018-10-12 11:42:33 -070078 new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
Adam Cohen2e6da152015-05-06 11:42:25 -070079
Alex Chau1c883d82021-12-01 18:43:10 +000080 @Retention(RetentionPolicy.SOURCE)
81 @IntDef({TYPE_PHONE, TYPE_MULTI_DISPLAY, TYPE_TABLET})
82 public @interface DeviceType{}
83 public static final int TYPE_PHONE = 0;
84 public static final int TYPE_MULTI_DISPLAY = 1;
85 public static final int TYPE_TABLET = 2;
86
Hyunyoung Songc55a3502018-12-04 15:43:16 -080087 private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
Sunny Goyal415f1732018-11-29 10:33:47 -080088
Sunny Goyal53d7ee42015-05-22 12:25:45 -070089 private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
90
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -070091 // Constants that affects the interpolation curve between statically defined device profile
92 // buckets.
Hyunyoung Songc55a3502018-12-04 15:43:16 -080093 private static final float KNEARESTNEIGHBOR = 3;
94 private static final float WEIGHT_POWER = 5;
Adam Cohen2e6da152015-05-06 11:42:25 -070095
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -070096 // used to offset float not being able to express extremely small weights in extreme cases.
Hyunyoung Songc55a3502018-12-04 15:43:16 -080097 private static final float WEIGHT_EFFICIENT = 100000f;
98
Thales Lima83bedbf2021-10-05 17:47:39 +010099 // Used for arrays to specify different sizes (e.g. border spaces, width/height) in different
100 // constraints
Thales Limabb7d3882021-12-22 12:56:29 +0000101 static final int COUNT_SIZES = 4;
Thales Lima83bedbf2021-10-05 17:47:39 +0100102 static final int INDEX_DEFAULT = 0;
103 static final int INDEX_LANDSCAPE = 1;
104 static final int INDEX_TWO_PANEL_PORTRAIT = 2;
105 static final int INDEX_TWO_PANEL_LANDSCAPE = 3;
Thales Lima83bedbf2021-10-05 17:47:39 +0100106
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700107 /**
108 * Number of icons per row and column in the workspace.
109 */
Adam Cohen2e6da152015-05-06 11:42:25 -0700110 public int numRows;
111 public int numColumns;
Alex Chau9fee3fd2021-12-01 18:43:10 +0000112 public int numSearchContainerColumns;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700113
114 /**
115 * Number of icons per row and column in the folder.
116 */
Adam Cohen2e6da152015-05-06 11:42:25 -0700117 public int numFolderRows;
118 public int numFolderColumns;
Thales Lima83bedbf2021-10-05 17:47:39 +0100119 public float[] iconSize;
120 public float[] iconTextSize;
Sunny Goyalfc218302015-09-17 14:59:10 -0700121 public int iconBitmapSize;
122 public int fillResIconDpi;
Alex Chau1c883d82021-12-01 18:43:10 +0000123 public @DeviceType int deviceType;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700124
Thales Lima83bedbf2021-10-05 17:47:39 +0100125 public PointF[] minCellSize;
Thales Lima78d00ad2021-09-30 11:29:06 +0100126
Thales Lima83bedbf2021-10-05 17:47:39 +0100127 public PointF[] borderSpaces;
Thales Lima78d00ad2021-09-30 11:29:06 +0100128 public float folderBorderSpace;
Thales Lima6e7f36c2022-01-04 12:14:11 +0000129 public float[] hotseatBorderSpaces;
Thales Lima78d00ad2021-09-30 11:29:06 +0100130
Thales Lima83bedbf2021-10-05 17:47:39 +0100131 public float[] horizontalMargin;
Jon Mirandae126d722021-02-25 10:45:20 -0500132
Thales Limab7ef5692022-03-10 10:32:36 +0000133 public PointF[] allAppsCellSize;
Thales Limabb7d3882021-12-22 12:56:29 +0000134 public float[] allAppsIconSize;
135 public float[] allAppsIconTextSize;
136 public PointF[] allAppsBorderSpaces;
137
Sunny Goyal5bc18462019-01-07 15:13:39 -0800138 private SparseArray<TypedValue> mExtraAttrs;
139
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700140 /**
141 * Number of icons inside the hotseat area.
142 */
Jon Mirandafd48b0c2022-01-31 16:25:22 -0800143 public int numShownHotseatIcons;
Tony Wickhamb87f3cd2021-04-07 15:02:37 -0700144
145 /**
Alex Chau6ed408f2022-03-04 12:58:05 +0000146 * Number of icons inside the hotseat area when using 3 buttons navigation.
147 */
148 public int numShrunkenHotseatIcons;
149
150 /**
Tony Wickhamb87f3cd2021-04-07 15:02:37 -0700151 * Number of icons inside the hotseat area that is stored in the database. This is greater than
152 * or equal to numnShownHotseatIcons, allowing for a seamless transition between two hotseat
153 * sizes that share the same DB.
154 */
155 public int numDatabaseHotseatIcons;
Adam Cohen27824492017-09-22 17:10:55 -0700156
Jon Miranda6f7e9702019-09-16 14:44:14 -0700157 /**
158 * Number of columns in the all apps list.
159 */
160 public int numAllAppsColumns;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700161 public int numDatabaseAllAppsColumns;
Jon Miranda6f7e9702019-09-16 14:44:14 -0700162
Jon Mirandae126d722021-02-25 10:45:20 -0500163 /**
164 * Do not query directly. see {@link DeviceProfile#isScalableGrid}.
165 */
166 protected boolean isScalable;
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400167 public int devicePaddingId;
Jon Mirandae126d722021-02-25 10:45:20 -0500168
Tracy Zhou7df93d22020-01-27 13:44:06 -0800169 public String dbFile;
Sunny Goyal415f1732018-11-29 10:33:47 -0800170 public int defaultLayoutId;
Adam Cohen27824492017-09-22 17:10:55 -0700171 int demoModeLayoutId;
Thales Lima12d0eff2022-03-25 17:06:11 +0000172 boolean[] inlineQsb = new boolean[COUNT_SIZES];
Adam Cohen2e6da152015-05-06 11:42:25 -0700173
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000174 /**
175 * An immutable list of supported profiles.
176 */
177 public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST;
Sunny Goyalc6205602015-05-21 20:46:33 -0700178
sfufa@google.comde013292021-09-21 18:22:44 -0700179 @Nullable
180 public DevicePaddings devicePaddings;
Jon Miranda228877d2021-02-09 11:05:00 -0500181
Sunny Goyal6f866092016-03-17 17:04:15 -0700182 public Point defaultWallpaperSize;
Sunny Goyal58fa4b62019-03-22 16:23:25 -0700183 public Rect defaultWidgetPadding;
Sunny Goyal6f866092016-03-17 17:04:15 -0700184
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700185 private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700186
Sunny Goyalf633ef52018-03-13 09:57:05 -0700187 @VisibleForTesting
Sunny Goyal187b16c2022-03-01 16:53:23 -0800188 public InvariantDeviceProfile() { }
Adam Cohen2e6da152015-05-06 11:42:25 -0700189
Sunny Goyalbbf01842015-10-08 07:41:15 -0700190 @TargetApi(23)
Sunny Goyald0e360a2018-06-29 14:40:18 -0700191 private InvariantDeviceProfile(Context context) {
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700192 String gridName = getCurrentGridName(context);
193 String newGridName = initGrid(context, gridName);
194 if (!newGridName.equals(gridName)) {
195 Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply();
196 }
Sunny Goyal68031ca2021-08-02 12:23:44 -0700197 new DeviceGridState(this).writeToPrefs(context);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700198
Tracy Zhouc8beebf2021-09-23 10:18:11 -0700199 DisplayController.INSTANCE.get(context).setPriorityListener(
Alex Chaufd6d9422021-04-22 19:10:21 +0100200 (displayContext, info, flags) -> {
Alex Chau6ed408f2022-03-04 12:58:05 +0000201 if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS
202 | CHANGE_NAVIGATION_MODE)) != 0) {
Alex Chaufd6d9422021-04-22 19:10:21 +0100203 onConfigChanged(displayContext);
Sunny Goyal35c7b192021-04-20 16:51:10 -0700204 }
205 });
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700206 }
207
Hyunyoung Songe11eb472019-03-19 15:05:21 -0700208 /**
209 * This constructor should NOT have any monitors by design.
210 */
Sunny Goyaleff44f32019-01-09 17:29:49 -0800211 public InvariantDeviceProfile(Context context, String gridName) {
212 String newName = initGrid(context, gridName);
213 if (newName == null || !newName.equals(gridName)) {
214 throw new IllegalArgumentException("Unknown grid name");
215 }
216 }
217
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700218 /**
Sunny Goyal9c2b9602020-01-07 13:07:55 -0800219 * This constructor should NOT have any monitors by design.
220 */
221 public InvariantDeviceProfile(Context context, Display display) {
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700222 // Ensure that the main device profile is initialized
Alex Chaufd6d9422021-04-22 19:10:21 +0100223 INSTANCE.get(context);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700224 String gridName = getCurrentGridName(context);
225
226 // Get the display info based on default display and interpolate it to existing display
Alex Chau1c883d82021-12-01 18:43:10 +0000227 Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
228 @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700229 DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
Alex Chau1c883d82021-12-01 18:43:10 +0000230 defaultInfo,
231 getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
232 /*allowDisabledGrid=*/false),
233 defaultDeviceType);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700234
Alex Chau417bd722021-01-26 15:22:18 +0000235 Info myInfo = new Info(context, display);
Alex Chau1c883d82021-12-01 18:43:10 +0000236 @DeviceType int deviceType = getDeviceType(myInfo);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700237 DisplayOption myDisplayOption = invDistWeightedInterpolate(
Alex Chau1c883d82021-12-01 18:43:10 +0000238 myInfo,
239 getPredefinedDeviceProfiles(context, gridName, deviceType,
240 /*allowDisabledGrid=*/false),
241 deviceType);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700242
243 DisplayOption result = new DisplayOption(defaultDisplayOption.grid)
244 .add(myDisplayOption);
Thales Lima83bedbf2021-10-05 17:47:39 +0100245 result.iconSizes[INDEX_DEFAULT] =
246 defaultDisplayOption.iconSizes[INDEX_DEFAULT];
247 for (int i = 1; i < COUNT_SIZES; i++) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700248 result.iconSizes[i] = Math.min(
249 defaultDisplayOption.iconSizes[i], myDisplayOption.iconSizes[i]);
Alex Chau7c439722021-03-24 11:32:44 +0000250 }
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700251
Thales Lima83bedbf2021-10-05 17:47:39 +0100252 System.arraycopy(defaultDisplayOption.minCellSize, 0, result.minCellSize, 0,
253 COUNT_SIZES);
254 System.arraycopy(defaultDisplayOption.borderSpaces, 0, result.borderSpaces, 0,
255 COUNT_SIZES);
Thales Lima12d0eff2022-03-25 17:06:11 +0000256 System.arraycopy(defaultDisplayOption.inlineQsb, 0, result.inlineQsb, 0,
257 COUNT_SIZES);
Jon Miranda228877d2021-02-09 11:05:00 -0500258
Alex Chau1c883d82021-12-01 18:43:10 +0000259 initGrid(context, myInfo, result, deviceType);
Sunny Goyal9c2b9602020-01-07 13:07:55 -0800260 }
261
Alex Chau238aaee2021-10-06 16:15:24 +0100262 /**
263 * Reinitialize the current grid after a restore, where some grids might now be disabled.
264 */
265 public void reinitializeAfterRestore(Context context) {
Alex Chau29a96ad2022-02-10 13:12:20 +0000266 String currentGridName = getCurrentGridName(context);
Alex Chau238aaee2021-10-06 16:15:24 +0100267 String currentDbFile = dbFile;
Alex Chau29a96ad2022-02-10 13:12:20 +0000268 String newGridName = initGrid(context, currentGridName);
269 String newDbFile = dbFile;
270 if (!newDbFile.equals(currentDbFile)) {
271 Log.d(TAG, "Restored grid is disabled : " + currentGridName
Alex Chau238aaee2021-10-06 16:15:24 +0100272 + ", migrating to: " + newGridName
273 + ", removing all other grid db files");
274 for (String gridDbFile : LauncherFiles.GRID_DB_FILES) {
275 if (gridDbFile.equals(currentDbFile)) {
276 continue;
277 }
278 if (context.getDatabasePath(gridDbFile).delete()) {
279 Log.d(TAG, "Removed old grid db file: " + gridDbFile);
280 }
281 }
Alex Chau29a96ad2022-02-10 13:12:20 +0000282 setCurrentGrid(context, newGridName);
Alex Chau238aaee2021-10-06 16:15:24 +0100283 }
284 }
285
Alex Chau1c883d82021-12-01 18:43:10 +0000286 private static @DeviceType int getDeviceType(Info displayInfo) {
Sunny Goyal187b16c2022-03-01 16:53:23 -0800287 int flagPhone = 1 << 0;
288 int flagTablet = 1 << 1;
289
290 int type = displayInfo.supportedBounds.stream()
291 .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
292 .reduce(0, (a, b) -> a | b);
293 if ((type == (flagPhone | flagTablet)) && ENABLE_TWO_PANEL_HOME.get()) {
294 // device has profiles supporting both phone and table modes
Alex Chau1c883d82021-12-01 18:43:10 +0000295 return TYPE_MULTI_DISPLAY;
Sunny Goyal187b16c2022-03-01 16:53:23 -0800296 } else if (type == flagTablet) {
Alex Chau1c883d82021-12-01 18:43:10 +0000297 return TYPE_TABLET;
298 } else {
299 return TYPE_PHONE;
300 }
301 }
302
Tracy Zhou42255d22020-03-13 00:38:11 -0700303 public static String getCurrentGridName(Context context) {
Tracy Zhouc6060e62020-04-27 13:05:34 -0700304 return Utilities.isGridOptionsEnabled(context)
305 ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null) : null;
Tracy Zhou42255d22020-03-13 00:38:11 -0700306 }
307
Sunny Goyaleff44f32019-01-09 17:29:49 -0800308 private String initGrid(Context context, String gridName) {
Sunny Goyal35c7b192021-04-20 16:51:10 -0700309 Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
Alex Chau1c883d82021-12-01 18:43:10 +0000310 @DeviceType int deviceType = getDeviceType(displayInfo);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700311
312 ArrayList<DisplayOption> allOptions =
Alex Chau1c883d82021-12-01 18:43:10 +0000313 getPredefinedDeviceProfiles(context, gridName, deviceType,
Alex Chau238aaee2021-10-06 16:15:24 +0100314 RestoreDbTask.isPending(context));
Sunny Goyal19ff7282021-04-22 10:12:54 -0700315 DisplayOption displayOption =
Alex Chau1c883d82021-12-01 18:43:10 +0000316 invDistWeightedInterpolate(displayInfo, allOptions, deviceType);
317 initGrid(context, displayInfo, displayOption, deviceType);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700318 return displayOption.grid.name;
Sunny Goyal9c2b9602020-01-07 13:07:55 -0800319 }
Adam Cohen2e6da152015-05-06 11:42:25 -0700320
Alex Chau1c883d82021-12-01 18:43:10 +0000321 private void initGrid(Context context, Info displayInfo, DisplayOption displayOption,
322 @DeviceType int deviceType) {
Sunny Goyal35c7b192021-04-20 16:51:10 -0700323 DisplayMetrics metrics = context.getResources().getDisplayMetrics();
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700324 GridOption closestProfile = displayOption.grid;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000325 numRows = closestProfile.numRows;
326 numColumns = closestProfile.numColumns;
Alex Chau9fee3fd2021-12-01 18:43:10 +0000327 numSearchContainerColumns = closestProfile.numSearchContainerColumns;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000328 dbFile = closestProfile.dbFile;
329 defaultLayoutId = closestProfile.defaultLayoutId;
330 demoModeLayoutId = closestProfile.demoModeLayoutId;
331 numFolderRows = closestProfile.numFolderRows;
332 numFolderColumns = closestProfile.numFolderColumns;
Jon Mirandae126d722021-02-25 10:45:20 -0500333 isScalable = closestProfile.isScalable;
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400334 devicePaddingId = closestProfile.devicePaddingId;
Alex Chau1c883d82021-12-01 18:43:10 +0000335 this.deviceType = deviceType;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000336
337 mExtraAttrs = closestProfile.extraAttrs;
338
Thales Lima83bedbf2021-10-05 17:47:39 +0100339 iconSize = displayOption.iconSizes;
Thales Lima6e0005a2021-10-27 15:53:41 +0100340 float maxIconSize = iconSize[0];
341 for (int i = 1; i < iconSize.length; i++) {
342 maxIconSize = Math.max(maxIconSize, iconSize[i]);
343 }
344 iconBitmapSize = ResourceUtils.pxFromDp(maxIconSize, metrics);
Sunny Goyalae190ff2020-04-14 00:19:01 +0000345 fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
346
Thales Lima83bedbf2021-10-05 17:47:39 +0100347 iconTextSize = displayOption.textSizes;
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700348
Thales Lima83bedbf2021-10-05 17:47:39 +0100349 minCellSize = displayOption.minCellSize;
Thales Lima78d00ad2021-09-30 11:29:06 +0100350
Thales Lima83bedbf2021-10-05 17:47:39 +0100351 borderSpaces = displayOption.borderSpaces;
Thales Lima78d00ad2021-09-30 11:29:06 +0100352 folderBorderSpace = displayOption.folderBorderSpace;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700353
Thales Limad90faab2021-09-21 17:18:47 +0100354 horizontalMargin = displayOption.horizontalMargin;
Thales Limad90faab2021-09-21 17:18:47 +0100355
Sunny Goyal19ff7282021-04-22 10:12:54 -0700356 numShownHotseatIcons = closestProfile.numHotseatIcons;
Alex Chau6ed408f2022-03-04 12:58:05 +0000357 numShrunkenHotseatIcons = closestProfile.numShrunkenHotseatIcons;
Alex Chau1c883d82021-12-01 18:43:10 +0000358 numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
Sunny Goyal19ff7282021-04-22 10:12:54 -0700359 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
Thales Lima6e7f36c2022-01-04 12:14:11 +0000360 hotseatBorderSpaces = displayOption.hotseatBorderSpaces;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700361
362 numAllAppsColumns = closestProfile.numAllAppsColumns;
Alex Chau1c883d82021-12-01 18:43:10 +0000363 numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
Sunny Goyal19ff7282021-04-22 10:12:54 -0700364 ? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
Jon Mirandae126d722021-02-25 10:45:20 -0500365
Thales Limab7ef5692022-03-10 10:32:36 +0000366 allAppsCellSize = displayOption.allAppsCellSize;
Thales Limabb7d3882021-12-22 12:56:29 +0000367 allAppsBorderSpaces = displayOption.allAppsBorderSpaces;
368 allAppsIconSize = displayOption.allAppsIconSizes;
369 allAppsIconTextSize = displayOption.allAppsIconTextSizes;
Thales Lima83bedbf2021-10-05 17:47:39 +0100370 if (!Utilities.isGridOptionsEnabled(context)) {
Thales Limabb7d3882021-12-22 12:56:29 +0000371 allAppsIconSize = iconSize;
372 allAppsIconTextSize = iconTextSize;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000373 }
374
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400375 if (devicePaddingId != 0) {
376 devicePaddings = new DevicePaddings(context, devicePaddingId);
377 }
378
Thales Lima12d0eff2022-03-25 17:06:11 +0000379 inlineQsb = displayOption.inlineQsb;
380
Sunny Goyalae190ff2020-04-14 00:19:01 +0000381 // If the partner customization apk contains any grid overrides, apply them
382 // Supported overrides: numRows, numColumns, iconSize
Sunny Goyal35c7b192021-04-20 16:51:10 -0700383 applyPartnerDeviceProfileOverrides(context, metrics);
Sunny Goyalc6205602015-05-21 20:46:33 -0700384
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000385 final List<DeviceProfile> localSupportedProfiles = new ArrayList<>();
Sunny Goyal19ff7282021-04-22 10:12:54 -0700386 defaultWallpaperSize = new Point(displayInfo.currentSize);
387 for (WindowBounds bounds : displayInfo.supportedBounds) {
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000388 localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo)
Alex Chau1c883d82021-12-01 18:43:10 +0000389 .setUseTwoPanels(deviceType == TYPE_MULTI_DISPLAY)
Alex Chau6ed408f2022-03-04 12:58:05 +0000390 .setWindowBounds(bounds)
391 .build());
Sunny Goyalc6205602015-05-21 20:46:33 -0700392
Sunny Goyal19ff7282021-04-22 10:12:54 -0700393 // Wallpaper size should be the maximum of the all possible sizes Launcher expects
394 int displayWidth = bounds.bounds.width();
395 int displayHeight = bounds.bounds.height();
396 defaultWallpaperSize.y = Math.max(defaultWallpaperSize.y, displayHeight);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700397
Sunny Goyal19ff7282021-04-22 10:12:54 -0700398 // We need to ensure that there is enough extra space in the wallpaper
399 // for the intended parallax effects
400 float parallaxFactor =
Sunny Goyal89a89d62022-05-09 19:25:15 +0000401 dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.densityDpi) < 720
Sunny Goyal19ff7282021-04-22 10:12:54 -0700402 ? 2
403 : wallpaperTravelToScreenWidthRatio(displayWidth, displayHeight);
404 defaultWallpaperSize.x =
405 Math.max(defaultWallpaperSize.x, Math.round(parallaxFactor * displayWidth));
Sunny Goyal6f866092016-03-17 17:04:15 -0700406 }
Pinyao Ting9cd63c92021-06-16 17:51:39 +0000407 supportedProfiles = Collections.unmodifiableList(localSupportedProfiles);
Sunny Goyal58fa4b62019-03-22 16:23:25 -0700408
409 ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
410 defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
Adam Cohen2e6da152015-05-06 11:42:25 -0700411 }
412
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700413 public void addOnChangeListener(OnIDPChangeListener listener) {
414 mChangeListeners.add(listener);
415 }
416
Hyunyoung Songb4d1ca42019-01-08 17:15:16 -0800417 public void removeOnChangeListener(OnIDPChangeListener listener) {
418 mChangeListeners.remove(listener);
419 }
420
Hyunyoung Songc55a3502018-12-04 15:43:16 -0800421
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800422 public void setCurrentGrid(Context context, String gridName) {
423 Context appContext = context.getApplicationContext();
424 Utilities.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply();
Sunny Goyal6fe3eec2019-08-15 14:53:41 -0700425 MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext));
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800426 }
427
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700428 private Object[] toModelState() {
sfufa@google.comde013292021-09-21 18:22:44 -0700429 return new Object[]{
Alex Chau9fee3fd2021-12-01 18:43:10 +0000430 numColumns, numRows, numSearchContainerColumns, numDatabaseHotseatIcons,
431 iconBitmapSize, fillResIconDpi, numDatabaseAllAppsColumns, dbFile};
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700432 }
433
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700434 private void onConfigChanged(Context context) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700435 Object[] oldState = toModelState();
436
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700437 // Re-init grid
Tracy Zhouc6060e62020-04-27 13:05:34 -0700438 String gridName = getCurrentGridName(context);
Jon Miranda6f7e9702019-09-16 14:44:14 -0700439 initGrid(context, gridName);
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700440
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700441 boolean modelPropsChanged = !Arrays.equals(oldState, toModelState());
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700442 for (OnIDPChangeListener listener : mChangeListeners) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700443 listener.onIdpChanged(modelPropsChanged);
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700444 }
445 }
446
Alex Chau1c883d82021-12-01 18:43:10 +0000447 private static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context,
448 String gridName, @DeviceType int deviceType, boolean allowDisabledGrid) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800449 ArrayList<DisplayOption> profiles = new ArrayList<>();
Thales Lima1de4d552021-10-13 16:13:25 +0100450
Alex Chau1c883d82021-12-01 18:43:10 +0000451 try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
Sunny Goyal819e1932016-07-07 16:43:58 -0700452 final int depth = parser.getDepth();
453 int type;
Sunny Goyal819e1932016-07-07 16:43:58 -0700454 while (((type = parser.next()) != XmlPullParser.END_TAG ||
455 parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800456 if ((type == XmlPullParser.START_TAG)
457 && GridOption.TAG_NAME.equals(parser.getName())) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800458
Alex Chau1c883d82021-12-01 18:43:10 +0000459 GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser),
460 deviceType);
Alex Chau238aaee2021-10-06 16:15:24 +0100461 if (gridOption.isEnabled || allowDisabledGrid) {
Thales Lima7ec83822021-08-05 13:32:10 +0100462 final int displayDepth = parser.getDepth();
463 while (((type = parser.next()) != XmlPullParser.END_TAG
464 || parser.getDepth() > displayDepth)
465 && type != XmlPullParser.END_DOCUMENT) {
466 if ((type == XmlPullParser.START_TAG) && "display-option".equals(
467 parser.getName())) {
468 profiles.add(new DisplayOption(gridOption, context,
Thales Lima1de4d552021-10-13 16:13:25 +0100469 Xml.asAttributeSet(parser)));
Thales Lima7ec83822021-08-05 13:32:10 +0100470 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800471 }
472 }
Sunny Goyal819e1932016-07-07 16:43:58 -0700473 }
474 }
sfufa@google.comde013292021-09-21 18:22:44 -0700475 } catch (IOException | XmlPullParserException e) {
Sunny Goyal819e1932016-07-07 16:43:58 -0700476 throw new RuntimeException(e);
477 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800478
Sunny Goyalae190ff2020-04-14 00:19:01 +0000479 ArrayList<DisplayOption> filteredProfiles = new ArrayList<>();
Sunny Goyal415f1732018-11-29 10:33:47 -0800480 if (!TextUtils.isEmpty(gridName)) {
481 for (DisplayOption option : profiles) {
Alex Chau238aaee2021-10-06 16:15:24 +0100482 if (gridName.equals(option.grid.name)
483 && (option.grid.isEnabled || allowDisabledGrid)) {
Sunny Goyalae190ff2020-04-14 00:19:01 +0000484 filteredProfiles.add(option);
Sunny Goyal415f1732018-11-29 10:33:47 -0800485 }
486 }
487 }
Sunny Goyalae190ff2020-04-14 00:19:01 +0000488 if (filteredProfiles.isEmpty()) {
489 // No grid found, use the default options
490 for (DisplayOption option : profiles) {
491 if (option.canBeDefault) {
492 filteredProfiles.add(option);
493 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800494 }
495 }
Sunny Goyalae190ff2020-04-14 00:19:01 +0000496 if (filteredProfiles.isEmpty()) {
497 throw new RuntimeException("No display option with canBeDefault=true");
498 }
499 return filteredProfiles;
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700500 }
501
Thales Lima7ec83822021-08-05 13:32:10 +0100502 /**
503 * @return all the grid options that can be shown on the device
504 */
505 public List<GridOption> parseAllGridOptions(Context context) {
506 List<GridOption> result = new ArrayList<>();
Thales Lima1de4d552021-10-13 16:13:25 +0100507
Alex Chau1c883d82021-12-01 18:43:10 +0000508 try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
Thales Lima7ec83822021-08-05 13:32:10 +0100509 final int depth = parser.getDepth();
510 int type;
511 while (((type = parser.next()) != XmlPullParser.END_TAG
512 || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
513 if ((type == XmlPullParser.START_TAG)
514 && GridOption.TAG_NAME.equals(parser.getName())) {
515 GridOption option =
Alex Chau1c883d82021-12-01 18:43:10 +0000516 new GridOption(context, Xml.asAttributeSet(parser), deviceType);
Thales Lima7ec83822021-08-05 13:32:10 +0100517 if (option.isEnabled) {
518 result.add(option);
519 }
520 }
521 }
522 } catch (IOException | XmlPullParserException e) {
523 Log.e(TAG, "Error parsing device profile", e);
524 return Collections.emptyList();
525 }
526 return result;
527 }
528
Sunny Goyal53d7ee42015-05-22 12:25:45 -0700529 private int getLauncherIconDensity(int requiredSize) {
530 // Densities typically defined by an app.
sfufa@google.comde013292021-09-21 18:22:44 -0700531 int[] densityBuckets = new int[]{
Sunny Goyal53d7ee42015-05-22 12:25:45 -0700532 DisplayMetrics.DENSITY_LOW,
533 DisplayMetrics.DENSITY_MEDIUM,
534 DisplayMetrics.DENSITY_TV,
535 DisplayMetrics.DENSITY_HIGH,
536 DisplayMetrics.DENSITY_XHIGH,
537 DisplayMetrics.DENSITY_XXHIGH,
538 DisplayMetrics.DENSITY_XXXHIGH
539 };
540
541 int density = DisplayMetrics.DENSITY_XXXHIGH;
542 for (int i = densityBuckets.length - 1; i >= 0; i--) {
543 float expectedSize = ICON_SIZE_DEFINED_IN_APP_DP * densityBuckets[i]
544 / DisplayMetrics.DENSITY_DEFAULT;
545 if (expectedSize >= requiredSize) {
546 density = densityBuckets[i];
547 }
548 }
549
550 return density;
551 }
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700552
Adam Cohen2e6da152015-05-06 11:42:25 -0700553 /**
554 * Apply any Partner customization grid overrides.
555 *
556 * Currently we support: all apps row / column count.
557 */
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700558 private void applyPartnerDeviceProfileOverrides(Context context, DisplayMetrics dm) {
559 Partner p = Partner.get(context.getPackageManager());
Adam Cohen2e6da152015-05-06 11:42:25 -0700560 if (p != null) {
561 p.applyInvariantDeviceProfileOverrides(this, dm);
562 }
563 }
564
Sunny Goyal415f1732018-11-29 10:33:47 -0800565 private static float dist(float x0, float y0, float x1, float y1) {
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700566 return (float) Math.hypot(x1 - x0, y1 - y0);
Adam Cohen2e6da152015-05-06 11:42:25 -0700567 }
568
Sunny Goyal19ff7282021-04-22 10:12:54 -0700569 private static DisplayOption invDistWeightedInterpolate(
Alex Chau1c883d82021-12-01 18:43:10 +0000570 Info displayInfo, ArrayList<DisplayOption> points, @DeviceType int deviceType) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700571 int minWidthPx = Integer.MAX_VALUE;
572 int minHeightPx = Integer.MAX_VALUE;
573 for (WindowBounds bounds : displayInfo.supportedBounds) {
574 boolean isTablet = displayInfo.isTablet(bounds);
Alex Chau1c883d82021-12-01 18:43:10 +0000575 if (isTablet && deviceType == TYPE_MULTI_DISPLAY) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700576 // For split displays, take half width per page
577 minWidthPx = Math.min(minWidthPx, bounds.availableSize.x / 2);
578 minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700579
Sunny Goyal19ff7282021-04-22 10:12:54 -0700580 } else if (!isTablet && bounds.isLandscape()) {
581 // We will use transposed layout in this case
582 minWidthPx = Math.min(minWidthPx, bounds.availableSize.y);
583 minHeightPx = Math.min(minHeightPx, bounds.availableSize.x);
584 } else {
585 minWidthPx = Math.min(minWidthPx, bounds.availableSize.x);
586 minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
587 }
588 }
589
Sunny Goyal89a89d62022-05-09 19:25:15 +0000590 float width = dpiFromPx(minWidthPx, displayInfo.densityDpi);
591 float height = dpiFromPx(minHeightPx, displayInfo.densityDpi);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700592
593 // Sort the profiles based on the closeness to the device size
594 Collections.sort(points, (a, b) ->
595 Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
596 dist(width, height, b.minWidthDps, b.minHeightDps)));
597
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700598 DisplayOption closestPoint = points.get(0);
599 GridOption closestOption = closestPoint.grid;
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700600 float weights = 0;
601
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700602 if (dist(width, height, closestPoint.minWidthDps, closestPoint.minHeightDps) == 0) {
603 return closestPoint;
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700604 }
605
606 DisplayOption out = new DisplayOption(closestOption);
607 for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700608 DisplayOption p = points.get(i);
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700609 float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER);
610 weights += w;
611 out.add(new DisplayOption().add(p).multiply(w));
612 }
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700613 out.multiply(1.0f / weights);
614
Thales Lima6e0005a2021-10-27 15:53:41 +0100615 // Since the bitmaps are persisted, ensure that all bitmap sizes are not larger than
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700616 // predefined size to avoid cache invalidation
Thales Lima6e0005a2021-10-27 15:53:41 +0100617 for (int i = INDEX_DEFAULT; i < COUNT_SIZES; i++) {
618 out.iconSizes[i] = Math.min(out.iconSizes[i], closestPoint.iconSizes[i]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700619 }
620
621 return out;
Sunny Goyal0e7a3382020-04-13 17:15:05 -0700622 }
623
Sunny Goyal27835952017-01-13 12:15:53 -0800624 public DeviceProfile getDeviceProfile(Context context) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700625 Resources res = context.getResources();
626 Configuration config = context.getResources().getConfiguration();
627
Sunny Goyal3e9a29c2021-09-07 15:53:09 -0400628 float screenWidth = config.screenWidthDp * res.getDisplayMetrics().density;
629 float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
Alex Chaud3e8cc42022-05-03 17:45:34 +0100630 int rotation = WindowManagerProxy.INSTANCE.get(context).getRotation(context);
631
632 if (Utilities.IS_DEBUG_DEVICE) {
633 StringWriter stringWriter = new StringWriter();
634 PrintWriter printWriter = new PrintWriter(stringWriter);
635 DisplayController.INSTANCE.get(context).dump(printWriter);
636 printWriter.flush();
637 Log.d("b/231312158", "getDeviceProfile -"
638 + "\nconfig: " + config
639 + "\ndisplayMetrics: " + res.getDisplayMetrics()
640 + "\nrotation: " + rotation
641 + "\n" + stringWriter.toString(),
642 new Exception());
643 }
644 return getBestMatch(screenWidth, screenHeight, rotation);
Sunny Goyal3e9a29c2021-09-07 15:53:09 -0400645 }
Sunny Goyal19ff7282021-04-22 10:12:54 -0700646
Sunny Goyal187b16c2022-03-01 16:53:23 -0800647 /**
648 * Returns the device profile matching the provided screen configuration
649 */
650 public DeviceProfile getBestMatch(float screenWidth, float screenHeight, int rotation) {
Sunny Goyal19ff7282021-04-22 10:12:54 -0700651 DeviceProfile bestMatch = supportedProfiles.get(0);
652 float minDiff = Float.MAX_VALUE;
653
654 for (DeviceProfile profile : supportedProfiles) {
Sunny Goyal3e9a29c2021-09-07 15:53:09 -0400655 float diff = Math.abs(profile.widthPx - screenWidth)
656 + Math.abs(profile.heightPx - screenHeight);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700657 if (diff < minDiff) {
658 minDiff = diff;
659 bestMatch = profile;
Sunny Goyal187b16c2022-03-01 16:53:23 -0800660 } else if (diff == minDiff && profile.rotationHint == rotation) {
661 bestMatch = profile;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700662 }
663 }
664 return bestMatch;
Sunny Goyal27835952017-01-13 12:15:53 -0800665 }
666
Sunny Goyal415f1732018-11-29 10:33:47 -0800667 private static float weight(float x0, float y0, float x1, float y1, float pow) {
Hyunyoung Song35c3c7f2015-05-28 15:33:40 -0700668 float d = dist(x0, y0, x1, y1);
669 if (Float.compare(d, 0f) == 0) {
670 return Float.POSITIVE_INFINITY;
671 }
672 return (float) (WEIGHT_EFFICIENT / Math.pow(d, pow));
673 }
Sunny Goyal6f866092016-03-17 17:04:15 -0700674
675 /**
676 * As a ratio of screen height, the total distance we want the parallax effect to span
677 * horizontally
678 */
679 private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
680 float aspectRatio = width / (float) height;
681
682 // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
683 // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
684 // We will use these two data points to extrapolate how much the wallpaper parallax effect
685 // to span (ie travel) at any aspect ratio:
686
sfufa@google.comde013292021-09-21 18:22:44 -0700687 final float ASPECT_RATIO_LANDSCAPE = 16 / 10f;
688 final float ASPECT_RATIO_PORTRAIT = 10 / 16f;
Sunny Goyal6f866092016-03-17 17:04:15 -0700689 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
690 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
691
692 // To find out the desired width at different aspect ratios, we use the following two
693 // formulas, where the coefficient on x is the aspect ratio (width/height):
694 // (16/10)x + y = 1.5
695 // (10/16)x + y = 1.2
696 // We solve for x and y and end up with a final formula:
697 final float x =
sfufa@google.comde013292021-09-21 18:22:44 -0700698 (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE
699 - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
Sunny Goyal6f866092016-03-17 17:04:15 -0700700 (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
701 final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
702 return x * aspectRatio + y;
703 }
704
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700705 public interface OnIDPChangeListener {
706
Sunny Goyalb47172b2021-05-03 19:59:51 -0700707 /**
708 * Called when the device provide changes
709 */
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700710 void onIdpChanged(boolean modelPropertiesChanged);
Sunny Goyal87dc48b2018-10-12 11:42:33 -0700711 }
Sunny Goyal415f1732018-11-29 10:33:47 -0800712
713
Sunny Goyaleff44f32019-01-09 17:29:49 -0800714 public static final class GridOption {
Sunny Goyal415f1732018-11-29 10:33:47 -0800715
Sunny Goyal7d892ff2019-01-11 15:08:44 -0800716 public static final String TAG_NAME = "grid-option";
717
Alex Chau1c883d82021-12-01 18:43:10 +0000718 private static final int DEVICE_CATEGORY_PHONE = 1 << 0;
719 private static final int DEVICE_CATEGORY_TABLET = 1 << 1;
720 private static final int DEVICE_CATEGORY_MULTI_DISPLAY = 1 << 2;
721 private static final int DEVICE_CATEGORY_ALL =
722 DEVICE_CATEGORY_PHONE | DEVICE_CATEGORY_TABLET | DEVICE_CATEGORY_MULTI_DISPLAY;
723
Sunny Goyaleff44f32019-01-09 17:29:49 -0800724 public final String name;
725 public final int numRows;
726 public final int numColumns;
Alex Chau9fee3fd2021-12-01 18:43:10 +0000727 public final int numSearchContainerColumns;
Thales Lima7ec83822021-08-05 13:32:10 +0100728 public final boolean isEnabled;
Sunny Goyal415f1732018-11-29 10:33:47 -0800729
730 private final int numFolderRows;
731 private final int numFolderColumns;
732
Sunny Goyal19ff7282021-04-22 10:12:54 -0700733 private final int numAllAppsColumns;
734 private final int numDatabaseAllAppsColumns;
735 private final int numHotseatIcons;
Alex Chau6ed408f2022-03-04 12:58:05 +0000736 private final int numShrunkenHotseatIcons;
Tony Wickhamb87f3cd2021-04-07 15:02:37 -0700737 private final int numDatabaseHotseatIcons;
Sunny Goyal415f1732018-11-29 10:33:47 -0800738
Tracy Zhou7df93d22020-01-27 13:44:06 -0800739 private final String dbFile;
Sunny Goyalae190ff2020-04-14 00:19:01 +0000740
Sunny Goyal415f1732018-11-29 10:33:47 -0800741 private final int defaultLayoutId;
742 private final int demoModeLayoutId;
743
Jon Mirandae126d722021-02-25 10:45:20 -0500744 private final boolean isScalable;
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400745 private final int devicePaddingId;
Jon Mirandae126d722021-02-25 10:45:20 -0500746
Sunny Goyal5bc18462019-01-07 15:13:39 -0800747 private final SparseArray<TypedValue> extraAttrs;
748
Alex Chau1c883d82021-12-01 18:43:10 +0000749 public GridOption(Context context, AttributeSet attrs, @DeviceType int deviceType) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800750 TypedArray a = context.obtainStyledAttributes(
751 attrs, R.styleable.GridDisplayOption);
752 name = a.getString(R.styleable.GridDisplayOption_name);
753 numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0);
754 numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0);
Alex Chau9fee3fd2021-12-01 18:43:10 +0000755 numSearchContainerColumns = a.getInt(
756 R.styleable.GridDisplayOption_numSearchContainerColumns, numColumns);
Sunny Goyal415f1732018-11-29 10:33:47 -0800757
Tracy Zhou7df93d22020-01-27 13:44:06 -0800758 dbFile = a.getString(R.styleable.GridDisplayOption_dbFile);
Alex Chau1c883d82021-12-01 18:43:10 +0000759 defaultLayoutId = a.getResourceId(deviceType == TYPE_MULTI_DISPLAY && a.hasValue(
Alex Chau1e448462021-08-13 21:48:35 +0100760 R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId)
761 ? R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId
762 : R.styleable.GridDisplayOption_defaultLayoutId, 0);
Sunny Goyal415f1732018-11-29 10:33:47 -0800763 demoModeLayoutId = a.getResourceId(
764 R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700765
766 numAllAppsColumns = a.getInt(
767 R.styleable.GridDisplayOption_numAllAppsColumns, numColumns);
768 numDatabaseAllAppsColumns = a.getInt(
769 R.styleable.GridDisplayOption_numExtendedAllAppsColumns, 2 * numAllAppsColumns);
770
771 numHotseatIcons = a.getInt(
Sunny Goyal415f1732018-11-29 10:33:47 -0800772 R.styleable.GridDisplayOption_numHotseatIcons, numColumns);
Alex Chau6ed408f2022-03-04 12:58:05 +0000773 numShrunkenHotseatIcons = a.getInt(
774 R.styleable.GridDisplayOption_numShrunkenHotseatIcons, numHotseatIcons / 2);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700775 numDatabaseHotseatIcons = a.getInt(
776 R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons);
777
Sunny Goyal415f1732018-11-29 10:33:47 -0800778 numFolderRows = a.getInt(
779 R.styleable.GridDisplayOption_numFolderRows, numRows);
780 numFolderColumns = a.getInt(
781 R.styleable.GridDisplayOption_numFolderColumns, numColumns);
Jon Miranda6f7e9702019-09-16 14:44:14 -0700782
Jon Mirandae126d722021-02-25 10:45:20 -0500783 isScalable = a.getBoolean(
784 R.styleable.GridDisplayOption_isScalable, false);
Jon Mirandac9e69fa2021-03-22 17:13:34 -0400785 devicePaddingId = a.getResourceId(
786 R.styleable.GridDisplayOption_devicePaddingId, 0);
Jon Mirandae126d722021-02-25 10:45:20 -0500787
Alex Chau1c883d82021-12-01 18:43:10 +0000788 int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
789 DEVICE_CATEGORY_ALL);
790 isEnabled = (deviceType == TYPE_PHONE
791 && ((deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE))
792 || (deviceType == TYPE_TABLET
793 && ((deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET))
794 || (deviceType == TYPE_MULTI_DISPLAY
795 && ((deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
796 == DEVICE_CATEGORY_MULTI_DISPLAY));
Thales Lima7ec83822021-08-05 13:32:10 +0100797
Sunny Goyal415f1732018-11-29 10:33:47 -0800798 a.recycle();
Sunny Goyal5bc18462019-01-07 15:13:39 -0800799 extraAttrs = Themes.createValueMap(context, attrs,
800 IntArray.wrap(R.styleable.GridDisplayOption));
Sunny Goyal415f1732018-11-29 10:33:47 -0800801 }
802 }
803
Sunny Goyal19ff7282021-04-22 10:12:54 -0700804 @VisibleForTesting
805 static final class DisplayOption {
Thales Lima12d0eff2022-03-25 17:06:11 +0000806 private static final int INLINE_QSB_FOR_PORTRAIT = 1 << 0;
807 private static final int INLINE_QSB_FOR_LANDSCAPE = 1 << 1;
808 private static final int INLINE_QSB_FOR_TWO_PANEL_PORTRAIT = 1 << 2;
809 private static final int INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE = 1 << 3;
810 private static final int DONT_INLINE_QSB = 0;
Sunny Goyal19ff7282021-04-22 10:12:54 -0700811
812 public final GridOption grid;
Sunny Goyal415f1732018-11-29 10:33:47 -0800813
Sunny Goyal415f1732018-11-29 10:33:47 -0800814 private final float minWidthDps;
815 private final float minHeightDps;
816 private final boolean canBeDefault;
Thales Lima12d0eff2022-03-25 17:06:11 +0000817 private final boolean[] inlineQsb = new boolean[COUNT_SIZES];
Sunny Goyal415f1732018-11-29 10:33:47 -0800818
Thales Lima83bedbf2021-10-05 17:47:39 +0100819 private final PointF[] minCellSize = new PointF[COUNT_SIZES];
Thales Lima78d00ad2021-09-30 11:29:06 +0100820
821 private float folderBorderSpace;
822 private final PointF[] borderSpaces = new PointF[COUNT_SIZES];
Thales Lima83bedbf2021-10-05 17:47:39 +0100823 private final float[] horizontalMargin = new float[COUNT_SIZES];
Thales Lima6e7f36c2022-01-04 12:14:11 +0000824 private final float[] hotseatBorderSpaces = new float[COUNT_SIZES];
Thales Limad90faab2021-09-21 17:18:47 +0100825
Thales Lima78d00ad2021-09-30 11:29:06 +0100826 private final float[] iconSizes = new float[COUNT_SIZES];
827 private final float[] textSizes = new float[COUNT_SIZES];
Sunny Goyal415f1732018-11-29 10:33:47 -0800828
Thales Limab7ef5692022-03-10 10:32:36 +0000829 private final PointF[] allAppsCellSize = new PointF[COUNT_SIZES];
Thales Limabb7d3882021-12-22 12:56:29 +0000830 private final float[] allAppsIconSizes = new float[COUNT_SIZES];
831 private final float[] allAppsIconTextSizes = new float[COUNT_SIZES];
832 private final PointF[] allAppsBorderSpaces = new PointF[COUNT_SIZES];
833
Thales Lima1de4d552021-10-13 16:13:25 +0100834 DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
Sunny Goyal415f1732018-11-29 10:33:47 -0800835 this.grid = grid;
836
Thales Lima1de4d552021-10-13 16:13:25 +0100837 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProfileDisplayOption);
Sunny Goyal415f1732018-11-29 10:33:47 -0800838
Sunny Goyal415f1732018-11-29 10:33:47 -0800839 minWidthDps = a.getFloat(R.styleable.ProfileDisplayOption_minWidthDps, 0);
840 minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0);
Sunny Goyal19ff7282021-04-22 10:12:54 -0700841
Thales Lima1de4d552021-10-13 16:13:25 +0100842 canBeDefault = a.getBoolean(R.styleable.ProfileDisplayOption_canBeDefault, false);
Sunny Goyal415f1732018-11-29 10:33:47 -0800843
Thales Lima12d0eff2022-03-25 17:06:11 +0000844 int inlineForRotation = a.getInt(R.styleable.ProfileDisplayOption_inlineQsb,
845 DONT_INLINE_QSB);
846 inlineQsb[INDEX_DEFAULT] =
847 (inlineForRotation & INLINE_QSB_FOR_PORTRAIT) == INLINE_QSB_FOR_PORTRAIT;
848 inlineQsb[INDEX_LANDSCAPE] =
849 (inlineForRotation & INLINE_QSB_FOR_LANDSCAPE) == INLINE_QSB_FOR_LANDSCAPE;
850 inlineQsb[INDEX_TWO_PANEL_PORTRAIT] =
851 (inlineForRotation & INLINE_QSB_FOR_TWO_PANEL_PORTRAIT)
852 == INLINE_QSB_FOR_TWO_PANEL_PORTRAIT;
853 inlineQsb[INDEX_TWO_PANEL_LANDSCAPE] =
854 (inlineForRotation & INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE)
855 == INLINE_QSB_FOR_TWO_PANEL_LANDSCAPE;
856
Thales Lima83bedbf2021-10-05 17:47:39 +0100857 float x;
858 float y;
859
Thales Lima85c942f2021-12-31 13:04:20 +0000860 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidth, 0);
861 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeight, 0);
Thales Lima83bedbf2021-10-05 17:47:39 +0100862 minCellSize[INDEX_DEFAULT] = new PointF(x, y);
Thales Limadd027342022-01-07 12:54:37 +0000863
864 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthLandscape,
865 minCellSize[INDEX_DEFAULT].x);
866 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightLandscape,
867 minCellSize[INDEX_DEFAULT].y);
Thales Lima83bedbf2021-10-05 17:47:39 +0100868 minCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
Thales Lima83bedbf2021-10-05 17:47:39 +0100869
Thales Lima85c942f2021-12-31 13:04:20 +0000870 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthTwoPanelPortrait,
Thales Lima83bedbf2021-10-05 17:47:39 +0100871 minCellSize[INDEX_DEFAULT].x);
Thales Lima85c942f2021-12-31 13:04:20 +0000872 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightTwoPanelPortrait,
Thales Lima83bedbf2021-10-05 17:47:39 +0100873 minCellSize[INDEX_DEFAULT].y);
874 minCellSize[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
875
Thales Lima85c942f2021-12-31 13:04:20 +0000876 x = a.getFloat(R.styleable.ProfileDisplayOption_minCellWidthTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100877 minCellSize[INDEX_DEFAULT].x);
Thales Lima85c942f2021-12-31 13:04:20 +0000878 y = a.getFloat(R.styleable.ProfileDisplayOption_minCellHeightTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100879 minCellSize[INDEX_DEFAULT].y);
880 minCellSize[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
Thales Lima78d00ad2021-09-30 11:29:06 +0100881
Thales Lima85c942f2021-12-31 13:04:20 +0000882 float borderSpace = a.getFloat(R.styleable.ProfileDisplayOption_borderSpace, 0);
Thales Lima44cc3a22022-03-18 14:28:24 +0000883 float borderSpaceLandscape = a.getFloat(
884 R.styleable.ProfileDisplayOption_borderSpaceLandscape, borderSpace);
Thales Lima85c942f2021-12-31 13:04:20 +0000885 float borderSpaceTwoPanelPortrait = a.getFloat(
886 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelPortrait, borderSpace);
887 float borderSpaceTwoPanelLandscape = a.getFloat(
888 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelLandscape, borderSpace);
Thales Lima78d00ad2021-09-30 11:29:06 +0100889
Thales Lima85c942f2021-12-31 13:04:20 +0000890 x = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceHorizontal, borderSpace);
891 y = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceVertical, borderSpace);
Thales Lima78d00ad2021-09-30 11:29:06 +0100892 borderSpaces[INDEX_DEFAULT] = new PointF(x, y);
Thales Lima44cc3a22022-03-18 14:28:24 +0000893
894 x = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceLandscapeHorizontal,
895 borderSpaceLandscape);
896 y = a.getFloat(R.styleable.ProfileDisplayOption_borderSpaceLandscapeVertical,
897 borderSpaceLandscape);
Thales Lima78d00ad2021-09-30 11:29:06 +0100898 borderSpaces[INDEX_LANDSCAPE] = new PointF(x, y);
899
900 x = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000901 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelPortraitHorizontal,
902 borderSpaceTwoPanelPortrait);
Thales Lima78d00ad2021-09-30 11:29:06 +0100903 y = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000904 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelPortraitVertical,
905 borderSpaceTwoPanelPortrait);
Thales Lima78d00ad2021-09-30 11:29:06 +0100906 borderSpaces[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
907
908 x = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000909 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelLandscapeHorizontal,
910 borderSpaceTwoPanelLandscape);
Thales Lima78d00ad2021-09-30 11:29:06 +0100911 y = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +0000912 R.styleable.ProfileDisplayOption_borderSpaceTwoPanelLandscapeVertical,
913 borderSpaceTwoPanelLandscape);
Thales Lima78d00ad2021-09-30 11:29:06 +0100914 borderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
915
Thales Limabb7d3882021-12-22 12:56:29 +0000916 folderBorderSpace = borderSpace;
917
Thales Limab7ef5692022-03-10 10:32:36 +0000918 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidth,
919 minCellSize[INDEX_DEFAULT].x);
920 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeight,
921 minCellSize[INDEX_DEFAULT].y);
922 allAppsCellSize[INDEX_DEFAULT] = new PointF(x, y);
923
924 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthLandscape,
925 allAppsCellSize[INDEX_DEFAULT].x);
926 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightLandscape,
927 allAppsCellSize[INDEX_DEFAULT].y);
928 allAppsCellSize[INDEX_LANDSCAPE] = new PointF(x, y);
929
930 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelPortrait,
931 allAppsCellSize[INDEX_DEFAULT].x);
932 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelPortrait,
933 allAppsCellSize[INDEX_DEFAULT].y);
934 allAppsCellSize[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
935
936 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidthTwoPanelLandscape,
937 allAppsCellSize[INDEX_DEFAULT].x);
938 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeightTwoPanelLandscape,
939 allAppsCellSize[INDEX_DEFAULT].y);
940 allAppsCellSize[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
941
Thales Lima080d8902022-03-28 15:30:29 +0100942 float allAppsBorderSpace = a.getFloat(
943 R.styleable.ProfileDisplayOption_allAppsBorderSpace, borderSpace);
944 float allAppsBorderSpaceLandscape = a.getFloat(
945 R.styleable.ProfileDisplayOption_allAppsBorderSpaceLandscape,
946 allAppsBorderSpace);
947 float allAppsBorderSpaceTwoPanelPortrait = a.getFloat(
Thales Limabb7d3882021-12-22 12:56:29 +0000948 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelPortrait,
Thales Lima080d8902022-03-28 15:30:29 +0100949 allAppsBorderSpace);
950 float allAppsBorderSpaceTwoPanelLandscape = a.getFloat(
Thales Limabb7d3882021-12-22 12:56:29 +0000951 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelLandscape,
Thales Lima080d8902022-03-28 15:30:29 +0100952 allAppsBorderSpace);
953
954 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceHorizontal,
955 allAppsBorderSpace);
956 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceVertical,
957 allAppsBorderSpace);
958 allAppsBorderSpaces[INDEX_DEFAULT] = new PointF(x, y);
959
960 x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceLandscapeHorizontal,
961 allAppsBorderSpaceLandscape);
962 y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsBorderSpaceLandscapeVertical,
963 allAppsBorderSpaceLandscape);
964 allAppsBorderSpaces[INDEX_LANDSCAPE] = new PointF(x, y);
965
966 x = a.getFloat(
967 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelPortraitHorizontal,
968 allAppsBorderSpaceTwoPanelPortrait);
969 y = a.getFloat(
970 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelPortraitVertical,
971 allAppsBorderSpaceTwoPanelPortrait);
972 allAppsBorderSpaces[INDEX_TWO_PANEL_PORTRAIT] = new PointF(x, y);
973
974 x = a.getFloat(
975 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelLandscapeHorizontal,
976 allAppsBorderSpaceTwoPanelLandscape);
977 y = a.getFloat(
978 R.styleable.ProfileDisplayOption_allAppsBorderSpaceTwoPanelLandscapeVertical,
979 allAppsBorderSpaceTwoPanelLandscape);
Thales Limabb7d3882021-12-22 12:56:29 +0000980 allAppsBorderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y);
Jon Mirandae126d722021-02-25 10:45:20 -0500981
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700982 iconSizes[INDEX_DEFAULT] =
983 a.getFloat(R.styleable.ProfileDisplayOption_iconImageSize, 0);
984 iconSizes[INDEX_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +0000985 a.getFloat(R.styleable.ProfileDisplayOption_iconSizeLandscape,
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700986 iconSizes[INDEX_DEFAULT]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700987 iconSizes[INDEX_TWO_PANEL_PORTRAIT] =
Thales Lima85c942f2021-12-31 13:04:20 +0000988 a.getFloat(R.styleable.ProfileDisplayOption_iconSizeTwoPanelPortrait,
Sunny Goyal6e6f7992021-08-24 16:23:29 -0700989 iconSizes[INDEX_DEFAULT]);
990 iconSizes[INDEX_TWO_PANEL_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +0000991 a.getFloat(R.styleable.ProfileDisplayOption_iconSizeTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +0100992 iconSizes[INDEX_DEFAULT]);
Jon Miranda6f7e9702019-09-16 14:44:14 -0700993
Thales Limabb7d3882021-12-22 12:56:29 +0000994 allAppsIconSizes[INDEX_DEFAULT] = a.getFloat(
995 R.styleable.ProfileDisplayOption_allAppsIconSize, iconSizes[INDEX_DEFAULT]);
996 allAppsIconSizes[INDEX_LANDSCAPE] = allAppsIconSizes[INDEX_DEFAULT];
997 allAppsIconSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
998 R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelPortrait,
999 allAppsIconSizes[INDEX_DEFAULT]);
1000 allAppsIconSizes[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
1001 R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelLandscape,
1002 allAppsIconSizes[INDEX_DEFAULT]);
1003
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001004 textSizes[INDEX_DEFAULT] =
1005 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
1006 textSizes[INDEX_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +00001007 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSizeLandscape,
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001008 textSizes[INDEX_DEFAULT]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001009 textSizes[INDEX_TWO_PANEL_PORTRAIT] =
Thales Lima85c942f2021-12-31 13:04:20 +00001010 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSizeTwoPanelPortrait,
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001011 textSizes[INDEX_DEFAULT]);
1012 textSizes[INDEX_TWO_PANEL_LANDSCAPE] =
Thales Lima85c942f2021-12-31 13:04:20 +00001013 a.getFloat(R.styleable.ProfileDisplayOption_iconTextSizeTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +01001014 textSizes[INDEX_DEFAULT]);
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001015
Thales Limabb7d3882021-12-22 12:56:29 +00001016 allAppsIconTextSizes[INDEX_DEFAULT] = a.getFloat(
1017 R.styleable.ProfileDisplayOption_allAppsIconTextSize, textSizes[INDEX_DEFAULT]);
1018 allAppsIconTextSizes[INDEX_LANDSCAPE] = allAppsIconTextSizes[INDEX_DEFAULT];
1019 allAppsIconTextSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
1020 R.styleable.ProfileDisplayOption_allAppsIconTextSizeTwoPanelPortrait,
1021 allAppsIconTextSizes[INDEX_DEFAULT]);
1022 allAppsIconTextSizes[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
1023 R.styleable.ProfileDisplayOption_allAppsIconTextSizeTwoPanelLandscape,
1024 allAppsIconTextSizes[INDEX_DEFAULT]);
1025
Thales Lima83bedbf2021-10-05 17:47:39 +01001026 horizontalMargin[INDEX_DEFAULT] = a.getFloat(
1027 R.styleable.ProfileDisplayOption_horizontalMargin, 0);
Thales Limadd027342022-01-07 12:54:37 +00001028 horizontalMargin[INDEX_LANDSCAPE] = a.getFloat(
1029 R.styleable.ProfileDisplayOption_horizontalMarginLandscape,
1030 horizontalMargin[INDEX_DEFAULT]);
Thales Lima83bedbf2021-10-05 17:47:39 +01001031 horizontalMargin[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +00001032 R.styleable.ProfileDisplayOption_horizontalMarginTwoPanelLandscape,
Thales Lima83bedbf2021-10-05 17:47:39 +01001033 horizontalMargin[INDEX_DEFAULT]);
1034 horizontalMargin[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
Thales Lima85c942f2021-12-31 13:04:20 +00001035 R.styleable.ProfileDisplayOption_horizontalMarginTwoPanelPortrait,
Thales Lima83bedbf2021-10-05 17:47:39 +01001036 horizontalMargin[INDEX_DEFAULT]);
Thales Limad90faab2021-09-21 17:18:47 +01001037
Thales Lima6e7f36c2022-01-04 12:14:11 +00001038 hotseatBorderSpaces[INDEX_DEFAULT] = a.getFloat(
1039 R.styleable.ProfileDisplayOption_hotseatBorderSpace, borderSpace);
Thales Limadd027342022-01-07 12:54:37 +00001040 hotseatBorderSpaces[INDEX_LANDSCAPE] = a.getFloat(
1041 R.styleable.ProfileDisplayOption_hotseatBorderSpaceLandscape,
1042 hotseatBorderSpaces[INDEX_DEFAULT]);
Thales Lima6e7f36c2022-01-04 12:14:11 +00001043 hotseatBorderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat(
1044 R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelLandscape,
1045 hotseatBorderSpaces[INDEX_DEFAULT]);
1046 hotseatBorderSpaces[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
1047 R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelPortrait,
1048 hotseatBorderSpaces[INDEX_DEFAULT]);
1049
Sunny Goyal415f1732018-11-29 10:33:47 -08001050 a.recycle();
1051 }
1052
1053 DisplayOption() {
Sunny Goyal0e7a3382020-04-13 17:15:05 -07001054 this(null);
1055 }
1056
1057 DisplayOption(GridOption grid) {
1058 this.grid = grid;
Sunny Goyal415f1732018-11-29 10:33:47 -08001059 minWidthDps = 0;
1060 minHeightDps = 0;
1061 canBeDefault = false;
Thales Lima78d00ad2021-09-30 11:29:06 +01001062 for (int i = 0; i < COUNT_SIZES; i++) {
1063 iconSizes[i] = 0;
1064 textSizes[i] = 0;
1065 borderSpaces[i] = new PointF();
Thales Lima83bedbf2021-10-05 17:47:39 +01001066 minCellSize[i] = new PointF();
Thales Limab7ef5692022-03-10 10:32:36 +00001067 allAppsCellSize[i] = new PointF();
Thales Limabb7d3882021-12-22 12:56:29 +00001068 allAppsIconSizes[i] = 0;
1069 allAppsIconTextSizes[i] = 0;
1070 allAppsBorderSpaces[i] = new PointF();
Thales Lima12d0eff2022-03-25 17:06:11 +00001071 inlineQsb[i] = false;
Thales Lima78d00ad2021-09-30 11:29:06 +01001072 }
Sunny Goyal415f1732018-11-29 10:33:47 -08001073 }
1074
1075 private DisplayOption multiply(float w) {
Thales Lima78d00ad2021-09-30 11:29:06 +01001076 for (int i = 0; i < COUNT_SIZES; i++) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001077 iconSizes[i] *= w;
1078 textSizes[i] *= w;
Thales Lima83bedbf2021-10-05 17:47:39 +01001079 borderSpaces[i].x *= w;
1080 borderSpaces[i].y *= w;
1081 minCellSize[i].x *= w;
1082 minCellSize[i].y *= w;
1083 horizontalMargin[i] *= w;
Thales Lima6e7f36c2022-01-04 12:14:11 +00001084 hotseatBorderSpaces[i] *= w;
Thales Limab7ef5692022-03-10 10:32:36 +00001085 allAppsCellSize[i].x *= w;
1086 allAppsCellSize[i].y *= w;
Thales Limabb7d3882021-12-22 12:56:29 +00001087 allAppsIconSizes[i] *= w;
1088 allAppsIconTextSizes[i] *= w;
1089 allAppsBorderSpaces[i].x *= w;
1090 allAppsBorderSpaces[i].y *= w;
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001091 }
Thales Lima78d00ad2021-09-30 11:29:06 +01001092
1093 folderBorderSpace *= w;
1094
Sunny Goyal415f1732018-11-29 10:33:47 -08001095 return this;
1096 }
1097
1098 private DisplayOption add(DisplayOption p) {
Thales Lima78d00ad2021-09-30 11:29:06 +01001099 for (int i = 0; i < COUNT_SIZES; i++) {
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001100 iconSizes[i] += p.iconSizes[i];
1101 textSizes[i] += p.textSizes[i];
Thales Lima83bedbf2021-10-05 17:47:39 +01001102 borderSpaces[i].x += p.borderSpaces[i].x;
1103 borderSpaces[i].y += p.borderSpaces[i].y;
1104 minCellSize[i].x += p.minCellSize[i].x;
1105 minCellSize[i].y += p.minCellSize[i].y;
1106 horizontalMargin[i] += p.horizontalMargin[i];
Thales Lima6e7f36c2022-01-04 12:14:11 +00001107 hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i];
Thales Limab7ef5692022-03-10 10:32:36 +00001108 allAppsCellSize[i].x += p.allAppsCellSize[i].x;
1109 allAppsCellSize[i].y += p.allAppsCellSize[i].y;
Thales Limabb7d3882021-12-22 12:56:29 +00001110 allAppsIconSizes[i] += p.allAppsIconSizes[i];
1111 allAppsIconTextSizes[i] += p.allAppsIconTextSizes[i];
1112 allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x;
1113 allAppsBorderSpaces[i].y += p.allAppsBorderSpaces[i].y;
Thales Lima12d0eff2022-03-25 17:06:11 +00001114 inlineQsb[i] |= p.inlineQsb[i];
Sunny Goyal6e6f7992021-08-24 16:23:29 -07001115 }
Thales Lima78d00ad2021-09-30 11:29:06 +01001116
1117 folderBorderSpace += p.folderBorderSpace;
1118
Sunny Goyal415f1732018-11-29 10:33:47 -08001119 return this;
1120 }
1121 }
Sunny Goyalae190ff2020-04-14 00:19:01 +00001122}