1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3;
18 
19 import android.database.sqlite.SQLiteDatabase;
20 import android.provider.BaseColumns;
21 
22 import androidx.annotation.NonNull;
23 
24 import com.android.launcher3.model.data.ItemInfo;
25 
26 import java.util.LinkedHashMap;
27 import java.util.stream.Collectors;
28 
29 /**
30  * Settings related utilities.
31  */
32 public class LauncherSettings {
33 
34     /**
35      * Types of animations.
36      */
37     public static final class Animation {
38         /**
39          * The default animation for a given view/item info type.
40          */
41         public static final int DEFAULT = 0;
42         /**
43          * An animation using the view's background.
44          */
45         public static final int VIEW_BACKGROUND = 1;
46         /**
47          * The default animation for a given view/item info type, but without the splash icon.
48          */
49         public static final int DEFAULT_NO_ICON = 2;
50     }
51 
52     /**
53      * Favorites.
54      */
55     public static final class Favorites implements BaseColumns {
56         /**
57          * The time of the last update to this row.
58          * <P>Type: INTEGER</P>
59          */
60         public static final String MODIFIED = "modified";
61 
62         /**
63          * Descriptive name of the gesture that can be displayed to the user.
64          * <P>Type: TEXT</P>
65          */
66         public static final String TITLE = "title";
67 
68         /**
69          * The Intent URL of the gesture, describing what it points to. This
70          * value is given to {@link android.content.Intent#parseUri(String, int)} to create
71          * an Intent that can be launched.
72          * <P>Type: TEXT</P>
73          */
74         public static final String INTENT = "intent";
75 
76         /**
77          * The type of the gesture
78          *
79          * <P>Type: INTEGER</P>
80          */
81         public static final String ITEM_TYPE = "itemType";
82 
83         /**
84          * The gesture is a package
85          */
86         public static final int ITEM_TYPE_NON_ACTIONABLE = -1;
87         /**
88          * The gesture is an application
89          */
90         public static final int ITEM_TYPE_APPLICATION = 0;
91 
92         /**
93          * The gesture is an application created shortcut
94          * @deprecated This is no longer supported. Use {@link #ITEM_TYPE_DEEP_SHORTCUT} instead
95          */
96         @Deprecated
97         public static final int ITEM_TYPE_SHORTCUT = 1;
98 
99         /**
100          * The favorite is a user created folder
101          */
102         public static final int ITEM_TYPE_FOLDER = 2;
103 
104         /**
105          * The favorite is a widget
106          */
107         public static final int ITEM_TYPE_APPWIDGET = 4;
108 
109         /**
110          * The favorite is a custom widget provided by the launcher
111          */
112         public static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
113 
114         /**
115          * The gesture is an application created deep shortcut
116          */
117         public static final int ITEM_TYPE_DEEP_SHORTCUT = 6;
118 
119         /**
120          * The favorite is an app pair for launching split screen
121          */
122         public static final int ITEM_TYPE_APP_PAIR = 10;
123 
124         // *** Below enum values are used for metrics purpose but not used in Favorites DB ***
125 
126         /**
127          * Type of the item is recents task.
128          */
129         public static final int ITEM_TYPE_TASK = 7;
130 
131         /**
132          * The item is QSB
133          */
134         public static final int ITEM_TYPE_QSB = 8;
135 
136         /**
137          * The favorite is a search action
138          */
139         public static final int ITEM_TYPE_SEARCH_ACTION = 9;
140 
141         /**
142          * Private space install app button.
143          */
144         public static final int ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON = 11;
145 
146         /**
147          * The custom icon bitmap.
148          * <P>Type: BLOB</P>
149          */
150         public static final String ICON = "icon";
151 
152         public static final String TABLE_NAME = "favorites";
153 
154         /**
155          * Backup table created when user hotseat is moved to workspace for hybrid hotseat
156          */
157         public static final String HYBRID_HOTSEAT_BACKUP_TABLE = "hotseat_restore_backup";
158 
159         /**
160          * Temporary table used specifically for multi-db grid migrations
161          */
162         public static final String TMP_TABLE = "favorites_tmp";
163 
164         /**
165          * The container holding the favorite
166          * <P>Type: INTEGER</P>
167          */
168         public static final String CONTAINER = "container";
169 
170         /**
171          * The icon is a resource identified by a package name and an integer id.
172          */
173         public static final int CONTAINER_DESKTOP = -100;
174         public static final int CONTAINER_HOTSEAT = -101;
175         public static final int CONTAINER_PREDICTION = -102;
176         public static final int CONTAINER_WIDGETS_PREDICTION = -111;
177         public static final int CONTAINER_HOTSEAT_PREDICTION = -103;
178         public static final int CONTAINER_ALL_APPS = -104;
179         public static final int CONTAINER_WIDGETS_TRAY = -105;
180         public static final int CONTAINER_BOTTOM_WIDGETS_TRAY = -112;
181         public static final int CONTAINER_PIN_WIDGETS = -113;
182         public static final int CONTAINER_WALLPAPERS = -114;
183         public static final int CONTAINER_SHORTCUTS = -107;
184         public static final int CONTAINER_SETTINGS = -108;
185         public static final int CONTAINER_TASKSWITCHER = -109;
186         public static final int CONTAINER_PRIVATESPACE = -110;
187 
188         // Represents any of the extended containers implemented in non-AOSP variants.
189         public static final int EXTENDED_CONTAINERS = -200;
190 
191         public static final int CONTAINER_UNKNOWN = -1;
192 
containerToString(int container)193         public static final String containerToString(int container) {
194             switch (container) {
195                 case CONTAINER_DESKTOP: return "desktop";
196                 case CONTAINER_HOTSEAT: return "hotseat";
197                 case CONTAINER_PREDICTION: return "prediction";
198                 case CONTAINER_ALL_APPS: return "all_apps";
199                 case CONTAINER_WIDGETS_TRAY: return "widgets_tray";
200                 case CONTAINER_SHORTCUTS: return "shortcuts";
201                 default: return String.valueOf(container);
202             }
203         }
204 
itemTypeToString(int type)205         public static final String itemTypeToString(int type) {
206             switch(type) {
207                 case ITEM_TYPE_APPLICATION: return "APP";
208                 case ITEM_TYPE_FOLDER: return "FOLDER";
209                 case ITEM_TYPE_APPWIDGET: return "WIDGET";
210                 case ITEM_TYPE_CUSTOM_APPWIDGET: return "CUSTOMWIDGET";
211                 case ITEM_TYPE_DEEP_SHORTCUT: return "DEEPSHORTCUT";
212                 case ITEM_TYPE_TASK: return "TASK";
213                 case ITEM_TYPE_QSB: return "QSB";
214                 case ITEM_TYPE_APP_PAIR: return "APP_PAIR";
215                 case ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON:
216                     return "PRIVATE_SPACE_INSTALL_APP_BUTTON";
217                 default: return String.valueOf(type);
218             }
219         }
220 
221         /**
222          * The screen holding the favorite (if container is CONTAINER_DESKTOP)
223          * <P>Type: INTEGER</P>
224          */
225         public static final String SCREEN = "screen";
226 
227         /**
228          * The X coordinate of the cell holding the favorite
229          * (if container is CONTAINER_HOTSEAT or CONTAINER_HOTSEAT)
230          * <P>Type: INTEGER</P>
231          */
232         public static final String CELLX = "cellX";
233 
234         /**
235          * The Y coordinate of the cell holding the favorite
236          * (if container is CONTAINER_DESKTOP)
237          * <P>Type: INTEGER</P>
238          */
239         public static final String CELLY = "cellY";
240 
241         /**
242          * The X span of the cell holding the favorite
243          * <P>Type: INTEGER</P>
244          */
245         public static final String SPANX = "spanX";
246 
247         /**
248          * The Y span of the cell holding the favorite
249          * <P>Type: INTEGER</P>
250          */
251         public static final String SPANY = "spanY";
252 
253         /**
254          * The profile id of the item in the cell.
255          * <P>
256          * Type: INTEGER
257          * </P>
258          */
259         public static final String PROFILE_ID = "profileId";
260 
261         /**
262          * The appWidgetId of the widget
263          *
264          * <P>Type: INTEGER</P>
265          */
266         public static final String APPWIDGET_ID = "appWidgetId";
267 
268         /**
269          * The ComponentName of the widget provider
270          *
271          * <P>Type: STRING</P>
272          */
273         public static final String APPWIDGET_PROVIDER = "appWidgetProvider";
274 
275         /**
276          * Boolean indicating that his item was restored and not yet successfully bound.
277          * <P>Type: INTEGER</P>
278          */
279         public static final String RESTORED = "restored";
280 
281         /**
282          * Indicates the position of the item inside an auto-arranged view like folder or hotseat.
283          * <p>Type: INTEGER</p>
284          */
285         public static final String RANK = "rank";
286 
287         /**
288          * Stores general flag based options for {@link ItemInfo}s.
289          * <p>Type: INTEGER</p>
290          */
291         public static final String OPTIONS = "options";
292 
293         /**
294          * Stores the source container that the widget was added from.
295          * <p>Type: INTEGER</p>
296          */
297         public static final String APPWIDGET_SOURCE = "appWidgetSource";
298 
addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional)299         public static void addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional) {
300             addTableToDb(db, myProfileId, optional, TABLE_NAME);
301         }
302 
addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional, String tableName)303         public static void addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional,
304                 String tableName) {
305             db.execSQL("CREATE TABLE " + (optional ? " IF NOT EXISTS " : "") + tableName + " ("
306                     + getJoinedColumnsToTypes(myProfileId) + ");");
307         }
308 
309         // LinkedHashMap maintains Order of Insertion
310         @NonNull
getColumnsToTypes(long profileId)311         private static LinkedHashMap<String, String> getColumnsToTypes(long profileId) {
312             final LinkedHashMap<String, String> columnsToTypes = new LinkedHashMap<>();
313             columnsToTypes.put(_ID, "INTEGER PRIMARY KEY");
314             columnsToTypes.put(TITLE, "TEXT");
315             columnsToTypes.put(INTENT, "TEXT");
316             columnsToTypes.put(CONTAINER, "INTEGER");
317             columnsToTypes.put(SCREEN, "INTEGER");
318             columnsToTypes.put(CELLX, "INTEGER");
319             columnsToTypes.put(CELLY, "INTEGER");
320             columnsToTypes.put(SPANX, "INTEGER");
321             columnsToTypes.put(SPANY, "INTEGER");
322             columnsToTypes.put(ITEM_TYPE, "INTEGER");
323             columnsToTypes.put(APPWIDGET_ID, "INTEGER NOT NULL DEFAULT -1");
324             columnsToTypes.put(ICON, "BLOB");
325             columnsToTypes.put(APPWIDGET_PROVIDER, "TEXT");
326             columnsToTypes.put(MODIFIED, "INTEGER NOT NULL DEFAULT 0");
327             columnsToTypes.put(RESTORED, "INTEGER NOT NULL DEFAULT 0");
328             columnsToTypes.put(PROFILE_ID, "INTEGER DEFAULT " + profileId);
329             columnsToTypes.put(RANK, "INTEGER NOT NULL DEFAULT 0");
330             columnsToTypes.put(OPTIONS, "INTEGER NOT NULL DEFAULT 0");
331             columnsToTypes.put(APPWIDGET_SOURCE, "INTEGER NOT NULL DEFAULT -1");
332             return columnsToTypes;
333         }
334 
getJoinedColumnsToTypes(long profileId)335         private static String getJoinedColumnsToTypes(long profileId) {
336             return getColumnsToTypes(profileId)
337                     .entrySet()
338                     .stream()
339                     .map(it -> it.getKey() + " " + it.getValue())
340                     .collect(Collectors.joining(", "));
341         }
342 
343         /**
344          * Returns an ordered list of columns in the Favorites table as one string, ready to use in
345          * an SQL statement.
346          */
347         @NonNull
getColumns(long profileId)348         public static String getColumns(long profileId) {
349             return String.join(", ", getColumnsToTypes(profileId).keySet());
350         }
351     }
352 
353     /**
354      * Launcher settings
355      */
356     public static final class Settings {
357         public static final String LAYOUT_DIGEST_KEY = "launcher3.layout.provider.blob";
358         public static final String LAYOUT_DIGEST_LABEL = "launcher-layout";
359         public static final String LAYOUT_DIGEST_TAG = "ignore";
360     }
361 }
362