131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyalimport android.annotation.TargetApi; 207376faefbbcbe30cc4e3f706ab95c254a4707d98The Android Open Source Projectimport android.appwidget.AppWidgetHost; 21b87bd16c8e3f88a9ba78ed00c9f150b38dc39f33Mike Cleronimport android.appwidget.AppWidgetManager; 22228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.content.ComponentName; 2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.ContentProvider; 24085c853a5702c45865e9b017d21fa15cf2b151b9Yuraimport android.content.ContentProviderOperation; 25085c853a5702c45865e9b017d21fa15cf2b151b9Yuraimport android.content.ContentProviderResult; 26228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.content.ContentUris; 2731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.ContentValues; 28228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.content.Context; 2931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Intent; 30085c853a5702c45865e9b017d21fa15cf2b151b9Yuraimport android.content.OperationApplicationException; 31b85f8a44b51258f22938773ca30dd85845345010Michael Jurkaimport android.content.SharedPreferences; 32b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyalimport android.content.pm.PackageManager.NameNotFoundException; 33b87bd16c8e3f88a9ba78ed00c9f150b38dc39f33Mike Cleronimport android.content.res.Resources; 3431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.database.Cursor; 3531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.database.SQLException; 36228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.database.sqlite.SQLiteDatabase; 37228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.database.sqlite.SQLiteOpenHelper; 38228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.database.sqlite.SQLiteQueryBuilder; 390b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyalimport android.database.sqlite.SQLiteStatement; 4031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.net.Uri; 417779d62308b87ca26e3be47df836893f6f7693ecSunny Goyalimport android.os.Binder; 42b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyalimport android.os.Build; 43b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyalimport android.os.Bundle; 44b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyalimport android.os.Handler; 45b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyalimport android.os.Message; 467779d62308b87ca26e3be47df836893f6f7693ecSunny Goyalimport android.os.Process; 47e26d1008eb587303db25797ca02cc32464e45656Sunny Goyalimport android.os.Trace; 48b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyalimport android.os.UserManager; 49228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.text.TextUtils; 50228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport android.util.Log; 51094fc7ac6daef2463a8885499ae80bcf1ae7f849Dianne Hackborn 520fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; 530fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport com.android.launcher3.LauncherSettings.Favorites; 54b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyalimport com.android.launcher3.LauncherSettings.WorkspaceScreens; 55ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport com.android.launcher3.compat.UserHandleCompat; 56ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport com.android.launcher3.compat.UserManagerCompat; 57a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyalimport com.android.launcher3.config.FeatureFlags; 58e523e70f75ff90ca5d613fb8398d37208e6cd32dChris Wrenimport com.android.launcher3.config.ProviderConfig; 59827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickhamimport com.android.launcher3.dynamicui.ExtractionUtils; 60a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyalimport com.android.launcher3.provider.LauncherDbUtils; 61e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyalimport com.android.launcher3.provider.RestoreDbTask; 62e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyalimport com.android.launcher3.util.ManagedProfileHeuristic; 63bf67f3b1847c435bbaf19600ec7babbb9d4c7674Sunny Goyalimport com.android.launcher3.util.NoLocaleSqliteContext; 64b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyalimport com.android.launcher3.util.Preconditions; 65091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 668b805b17158886035b38261eb611d8641701ae43Michael Jurka 67228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport java.net.URISyntaxException; 68228da5a24e5a680cfb7bec14a24d20b5cb595a34Adam Cohenimport java.util.ArrayList; 6971483f417bb19f524cda41081f5ccac6084dc103Adam Cohenimport java.util.Collections; 70a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Beginimport java.util.Locale; 71edcce099c98a6c40d10109ac092ab50f9d2668f3Romain Guy 7231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectpublic class LauncherProvider extends ContentProvider { 73c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal private static final String TAG = "LauncherProvider"; 74a30ce8e6b25e41f392a41fd4d0d3e0a424a84dadJoe Onorato private static final boolean LOGD = false; 7531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 76a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal private static final int DATABASE_VERSION = 27; 7731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 78e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public static final String AUTHORITY = ProviderConfig.AUTHORITY; 793d503fbd9468fb2b9fa645f4f7b91e11229edbfaWinson Chung 80e87e6abc3639559f2746171999fee352cb5bd946Sunny Goyal static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; 8131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 82b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name"; 83b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal 84b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private final ChangeListenerWrapper mListenerWrapper = new ChangeListenerWrapper(); 85b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private Handler mListenerHandler; 86b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 87f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected DatabaseHelper mOpenHelper; 8831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public boolean onCreate() { 91e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal if (ProviderConfig.IS_DOGFOOD_BUILD) { 92e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal Log.d(TAG, "Launcher process started"); 93e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal } 94b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mListenerHandler = new Handler(mListenerWrapper); 95b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 96e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler LauncherAppState.setLauncherProvider(this); 9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return true; 9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 100d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal /** 101d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal * Sets a provider listener. 102d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal */ 10367e7cae5ad97ec5702bbd739c4272e3cfa17556dAnjali Koppal public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) { 104b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Preconditions.assertUIThread(); 105b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mListenerWrapper.mListener = listener; 10667e7cae5ad97ec5702bbd739c4272e3cfa17556dAnjali Koppal } 10767e7cae5ad97ec5702bbd739c4272e3cfa17556dAnjali Koppal 10831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 10931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public String getType(Uri uri) { 11031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments args = new SqlArguments(uri, null, null); 11131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (TextUtils.isEmpty(args.where)) { 11231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return "vnd.android.cursor.dir/" + args.table; 11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 11431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return "vnd.android.cursor.item/" + args.table; 11531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 11631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 11731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 118f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 119f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * Overridden in tests 120f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 121f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected synchronized void createDbIfNotExists() { 122d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal if (mOpenHelper == null) { 123e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal if (LauncherAppState.PROFILE_STARTUP) { 124e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal Trace.beginSection("Opening workspace DB"); 125e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal } 126b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler); 127e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal 128e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal if (RestoreDbTask.isPending(getContext())) { 129e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal if (!RestoreDbTask.performRestore(mOpenHelper)) { 130e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); 131e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal } 132e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal // Set is pending to false irrespective of the result, so that it doesn't get 133e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal // executed again. 134e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal RestoreDbTask.setPending(getContext(), false); 135e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal } 136e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal 137e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal if (LauncherAppState.PROFILE_STARTUP) { 138e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal Trace.endSection(); 139e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal } 140d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal } 141d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal } 142d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal 14331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 14431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public Cursor query(Uri uri, String[] projection, String selection, 14531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project String[] selectionArgs, String sortOrder) { 146d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 14731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 14831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments args = new SqlArguments(uri, selection, selectionArgs); 14931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 15031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project qb.setTables(args.table); 15131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 15273b979d8c141c7ceac82dad7c5b271a6a42afa67Romain Guy SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 15331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder); 15431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project result.setNotificationUri(getContext().getContentResolver(), uri); 15531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 15631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return result; 15731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 15831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 159091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static long dbInsertAndCheck(DatabaseHelper helper, 160a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) { 161d502404a44fb7c4ea739622d7f8bdd2a764d97a1Dan Sandler if (values == null) { 162d502404a44fb7c4ea739622d7f8bdd2a764d97a1Dan Sandler throw new RuntimeException("Error: attempting to insert null values"); 163d502404a44fb7c4ea739622d7f8bdd2a764d97a1Dan Sandler } 16471483f417bb19f524cda41081f5ccac6084dc103Adam Cohen if (!values.containsKey(LauncherSettings.ChangeLogColumns._ID)) { 165a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka throw new RuntimeException("Error: attempting to add item without specifying an id"); 166a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka } 1675dee7aff5fa8774d37977d12df7ce8986752321dChris Wren helper.checkId(table, values); 168a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka return db.insert(table, nullColumnHack, values); 169a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka } 170a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka 171d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal private void reloadLauncherIfExternal() { 172c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal if (Utilities.ATLEAST_MARSHMALLOW && Binder.getCallingPid() != Process.myPid()) { 173d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal LauncherAppState app = LauncherAppState.getInstanceNoCreate(); 174d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal if (app != null) { 175d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal app.reloadWorkspace(); 176d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal } 177d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal } 178d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal } 179d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal 18031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 18131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public Uri insert(Uri uri, ContentValues initialValues) { 182d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 18331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments args = new SqlArguments(uri); 18431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 185d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal // In very limited cases, we support system|signature permission apps to modify the db. 186d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal if (Binder.getCallingPid() != Process.myPid()) { 187b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (!initializeExternalAdd(initialValues)) { 188a043fa89211541c71b5bef052ebc49f722d338b9Adam Cohen return null; 189a043fa89211541c71b5bef052ebc49f722d338b9Adam Cohen } 190a043fa89211541c71b5bef052ebc49f722d338b9Adam Cohen } 191a043fa89211541c71b5bef052ebc49f722d338b9Adam Cohen 19231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1931ada10d5950f45aba998a7722bfde2e529201f48Chris Wren addModifiedTime(initialValues); 194a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues); 195e72f3d53f8c35b94aece6fafa6fd12cce9d09fe5Sunny Goyal if (rowId < 0) return null; 19631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 19731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project uri = ContentUris.withAppendedId(uri, rowId); 1981d4a2df091e2b5928406ea503321563a0ec8a01eSunny Goyal notifyListeners(); 1991d4a2df091e2b5928406ea503321563a0ec8a01eSunny Goyal 200c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal if (Utilities.ATLEAST_MARSHMALLOW) { 201c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal reloadLauncherIfExternal(); 202c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal } else { 203c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal // Deprecated behavior to support legacy devices which rely on provider callbacks. 204c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal LauncherAppState app = LauncherAppState.getInstanceNoCreate(); 205c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal if (app != null && "true".equals(uri.getQueryParameter("isExternalAdd"))) { 206c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal app.reloadWorkspace(); 207c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal } 208c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal 209c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal String notify = uri.getQueryParameter("notify"); 210c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal if (notify == null || "true".equals(notify)) { 211c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal getContext().getContentResolver().notifyChange(uri, null); 212c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal } 213c74e41973a74aa416e16aeadaa2f491153da26bcSunny Goyal } 21431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return uri; 21531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 21631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 217b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private boolean initializeExternalAdd(ContentValues values) { 218b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal // 1. Ensure that externally added items have a valid item id 219b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal long id = mOpenHelper.generateNewItemId(); 220b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal values.put(LauncherSettings.Favorites._ID, id); 221b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 222b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal // 2. In the case of an app widget, and if no app widget id is specified, we 223b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal // attempt allocate and bind the widget. 224b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Integer itemType = values.getAsInteger(LauncherSettings.Favorites.ITEM_TYPE); 225b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (itemType != null && 226b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal itemType.intValue() == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && 227b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal !values.containsKey(LauncherSettings.Favorites.APPWIDGET_ID)) { 228b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 229b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getContext()); 230b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal ComponentName cn = ComponentName.unflattenFromString( 231b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal values.getAsString(Favorites.APPWIDGET_PROVIDER)); 232b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 233b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (cn != null) { 234b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal try { 235b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal int appWidgetId = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID) 236b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal .allocateAppWidgetId(); 237b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId); 238b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) { 239b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return false; 240b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 241b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } catch (RuntimeException e) { 242b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Log.e(TAG, "Failed to initialize external widget", e); 243b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return false; 244b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 245b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } else { 246b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return false; 247b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 248b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 249b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 250b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal // Add screen id if not present 251b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal long screenId = values.getAsLong(LauncherSettings.Favorites.SCREEN); 252b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal SQLiteStatement stmp = null; 253b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal try { 254b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal stmp = mOpenHelper.getWritableDatabase().compileStatement( 255b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal "INSERT OR IGNORE INTO workspaceScreens (_id, screenRank) " + 256b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal "select ?, (ifnull(MAX(screenRank), -1)+1) from workspaceScreens"); 257b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal stmp.bindLong(1, screenId); 258b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 259b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal ContentValues valuesInserted = new ContentValues(); 260b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal valuesInserted.put(LauncherSettings.BaseLauncherColumns._ID, stmp.executeInsert()); 261b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mOpenHelper.checkId(WorkspaceScreens.TABLE_NAME, valuesInserted); 262b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return true; 263b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } catch (Exception e) { 264b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return false; 265b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } finally { 266b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Utilities.closeSilently(stmp); 267b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 268b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 269b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 27031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 27131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int bulkInsert(Uri uri, ContentValues[] values) { 272d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 27331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments args = new SqlArguments(uri); 27431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 27531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 27631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project db.beginTransaction(); 27731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project try { 27831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int numValues = values.length; 27931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project for (int i = 0; i < numValues; i++) { 2801ada10d5950f45aba998a7722bfde2e529201f48Chris Wren addModifiedTime(values[i]); 281a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) { 282a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka return 0; 283a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka } 28431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project db.setTransactionSuccessful(); 28631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } finally { 28731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project db.endTransaction(); 28831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 28931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 2901d4a2df091e2b5928406ea503321563a0ec8a01eSunny Goyal notifyListeners(); 291d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal reloadLauncherIfExternal(); 29231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return values.length; 29331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 29431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 29531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 296085c853a5702c45865e9b017d21fa15cf2b151b9Yura public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 297085c853a5702c45865e9b017d21fa15cf2b151b9Yura throws OperationApplicationException { 298d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 299085c853a5702c45865e9b017d21fa15cf2b151b9Yura SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 300085c853a5702c45865e9b017d21fa15cf2b151b9Yura db.beginTransaction(); 301085c853a5702c45865e9b017d21fa15cf2b151b9Yura try { 302085c853a5702c45865e9b017d21fa15cf2b151b9Yura ContentProviderResult[] result = super.applyBatch(operations); 303085c853a5702c45865e9b017d21fa15cf2b151b9Yura db.setTransactionSuccessful(); 304d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal reloadLauncherIfExternal(); 305085c853a5702c45865e9b017d21fa15cf2b151b9Yura return result; 306085c853a5702c45865e9b017d21fa15cf2b151b9Yura } finally { 307085c853a5702c45865e9b017d21fa15cf2b151b9Yura db.endTransaction(); 308085c853a5702c45865e9b017d21fa15cf2b151b9Yura } 309085c853a5702c45865e9b017d21fa15cf2b151b9Yura } 310085c853a5702c45865e9b017d21fa15cf2b151b9Yura 311085c853a5702c45865e9b017d21fa15cf2b151b9Yura @Override 31231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int delete(Uri uri, String selection, String[] selectionArgs) { 313d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 31431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments args = new SqlArguments(uri, selection, selectionArgs); 31531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 31631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 31731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 318a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin if (Binder.getCallingPid() != Process.myPid() 319a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin && Favorites.TABLE_NAME.equalsIgnoreCase(args.table)) { 320a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin String widgetSelection = TextUtils.isEmpty(args.where) ? "1=1" : args.where; 321a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin widgetSelection = String.format(Locale.ENGLISH, "%1$s = %2$d AND ( %3$s )", 322a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET, widgetSelection); 323a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin try (Cursor c = db.query(Favorites.TABLE_NAME, new String[] { Favorites.APPWIDGET_ID }, 324a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin widgetSelection, args.args, null, null, null)) { 325a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin AppWidgetHost host = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID); 326a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin while (c.moveToNext()) { 327a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin int widgetId = c.getInt(0); 328a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin if (widgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { 329a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin try { 330a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin host.deleteAppWidgetId(widgetId); 331a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } catch (RuntimeException e) { 332a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin Log.e(TAG, "Error deleting widget id " + widgetId, e); 333a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } 334a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } 335a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } 336a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } 337a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } 338a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin int count = db.delete(args.table, args.where, args.args); 339a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin if (count > 0) { 340a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin notifyListeners(); 341a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin reloadLauncherIfExternal(); 342a9c21c624ca15fe7aa5e65e17cdd9fb26d1ec691Louis Begin } 34331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return count; 34431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 34531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 34631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 34731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 348d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 34931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments args = new SqlArguments(uri, selection, selectionArgs); 35031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3511ada10d5950f45aba998a7722bfde2e529201f48Chris Wren addModifiedTime(values); 35231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 35331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project int count = db.update(args.table, values, args.where, args.args); 3541d4a2df091e2b5928406ea503321563a0ec8a01eSunny Goyal if (count > 0) notifyListeners(); 35531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 356d106418dee16b041f30682540fbd3ca3d841b7afSunny Goyal reloadLauncherIfExternal(); 35731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project return count; 35831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 35931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 3607779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal @Override 361827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham public Bundle call(String method, final String arg, final Bundle extras) { 3627779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal if (Binder.getCallingUid() != Process.myUid()) { 3637779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal return null; 3647779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal } 365d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal createDbIfNotExists(); 3667779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal 3677779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal switch (method) { 368827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham case LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID: { 369827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham String extractedColors = extras.getString( 370827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS); 371827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham int wallpaperId = extras.getInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID); 372827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham Utilities.getPrefs(getContext()).edit() 373827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham .putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors) 374827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham .putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId) 375827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham .apply(); 376b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_EXTRACTED_COLORS_CHANGED); 377827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham Bundle result = new Bundle(); 378827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors); 379827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham return result; 380827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham } 381d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG: { 382d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal clearFlagEmptyDbCreated(); 383d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return null; 384d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 385a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal case LauncherSettings.Settings.METHOD_WAS_EMPTY_DB_CREATED : { 386a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal Bundle result = new Bundle(); 387a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, 388a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal Utilities.getPrefs(getContext()).getBoolean(EMPTY_DATABASE_CREATED, false)); 389a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal return result; 390a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 391d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS: { 392d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal Bundle result = new Bundle(); 393d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal result.putSerializable(LauncherSettings.Settings.EXTRA_VALUE, deleteEmptyFolders()); 394d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return result; 395d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 396d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_NEW_ITEM_ID: { 397d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal Bundle result = new Bundle(); 398d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal result.putLong(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewItemId()); 399d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return result; 400d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 401d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_NEW_SCREEN_ID: { 402d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal Bundle result = new Bundle(); 403d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal result.putLong(LauncherSettings.Settings.EXTRA_VALUE, mOpenHelper.generateNewScreenId()); 404d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return result; 405d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 406d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: { 407d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal createEmptyDB(); 408d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return null; 409d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 410d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES: { 411d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal loadDefaultFavoritesIfNecessary(); 412d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return null; 413d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 414d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal case LauncherSettings.Settings.METHOD_DELETE_DB: { 415aefc0c4dd0589d2ef423caf26c11068b5cb59722Sunny Goyal // Are you sure? (y/n) 416aefc0c4dd0589d2ef423caf26c11068b5cb59722Sunny Goyal mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); 417d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal return null; 418d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal } 4197779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal } 4207779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal return null; 4217779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal } 4227779d62308b87ca26e3be47df836893f6f7693ecSunny Goyal 423b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal /** 424b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal * Deletes any empty folder from the DB. 425b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal * @return Ids of deleted folders. 426b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal */ 427d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal private ArrayList<Long> deleteEmptyFolders() { 428d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal ArrayList<Long> folderIds = new ArrayList<>(); 429b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 430b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal db.beginTransaction(); 431b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal try { 432b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal // Select folders whose id do not match any container value. 433b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal String selection = LauncherSettings.Favorites.ITEM_TYPE + " = " 434b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal + LauncherSettings.Favorites.ITEM_TYPE_FOLDER + " AND " 435b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal + LauncherSettings.Favorites._ID + " NOT IN (SELECT " + 436b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal LauncherSettings.Favorites.CONTAINER + " FROM " 437b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal + Favorites.TABLE_NAME + ")"; 438b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Cursor c = db.query(Favorites.TABLE_NAME, 439b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal new String[] {LauncherSettings.Favorites._ID}, 440b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal selection, null, null, null, null); 441b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal while (c.moveToNext()) { 442b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal folderIds.add(c.getLong(0)); 443b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } 444b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal c.close(); 445d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal if (!folderIds.isEmpty()) { 446b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery( 447b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal LauncherSettings.Favorites._ID, folderIds), null); 448b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } 449b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal db.setTransactionSuccessful(); 450b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } catch (SQLException ex) { 451b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal Log.e(TAG, ex.getMessage(), ex); 452b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal folderIds.clear(); 453b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } finally { 454b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal db.endTransaction(); 455b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } 456b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal return folderIds; 457b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } 458b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal 459f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 460f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * Overridden in tests 461f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 462f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected void notifyListeners() { 463b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_LAUNCHER_PROVIDER_CHANGED); 4641ada10d5950f45aba998a7722bfde2e529201f48Chris Wren } 4651ada10d5950f45aba998a7722bfde2e529201f48Chris Wren 466091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static void addModifiedTime(ContentValues values) { 4671ada10d5950f45aba998a7722bfde2e529201f48Chris Wren values.put(LauncherSettings.ChangeLogColumns.MODIFIED, System.currentTimeMillis()); 46831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 46931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 4705524b4957fc7c1c858037327429411efdb8fe7d6Brian Muramatsu /** 47142de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal * Clears all the data for a fresh start. 47242de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal */ 473d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal synchronized private void createEmptyDB() { 47442de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); 47542de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal } 47642de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal 477d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal private void clearFlagEmptyDbCreated() { 478f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal Utilities.getPrefs(getContext()).edit().remove(EMPTY_DATABASE_CREATED).commit(); 47933d443897658e6ad8b76bd2e58e3598161fd3eadSunny Goyal } 48033d443897658e6ad8b76bd2e58e3598161fd3eadSunny Goyal 48142de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal /** 4820fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * Loads the default workspace based on the following priority scheme: 483b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * 1) From the app restrictions 484b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * 2) From a package provided by play store 485b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * 3) From a partner configuration APK, already in the system image 486b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * 4) The default configuration for the particular device 4875524b4957fc7c1c858037327429411efdb8fe7d6Brian Muramatsu */ 488d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal synchronized private void loadDefaultFavoritesIfNecessary() { 489f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal SharedPreferences sp = Utilities.getPrefs(getContext()); 490e25af795647a19f1a0d60bc4baea5a996d215fdfAdam Cohen 491c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) { 4925dee7aff5fa8774d37977d12df7ce8986752321dChris Wren Log.d(TAG, "loading default workspace"); 49345355c4596f396d7e7247e91de850646356bd104Michael Jurka 494b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal AppWidgetHost widgetHost = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID); 495b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost); 496b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal if (loader == null) { 497b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper); 498b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal } 4990fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal if (loader == null) { 5009b8f51fcc85805436bee619a927e2222005e9e09Adam Cohen final Partner partner = Partner.get(getContext().getPackageManager()); 5019b8f51fcc85805436bee619a927e2222005e9e09Adam Cohen if (partner != null && partner.hasDefaultLayout()) { 5029b8f51fcc85805436bee619a927e2222005e9e09Adam Cohen final Resources partnerRes = partner.getResources(); 5034ae96ce92df7aad3c767c68b8795b80734e01829Adam Cohen int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, 5049b8f51fcc85805436bee619a927e2222005e9e09Adam Cohen "xml", partner.getPackageName()); 5050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal if (workspaceResId != 0) { 506b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal loader = new DefaultLayoutParser(getContext(), widgetHost, 5073a5a9d18daacb878a3eb379fce540ee6c67063e6Sunny Goyal mOpenHelper, partnerRes, workspaceResId); 5080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } 5099b8f51fcc85805436bee619a927e2222005e9e09Adam Cohen } 5109b8f51fcc85805436bee619a927e2222005e9e09Adam Cohen } 5115524b4957fc7c1c858037327429411efdb8fe7d6Brian Muramatsu 5129d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal final boolean usingExternallyProvidedLayout = loader != null; 5130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal if (loader == null) { 514b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal loader = getDefaultLayoutParser(widgetHost); 51545355c4596f396d7e7247e91de850646356bd104Michael Jurka } 516c6c8fef3e90f84b26c3b8550ec6a1d668ca9200dSunny Goyal 517c6c8fef3e90f84b26c3b8550ec6a1d668ca9200dSunny Goyal // There might be some partially restored DB items, due to buggy restore logic in 518c6c8fef3e90f84b26c3b8550ec6a1d668ca9200dSunny Goyal // previous versions of launcher. 519c6c8fef3e90f84b26c3b8550ec6a1d668ca9200dSunny Goyal createEmptyDB(); 5200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal // Populate favorites table with initial favorites 5219d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0) 5229d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal && usingExternallyProvidedLayout) { 5239d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal // Unable to load external layout. Cleanup and load the internal layout. 5249d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal createEmptyDB(); 5259d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), 526b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal getDefaultLayoutParser(widgetHost)); 5279d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal } 52833d443897658e6ad8b76bd2e58e3598161fd3eadSunny Goyal clearFlagEmptyDbCreated(); 529b85f8a44b51258f22938773ca30dd85845345010Michael Jurka } 530b85f8a44b51258f22938773ca30dd85845345010Michael Jurka } 531b85f8a44b51258f22938773ca30dd85845345010Michael Jurka 532b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal /** 533b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * Creates workspace loader from an XML resource listed in the app restrictions. 534b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * 535b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal * @return the loader if the restrictions are set and the resource exists; null otherwise. 536b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal */ 537b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 538b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) { 539b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18 5409fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal if (!Utilities.ATLEAST_JB_MR2) { 541b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal return null; 542b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal } 543b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal 544b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal Context ctx = getContext(); 545b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE); 546b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName()); 54735ca873bd9e1331765343a6cae8387431794b0afSunny Goyal if (bundle == null) { 54835ca873bd9e1331765343a6cae8387431794b0afSunny Goyal return null; 54935ca873bd9e1331765343a6cae8387431794b0afSunny Goyal } 550b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal 55135ca873bd9e1331765343a6cae8387431794b0afSunny Goyal String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME); 552b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal if (packageName != null) { 553b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal try { 554b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal Resources targetResources = ctx.getPackageManager() 555b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal .getResourcesForApplication(packageName); 556b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal return AutoInstallsLayout.get(ctx, packageName, targetResources, 557b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal widgetHost, mOpenHelper); 558b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal } catch (NameNotFoundException e) { 559b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal Log.e(TAG, "Target package for restricted profile not found", e); 560b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal return null; 561b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal } 562b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal } 563b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal return null; 564b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal } 565b2d46ceaaa32ece85f18e049d9e30a5ccaf80e45Sunny Goyal 566b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) { 5679d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal int defaultLayout = LauncherAppState.getInstance() 5682e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen .getInvariantDeviceProfile().defaultLayoutId; 569b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return new DefaultLayoutParser(getContext(), widgetHost, 5709d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal mOpenHelper, getContext().getResources(), defaultLayout); 5719d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal } 5729d219685c5f008ddfb0f72ef01831308d8a81c2eSunny Goyal 573d3849d191bc0bd2d561cf03018ad90b896b13c56Sunny Goyal /** 574f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * The class is subclassed in tests to create an in-memory db. 575f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 576c190dbfb784c0bca629b6966ce314d735cf98db3Sunny Goyal public static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback { 577b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private final Handler mWidgetHostResetHandler; 57831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project private final Context mContext; 579dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen private long mMaxItemId = -1; 580dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen private long mMaxScreenId = -1; 58131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 582b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal DatabaseHelper(Context context, Handler widgetHostResetHandler) { 583b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal this(context, widgetHostResetHandler, LauncherFiles.LAUNCHER_DB); 5846fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal // Table creation sometimes fails silently, which leads to a crash loop. 5856fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal // This way, we will try to create a table every time after crash, so the device 5866fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal // would eventually be able to recover. 587b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (!tableExists(Favorites.TABLE_NAME) || !tableExists(WorkspaceScreens.TABLE_NAME)) { 5886fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); 5896fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal // This operation is a no-op if the table already exists. 5906fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal addFavoritesTable(getWritableDatabase(), true); 5916fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal addWorkspacesTable(getWritableDatabase(), true); 5926fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal } 5936fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal 5947eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal initIds(); 59531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 59631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 597f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 598c190dbfb784c0bca629b6966ce314d735cf98db3Sunny Goyal * Constructor used in tests and for restore. 599f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 6007eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal public DatabaseHelper( 601b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Context context, Handler widgetHostResetHandler, String tableName) { 602bf67f3b1847c435bbaf19600ec7babbb9d4c7674Sunny Goyal super(new NoLocaleSqliteContext(context), tableName, null, DATABASE_VERSION); 603f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mContext = context; 604b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mWidgetHostResetHandler = widgetHostResetHandler; 6057eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal } 606f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 6077eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal protected void initIds() { 6087eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from 6097eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal // the DB here 6107eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal if (mMaxItemId == -1) { 6117eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal mMaxItemId = initializeMaxItemId(getWritableDatabase()); 6127eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal } 6137eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal if (mMaxScreenId == -1) { 6147eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal mMaxScreenId = initializeMaxScreenId(getWritableDatabase()); 6157eab3cc374aeaaa6e305a3f583901da9844dfe08Sunny Goyal } 616f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 617f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 6186fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal private boolean tableExists(String tableName) { 6196fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal Cursor c = getReadableDatabase().query( 6206fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal true, "sqlite_master", new String[] {"tbl_name"}, 6216fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal "tbl_name = ?", new String[] {tableName}, 6226fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal null, null, null, null, null); 6236fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal try { 6246fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal return c.getCount() > 0; 6256fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal } finally { 6266fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal c.close(); 6276fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal } 6286fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal } 6296fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal 63031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 63131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void onCreate(SQLiteDatabase db) { 632a30ce8e6b25e41f392a41fd4d0d3e0a424a84dadJoe Onorato if (LOGD) Log.d(TAG, "creating new launcher database"); 633a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka 634dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen mMaxItemId = 1; 635dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen mMaxScreenId = 0; 636a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka 6376fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal addFavoritesTable(db, false); 6386fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal addWorkspacesTable(db, false); 6396fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal 6406fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal // Fresh and clean launcher DB. 6416fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal mMaxItemId = initializeMaxItemId(db); 642f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal onEmptyDbCreated(); 643f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 644f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 645f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 646f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * Overriden in tests. 647f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 648f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected void onEmptyDbCreated() { 649b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal // Database was just created, so wipe any previous widgets 650b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (mWidgetHostResetHandler != null) { 651b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost(); 652da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal mWidgetHostResetHandler.sendMessage(Message.obtain( 653da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal mWidgetHostResetHandler, 654da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET, 655da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal mContext 656da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal )); 657b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 658b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 659f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Set the flag for empty DB 660f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit(); 6616fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal 6626fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal // When a new DB is created, remove all previously stored managed profile information. 663f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal ManagedProfileHeuristic.processAllUsers(Collections.<UserHandleCompat>emptyList(), 664f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mContext); 6656fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal } 6666fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal 667e8f7d5a67ef71b1c6488f52145482a8876c1b708Sunny Goyal public long getDefaultUserSerial() { 668f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return UserManagerCompat.getInstance(mContext).getSerialNumberForUser( 669ed13187a745866483139e2878037e1f8427ce567Kenny Guy UserHandleCompat.myUserHandle()); 670f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 671ed13187a745866483139e2878037e1f8427ce567Kenny Guy 672f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private void addFavoritesTable(SQLiteDatabase db, boolean optional) { 673c190dbfb784c0bca629b6966ce314d735cf98db3Sunny Goyal Favorites.addTableToDb(db, getDefaultUserSerial(), optional); 67431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 67531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6766fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal private void addWorkspacesTable(SQLiteDatabase db, boolean optional) { 6776fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal String ifNotExists = optional ? " IF NOT EXISTS " : ""; 678b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal db.execSQL("CREATE TABLE " + ifNotExists + WorkspaceScreens.TABLE_NAME + " (" + 679d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal LauncherSettings.WorkspaceScreens._ID + " INTEGER PRIMARY KEY," + 6801ada10d5950f45aba998a7722bfde2e529201f48Chris Wren LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," + 6811ada10d5950f45aba998a7722bfde2e529201f48Chris Wren LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" + 682dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen ");"); 683dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen } 684dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen 685119285e755f8572632dc845d72320d9eed378f69Adam Cohen private void removeOrphanedItems(SQLiteDatabase db) { 686f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen // Delete items directly on the workspace who's screen id doesn't exist 687f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen // "DELETE FROM favorites WHERE screen NOT IN (SELECT _id FROM workspaceScreens) 688f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen // AND container = -100" 689b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal String removeOrphanedDesktopItems = "DELETE FROM " + Favorites.TABLE_NAME + 690f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen " WHERE " + 691119285e755f8572632dc845d72320d9eed378f69Adam Cohen LauncherSettings.Favorites.SCREEN + " NOT IN (SELECT " + 692b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal LauncherSettings.WorkspaceScreens._ID + " FROM " + WorkspaceScreens.TABLE_NAME + ")" + 693f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen " AND " + 694f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen LauncherSettings.Favorites.CONTAINER + " = " + 695f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen LauncherSettings.Favorites.CONTAINER_DESKTOP; 696f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen db.execSQL(removeOrphanedDesktopItems); 697f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen 698f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen // Delete items contained in folders which no longer exist (after above statement) 699f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen // "DELETE FROM favorites WHERE container <> -100 AND container <> -101 AND container 700f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen // NOT IN (SELECT _id FROM favorites WHERE itemType = 2)" 701b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal String removeOrphanedFolderItems = "DELETE FROM " + Favorites.TABLE_NAME + 702f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen " WHERE " + 703f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen LauncherSettings.Favorites.CONTAINER + " <> " + 704f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen LauncherSettings.Favorites.CONTAINER_DESKTOP + 705f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen " AND " 706f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen + LauncherSettings.Favorites.CONTAINER + " <> " + 707f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen LauncherSettings.Favorites.CONTAINER_HOTSEAT + 708f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen " AND " 709f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen + LauncherSettings.Favorites.CONTAINER + " NOT IN (SELECT " + 710b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal LauncherSettings.Favorites._ID + " FROM " + Favorites.TABLE_NAME + 711f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen " WHERE " + LauncherSettings.Favorites.ITEM_TYPE + " = " + 712f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen LauncherSettings.Favorites.ITEM_TYPE_FOLDER + ")"; 713f9c14de995d31a19123397c10e4f43bd0fe9eb56Adam Cohen db.execSQL(removeOrphanedFolderItems); 714119285e755f8572632dc845d72320d9eed378f69Adam Cohen } 715119285e755f8572632dc845d72320d9eed378f69Adam Cohen 71631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project @Override 71731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 718c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion); 719a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal switch (oldVersion) { 720a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // The version cannot be lower that 12, as Launcher3 never supported a lower 721e87e6abc3639559f2746171999fee352cb5bd946Sunny Goyal // version of the DB. 722a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 12: { 723a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // With the new shrink-wrapped and re-orderable workspaces, it makes sense 724a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // to persist workspace screens and their relative order. 725a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal mMaxScreenId = 0; 7266fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal addWorkspacesTable(db, false); 727d5e66bfca1dc4fdbab7513d88c6568bc4d17bca8Chris Wren } 728a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 13: { 729a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.beginTransaction(); 730a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal try { 731a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Insert new column for holding widget provider name 732a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.execSQL("ALTER TABLE favorites " + 733a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal "ADD COLUMN appWidgetProvider TEXT;"); 734a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.setTransactionSuccessful(); 735a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } catch (SQLException ex) { 736a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal Log.e(TAG, ex.getMessage(), ex); 737a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Old version remains, which means we wipe old data 738a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal break; 739a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } finally { 740a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.endTransaction(); 741a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 7421ada10d5950f45aba998a7722bfde2e529201f48Chris Wren } 743a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 14: { 744a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.beginTransaction(); 745a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal try { 746a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Insert new column for holding update timestamp 747a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.execSQL("ALTER TABLE favorites " + 748a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;"); 749a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.execSQL("ALTER TABLE workspaceScreens " + 750a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;"); 751a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.setTransactionSuccessful(); 752a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } catch (SQLException ex) { 753a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal Log.e(TAG, ex.getMessage(), ex); 754a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Old version remains, which means we wipe old data 755a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal break; 756a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } finally { 757a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal db.endTransaction(); 758a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 759f4d081107f5984bfb92cb1a627667fea5bf1498cChris Wren } 760a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 15: { 7615d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal if (!addIntegerColumn(db, Favorites.RESTORED, 0)) { 762a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Old version remains, which means we wipe old data 763a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal break; 764a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 765ed13187a745866483139e2878037e1f8427ce567Kenny Guy } 766a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 16: { 767a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // We use the db version upgrade here to identify users who may not have seen 768a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // clings yet (because they weren't available), but for whom the clings are now 769a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // available (tablet users). Because one of the possible cling flows (migration) 770a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // is very destructive (wipes out workspaces), we want to prevent this from showing 771a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // until clear data. We do so by marking that the clings have been shown. 772d80439875557e8c94052e5b0f0327b656370b5fdSunny Goyal LauncherClings.markFirstRunClingDismissed(mContext); 773a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 774a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 17: { 775a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // No-op 776a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 777a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 18: { 778a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Due to a data loss bug, some users may have items associated with screen ids 779a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // which no longer exist. Since this can cause other problems, and since the user 780a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // will never see these items anyway, we use database upgrade as an opportunity to 781a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // clean things up. 782a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal removeOrphanedItems(db); 783a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 784a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 19: { 785a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Add userId column 786a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal if (!addProfileColumn(db)) { 787a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // Old version remains, which means we wipe old data 788a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal break; 789a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 790a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 791a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal case 20: 792a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal if (!updateFolderItemsRank(db, true)) { 793a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal break; 794a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal } 795d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal case 21: 796d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal // Recreate workspace table with screen id a primary key 797d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal if (!recreateWorkspaceTable(db)) { 798d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal break; 799d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 800d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal case 22: { 8015d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal if (!addIntegerColumn(db, Favorites.OPTIONS, 0)) { 8025d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal // Old version remains, which means we wipe old data 8035d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal break; 8045d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal } 8055d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal } 8060b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal case 23: 8075c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal // No-op 808e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal case 24: 809e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext); 8105c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal case 25: 8115c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal convertShortcutsToLauncherActivities(db); 812a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal case 26: 813a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal // QSB was moved to the grid. Clear the first row on screen 0. 814a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal if (FeatureFlags.QSB_ON_FIRST_SCREEN && 815a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal !LauncherDbUtils.prepareScreenZeroToHostQsb(db)) { 816a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal break; 817a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal } 818a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal case 27: { 819a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // DB Upgraded successfully 820a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal return; 82108f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } 82208f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } 82308f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal 824a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal // DB was not upgraded 825a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal Log.w(TAG, "Destroying all old data."); 826a2cc624e75e41f1439d738ea6cb69802dc9652beSunny Goyal createEmptyDB(db); 82731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 8287eb9e5e9257635cee5609ed633eb575fda93dd5aRomain Guy 8299b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen @Override 8309b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 8319b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen // This shouldn't happen -- throw our hands up in the air and start over. 8329b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen Log.w(TAG, "Database version downgrade from: " + oldVersion + " to " + newVersion + 8339b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen ". Wiping databse."); 83442de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal createEmptyDB(db); 83542de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal } 83642de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal 83742de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal /** 83842de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal * Clears all the data for a fresh start. 83942de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal */ 84042de82ff8d2aa182594709e63e608bbcd4610cfaSunny Goyal public void createEmptyDB(SQLiteDatabase db) { 841b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal db.execSQL("DROP TABLE IF EXISTS " + Favorites.TABLE_NAME); 842b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME); 8439b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen onCreate(db); 8449b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen } 8459b1d062b0f1c4714883444df874e1a078764caa1Adam Cohen 846d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal /** 8470b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid 8480b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}. 8490b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal */ 850316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk void convertShortcutsToLauncherActivities(SQLiteDatabase db) { 8510b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal db.beginTransaction(); 8520b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Cursor c = null; 8530b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal SQLiteStatement updateStmt = null; 8540b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 8550b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal try { 8560b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal // Only consider the primary user as other users can't have a shortcut. 857b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal long userSerial = getDefaultUserSerial(); 858b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal c = db.query(Favorites.TABLE_NAME, new String[] { 8590b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Favorites._ID, 8600b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Favorites.INTENT, 8610b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal }, "itemType=" + Favorites.ITEM_TYPE_SHORTCUT + " AND profileId=" + userSerial, 8620b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal null, null, null, null); 8630b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 8640b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal updateStmt = db.compileStatement("UPDATE favorites SET itemType=" 8650b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal + Favorites.ITEM_TYPE_APPLICATION + " WHERE _id=?"); 8660b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 8670b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal final int idIndex = c.getColumnIndexOrThrow(Favorites._ID); 8680b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT); 8690b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 8700b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal while (c.moveToNext()) { 8710b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal String intentDescription = c.getString(intentIndex); 8720b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Intent intent; 8730b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal try { 8740b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal intent = Intent.parseUri(intentDescription, 0); 8750b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } catch (URISyntaxException e) { 8760b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Log.e(TAG, "Unable to parse intent", e); 8770b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal continue; 8780b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 8790b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 8804e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyal if (!Utilities.isLauncherAppTarget(intent)) { 8810b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal continue; 8820b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 8830b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 8840b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal long id = c.getLong(idIndex); 8850b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal updateStmt.bindLong(1, id); 886c22841bfd1961781a84cfccb98d1c2937a9adee4Sunny Goyal updateStmt.executeUpdateDelete(); 8870b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 8880b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal db.setTransactionSuccessful(); 8890b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } catch (SQLException ex) { 8900b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal Log.w(TAG, "Error deduping shortcuts", ex); 8910b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } finally { 8920b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal db.endTransaction(); 8930b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal if (c != null) { 8940b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal c.close(); 8950b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 8960b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal if (updateStmt != null) { 8970b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal updateStmt.close(); 8980b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 8990b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 9000b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal } 9010b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal 9020b037789662d1c16627dc5b509d1ac55bc76971bSunny Goyal /** 903d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal * Recreates workspace table and migrates data to the new table. 904d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal */ 905d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal public boolean recreateWorkspaceTable(SQLiteDatabase db) { 906d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal db.beginTransaction(); 907d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal try { 908b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal Cursor c = db.query(WorkspaceScreens.TABLE_NAME, 909d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal new String[] {LauncherSettings.WorkspaceScreens._ID}, 910d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal null, null, null, null, 911d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal LauncherSettings.WorkspaceScreens.SCREEN_RANK); 912d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal ArrayList<Long> sortedIDs = new ArrayList<Long>(); 913d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal long maxId = 0; 914d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal try { 915d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal while (c.moveToNext()) { 916d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal Long id = c.getLong(0); 917d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal if (!sortedIDs.contains(id)) { 918d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal sortedIDs.add(id); 919d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal maxId = Math.max(maxId, id); 920d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 921d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 922d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } finally { 923d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal c.close(); 924d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 925d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal 926b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME); 9276fb929e0038a9d03b60540fdbf6b6914146f7b21Sunny Goyal addWorkspacesTable(db, false); 928d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal 929d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal // Add all screen ids back 930d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal int total = sortedIDs.size(); 931d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal for (int i = 0; i < total; i++) { 932d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal ContentValues values = new ContentValues(); 933d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal values.put(LauncherSettings.WorkspaceScreens._ID, sortedIDs.get(i)); 934d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); 935d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal addModifiedTime(values); 936b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal db.insertOrThrow(WorkspaceScreens.TABLE_NAME, null, values); 937d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 938d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal db.setTransactionSuccessful(); 939d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal mMaxScreenId = maxId; 940d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } catch (SQLException ex) { 941d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal // Old version remains, which means we wipe old data 942d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal Log.e(TAG, ex.getMessage(), ex); 943d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal return false; 944d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } finally { 945d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal db.endTransaction(); 946d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 947d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal return true; 948d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal } 949d2f3819c34d8ecdfdb42bf973b6db3aac259bd62Sunny Goyal 950091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) { 95108f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal db.beginTransaction(); 95208f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal try { 95308f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal if (addRankColumn) { 95408f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal // Insert new column for holding rank 95508f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal db.execSQL("ALTER TABLE favorites ADD COLUMN rank INTEGER NOT NULL DEFAULT 0;"); 95608f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } 95708f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal 95808f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal // Get a map for folder ID to folder width 95908f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal Cursor c = db.rawQuery("SELECT container, MAX(cellX) FROM favorites" 96008f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal + " WHERE container IN (SELECT _id FROM favorites WHERE itemType = ?)" 96108f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal + " GROUP BY container;", 96208f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal new String[] {Integer.toString(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}); 96308f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal 96408f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal while (c.moveToNext()) { 965c87775d8e63c7b5722c23ef95c782f574b847d73Sunny Goyal db.execSQL("UPDATE favorites SET rank=cellX+(cellY*?) WHERE " 966c87775d8e63c7b5722c23ef95c782f574b847d73Sunny Goyal + "container=? AND cellX IS NOT NULL AND cellY IS NOT NULL;", 96708f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal new Object[] {c.getLong(1) + 1, c.getLong(0)}); 96808f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } 96908f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal 97008f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal c.close(); 97108f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal db.setTransactionSuccessful(); 97208f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } catch (SQLException ex) { 97308f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal // Old version remains, which means we wipe old data 97408f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal Log.e(TAG, ex.getMessage(), ex); 97508f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal return false; 97608f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } finally { 97708f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal db.endTransaction(); 97808f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } 97908f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal return true; 98008f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal } 98108f7261d11a53ae4b330ad4fa897b8519de3d750Sunny Goyal 982ed13187a745866483139e2878037e1f8427ce567Kenny Guy private boolean addProfileColumn(SQLiteDatabase db) { 983b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return addIntegerColumn(db, Favorites.PROFILE_ID, getDefaultUserSerial()); 9845d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal } 9855d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal 9865d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) { 987ed13187a745866483139e2878037e1f8427ce567Kenny Guy db.beginTransaction(); 988ed13187a745866483139e2878037e1f8427ce567Kenny Guy try { 9895d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal db.execSQL("ALTER TABLE favorites ADD COLUMN " 9905d85c44fd873c740dc191b28424c2ee367d730a2Sunny Goyal + columnName + " INTEGER NOT NULL DEFAULT " + defaultValue + ";"); 991ed13187a745866483139e2878037e1f8427ce567Kenny Guy db.setTransactionSuccessful(); 992ed13187a745866483139e2878037e1f8427ce567Kenny Guy } catch (SQLException ex) { 993ed13187a745866483139e2878037e1f8427ce567Kenny Guy Log.e(TAG, ex.getMessage(), ex); 994ed13187a745866483139e2878037e1f8427ce567Kenny Guy return false; 995ed13187a745866483139e2878037e1f8427ce567Kenny Guy } finally { 996ed13187a745866483139e2878037e1f8427ce567Kenny Guy db.endTransaction(); 997ed13187a745866483139e2878037e1f8427ce567Kenny Guy } 998ed13187a745866483139e2878037e1f8427ce567Kenny Guy return true; 999ed13187a745866483139e2878037e1f8427ce567Kenny Guy } 1000ed13187a745866483139e2878037e1f8427ce567Kenny Guy 1001a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka // Generates a new ID to use for an object in your database. This method should be only 1002a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka // called from the main UI thread. As an exception, we do call it when we call the 1003a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka // constructor from the worker thread; however, this doesn't extend until after the 1004a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp 1005a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka // after that point 10060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal @Override 1007dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen public long generateNewItemId() { 1008dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen if (mMaxItemId < 0) { 1009dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen throw new RuntimeException("Error: max item id was not initialized"); 1010a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka } 1011dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen mMaxItemId += 1; 1012dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen return mMaxItemId; 1013a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka } 1014a8c760d395e1d2a78522427738302fbca3a72453Michael Jurka 10150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal @Override 10160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal public long insertAndCheck(SQLiteDatabase db, ContentValues values) { 1017b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values); 10180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } 10190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal 10205dee7aff5fa8774d37977d12df7ce8986752321dChris Wren public void checkId(String table, ContentValues values) { 10215dee7aff5fa8774d37977d12df7ce8986752321dChris Wren long id = values.getAsLong(LauncherSettings.BaseLauncherColumns._ID); 1022b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (table == WorkspaceScreens.TABLE_NAME) { 10235dee7aff5fa8774d37977d12df7ce8986752321dChris Wren mMaxScreenId = Math.max(id, mMaxScreenId); 10245dee7aff5fa8774d37977d12df7ce8986752321dChris Wren } else { 10255dee7aff5fa8774d37977d12df7ce8986752321dChris Wren mMaxItemId = Math.max(id, mMaxItemId); 10265dee7aff5fa8774d37977d12df7ce8986752321dChris Wren } 10275dee7aff5fa8774d37977d12df7ce8986752321dChris Wren } 10285dee7aff5fa8774d37977d12df7ce8986752321dChris Wren 1029dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen private long initializeMaxItemId(SQLiteDatabase db) { 1030b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return getMaxId(db, Favorites.TABLE_NAME); 1031dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen } 1032dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen 1033dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen // Generates a new ID to use for an workspace screen in your database. This method 1034dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen // should be only called from the main UI thread. As an exception, we do call it when we 1035dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen // call the constructor from the worker thread; however, this doesn't extend until after the 1036dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp 1037dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen // after that point 1038dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen public long generateNewScreenId() { 1039dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen if (mMaxScreenId < 0) { 1040dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen throw new RuntimeException("Error: max screen id was not initialized"); 1041dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen } 1042dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen mMaxScreenId += 1; 1043dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen return mMaxScreenId; 1044dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen } 1045dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen 1046dcd297f05a866e07090d6e2af8fb4b15f28cb555Adam Cohen private long initializeMaxScreenId(SQLiteDatabase db) { 1047b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return getMaxId(db, WorkspaceScreens.TABLE_NAME); 10487ec3bbff8b6364dc609eb06ba85e6f3bb999c67eAdam Cohen } 10497ec3bbff8b6364dc609eb06ba85e6f3bb999c67eAdam Cohen 1050091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) { 105171483f417bb19f524cda41081f5ccac6084dc103Adam Cohen ArrayList<Long> screenIds = new ArrayList<Long>(); 10520fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal // TODO: Use multiple loaders with fall-back and transaction. 10530fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal int count = loader.loadLayout(db, screenIds); 105471483f417bb19f524cda41081f5ccac6084dc103Adam Cohen 105571483f417bb19f524cda41081f5ccac6084dc103Adam Cohen // Add the screens specified by the items above 105671483f417bb19f524cda41081f5ccac6084dc103Adam Cohen Collections.sort(screenIds); 105771483f417bb19f524cda41081f5ccac6084dc103Adam Cohen int rank = 0; 105871483f417bb19f524cda41081f5ccac6084dc103Adam Cohen ContentValues values = new ContentValues(); 105971483f417bb19f524cda41081f5ccac6084dc103Adam Cohen for (Long id : screenIds) { 106071483f417bb19f524cda41081f5ccac6084dc103Adam Cohen values.clear(); 106171483f417bb19f524cda41081f5ccac6084dc103Adam Cohen values.put(LauncherSettings.WorkspaceScreens._ID, id); 106271483f417bb19f524cda41081f5ccac6084dc103Adam Cohen values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank); 1063b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (dbInsertAndCheck(this, db, WorkspaceScreens.TABLE_NAME, null, values) < 0) { 106471483f417bb19f524cda41081f5ccac6084dc103Adam Cohen throw new RuntimeException("Failed initialize screen table" 106571483f417bb19f524cda41081f5ccac6084dc103Adam Cohen + "from default layout"); 106671483f417bb19f524cda41081f5ccac6084dc103Adam Cohen } 106771483f417bb19f524cda41081f5ccac6084dc103Adam Cohen rank++; 106871483f417bb19f524cda41081f5ccac6084dc103Adam Cohen } 106971483f417bb19f524cda41081f5ccac6084dc103Adam Cohen 107071483f417bb19f524cda41081f5ccac6084dc103Adam Cohen // Ensure that the max ids are initialized 107171483f417bb19f524cda41081f5ccac6084dc103Adam Cohen mMaxItemId = initializeMaxItemId(db); 107271483f417bb19f524cda41081f5ccac6084dc103Adam Cohen mMaxScreenId = initializeMaxScreenId(db); 10737ec3bbff8b6364dc609eb06ba85e6f3bb999c67eAdam Cohen 107471483f417bb19f524cda41081f5ccac6084dc103Adam Cohen return count; 107571483f417bb19f524cda41081f5ccac6084dc103Adam Cohen } 1076b87bd16c8e3f88a9ba78ed00c9f150b38dc39f33Mike Cleron } 1077c3a804042844dc4733b4bd4b6ac03bf4b2b015b7Daniel Lehmann 1078fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal /** 1079fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal * @return the max _id in the provided table. 1080fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal */ 1081091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen @Thunk static long getMaxId(SQLiteDatabase db, String table) { 1082fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal Cursor c = db.rawQuery("SELECT MAX(_id) FROM " + table, null); 1083fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal // get the result 1084fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal long id = -1; 1085fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal if (c != null && c.moveToNext()) { 1086fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal id = c.getLong(0); 1087fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal } 1088fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal if (c != null) { 1089fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal c.close(); 1090fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal } 1091fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal 1092fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal if (id == -1) { 1093fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal throw new RuntimeException("Error: could not query max id in " + table); 1094fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal } 1095fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal 1096fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal return id; 1097fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal } 1098fe4e4b91dc7db5d373690dd4bf2f3b5f1525b68aSunny Goyal 109931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project static class SqlArguments { 110031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public final String table; 110131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public final String where; 110231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project public final String[] args; 110331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 110431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments(Uri url, String where, String[] args) { 110531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (url.getPathSegments().size() == 1) { 110631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.table = url.getPathSegments().get(0); 110731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.where = where; 110831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.args = args; 110931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else if (url.getPathSegments().size() != 2) { 111031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new IllegalArgumentException("Invalid URI: " + url); 111131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else if (!TextUtils.isEmpty(where)) { 111231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new UnsupportedOperationException("WHERE clause not supported: " + url); 111331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 111431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.table = url.getPathSegments().get(0); 1115c3a804042844dc4733b4bd4b6ac03bf4b2b015b7Daniel Lehmann this.where = "_id=" + ContentUris.parseId(url); 111631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project this.args = null; 111731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 111831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 111931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 112031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project SqlArguments(Uri url) { 112131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project if (url.getPathSegments().size() == 1) { 112231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project table = url.getPathSegments().get(0); 112331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project where = null; 112431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project args = null; 112531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } else { 112631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project throw new IllegalArgumentException("Invalid URI: " + url); 112731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 112831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 112931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project } 1130b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 1131b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private static class ChangeListenerWrapper implements Handler.Callback { 1132b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 1133b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private static final int MSG_LAUNCHER_PROVIDER_CHANGED = 1; 1134b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private static final int MSG_EXTRACTED_COLORS_CHANGED = 2; 1135b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private static final int MSG_APP_WIDGET_HOST_RESET = 3; 1136b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 1137b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal private LauncherProviderChangeListener mListener; 1138b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal 1139b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal @Override 1140b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal public boolean handleMessage(Message msg) { 1141b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal if (mListener != null) { 1142b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal switch (msg.what) { 1143b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal case MSG_LAUNCHER_PROVIDER_CHANGED: 1144b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mListener.onLauncherProviderChange(); 1145b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal break; 1146b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal case MSG_EXTRACTED_COLORS_CHANGED: 1147b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal mListener.onExtractedColorsChanged(); 1148b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal break; 1149b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal case MSG_APP_WIDGET_HOST_RESET: 1150da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal Context context = (Context) msg.obj; 1151da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal if (context != null) { 1152da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal context.sendBroadcast(new Intent(Launcher.ACTION_APPWIDGET_HOST_RESET) 1153da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal .setPackage(context.getPackageName())); 1154da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal } 1155b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal break; 1156b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 1157b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 1158b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal return true; 1159b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 1160b5b55c8012c124182c1bd07bdd4be1e734d972d0Sunny Goyal } 116172960975d8367e7ce789d8a5b6f0763fb0ec78bfAdam Cohen} 1162