summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/LauncherProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/LauncherProvider.java')
-rw-r--r--src/com/android/launcher3/LauncherProvider.java1133
1 files changed, 428 insertions, 705 deletions
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 1715b02bf..cc5e18bc1 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,9 +16,9 @@
package com.android.launcher3;
+import android.annotation.TargetApi;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentProviderOperation;
@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
@@ -37,10 +38,13 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.net.Uri;
-import android.provider.Settings;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -50,52 +54,42 @@ import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.util.ManagedProfileHeuristic;
+import com.android.launcher3.util.Thunk;
import java.io.File;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
public class LauncherProvider extends ContentProvider {
private static final String TAG = "Launcher.LauncherProvider";
private static final boolean LOGD = false;
- private static final int DATABASE_VERSION = 20;
+ private static final int DATABASE_VERSION = 26;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
static final String AUTHORITY = ProviderConfig.AUTHORITY;
- // Should we attempt to load anything from the com.android.launcher2 provider?
- static final boolean IMPORT_LAUNCHER2_DATABASE = false;
-
- static final String TABLE_FAVORITES = "favorites";
- static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens";
- static final String PARAMETER_NOTIFY = "notify";
- static final String UPGRADED_FROM_OLD_DATABASE =
- "UPGRADED_FROM_OLD_DATABASE";
- static final String EMPTY_DATABASE_CREATED =
- "EMPTY_DATABASE_CREATED";
+ static final String TABLE_FAVORITES = LauncherSettings.Favorites.TABLE_NAME;
+ static final String TABLE_WORKSPACE_SCREENS = LauncherSettings.WorkspaceScreens.TABLE_NAME;
+ static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd";
- private LauncherProviderChangeListener mListener;
+ private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name";
- /**
- * {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
- * {@link AppWidgetHost#deleteHost()} is called during database creation.
- * Use this to recall {@link AppWidgetHost#startListening()} if needed.
- */
- static final Uri CONTENT_APPWIDGET_RESET_URI =
- Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
-
- private DatabaseHelper mOpenHelper;
- private static boolean sJustLoadedFromOldDb;
+ @Thunk LauncherProviderChangeListener mListener;
+ @Thunk DatabaseHelper mOpenHelper;
@Override
public boolean onCreate() {
final Context context = getContext();
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
mOpenHelper = new DatabaseHelper(context);
+ StrictMode.setThreadPolicy(oldPolicy);
LauncherAppState.setLauncherProvider(this);
return true;
}
@@ -106,6 +100,7 @@ public class LauncherProvider extends ContentProvider {
public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) {
mListener = listener;
+ mOpenHelper.mListener = mListener;
}
@Override
@@ -133,7 +128,7 @@ public class LauncherProvider extends ContentProvider {
return result;
}
- private static long dbInsertAndCheck(DatabaseHelper helper,
+ @Thunk static long dbInsertAndCheck(DatabaseHelper helper,
SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
if (values == null) {
throw new RuntimeException("Error: attempting to insert null values");
@@ -151,7 +146,8 @@ public class LauncherProvider extends ContentProvider {
// In very limited cases, we support system|signature permission apps to add to the db
String externalAdd = uri.getQueryParameter(URI_PARAM_IS_EXTERNAL_ADD);
- if (externalAdd != null && "true".equals(externalAdd)) {
+ final boolean isExternalAll = externalAdd != null && "true".equals(externalAdd);
+ if (isExternalAll) {
if (!mOpenHelper.initializeExternalAdd(initialValues)) {
return null;
}
@@ -160,10 +156,17 @@ public class LauncherProvider extends ContentProvider {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
addModifiedTime(initialValues);
final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
- if (rowId <= 0) return null;
+ if (rowId < 0) return null;
uri = ContentUris.withAppendedId(uri, rowId);
- sendNotify(uri);
+ notifyListeners();
+
+ if (isExternalAll) {
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app != null) {
+ app.reloadWorkspace();
+ }
+ }
return uri;
}
@@ -188,7 +191,7 @@ public class LauncherProvider extends ContentProvider {
db.endTransaction();
}
- sendNotify(uri);
+ notifyListeners();
return values.length;
}
@@ -212,7 +215,7 @@ public class LauncherProvider extends ContentProvider {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count = db.delete(args.table, args.where, args.args);
- if (count > 0) sendNotify(uri);
+ if (count > 0) notifyListeners();
return count;
}
@@ -224,17 +227,80 @@ public class LauncherProvider extends ContentProvider {
addModifiedTime(values);
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count = db.update(args.table, values, args.where, args.args);
- if (count > 0) sendNotify(uri);
+ if (count > 0) notifyListeners();
return count;
}
- private void sendNotify(Uri uri) {
- String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
- if (notify == null || "true".equals(notify)) {
- getContext().getContentResolver().notifyChange(uri, null);
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ if (Binder.getCallingUid() != Process.myUid()) {
+ return null;
+ }
+
+ switch (method) {
+ case LauncherSettings.Settings.METHOD_GET_BOOLEAN: {
+ Bundle result = new Bundle();
+ result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
+ getContext().getSharedPreferences(
+ LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE)
+ .getBoolean(arg, extras.getBoolean(
+ LauncherSettings.Settings.EXTRA_DEFAULT_VALUE)));
+ return result;
+ }
+ case LauncherSettings.Settings.METHOD_SET_BOOLEAN: {
+ boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
+ getContext().getSharedPreferences(
+ LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE)
+ .edit().putBoolean(arg, value).apply();
+ if (mListener != null) {
+ mListener.onSettingsChanged(arg, value);
+ }
+ Bundle result = new Bundle();
+ result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, value);
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Deletes any empty folder from the DB.
+ * @return Ids of deleted folders.
+ */
+ public List<Long> deleteEmptyFolders() {
+ ArrayList<Long> folderIds = new ArrayList<Long>();
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ // Select folders whose id do not match any container value.
+ String selection = LauncherSettings.Favorites.ITEM_TYPE + " = "
+ + LauncherSettings.Favorites.ITEM_TYPE_FOLDER + " AND "
+ + LauncherSettings.Favorites._ID + " NOT IN (SELECT " +
+ LauncherSettings.Favorites.CONTAINER + " FROM "
+ + TABLE_FAVORITES + ")";
+ Cursor c = db.query(TABLE_FAVORITES,
+ new String[] {LauncherSettings.Favorites._ID},
+ selection, null, null, null, null);
+ while (c.moveToNext()) {
+ folderIds.add(c.getLong(0));
+ }
+ c.close();
+ if (folderIds.size() > 0) {
+ db.delete(TABLE_FAVORITES, Utilities.createDbSelectionQuery(
+ LauncherSettings.Favorites._ID, folderIds), null);
+ }
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ folderIds.clear();
+ } finally {
+ db.endTransaction();
}
+ return folderIds;
+ }
+ private void notifyListeners() {
// always notify the backup agent
LauncherBackupAgentHelper.dataChanged(getContext());
if (mListener != null) {
@@ -242,7 +308,7 @@ public class LauncherProvider extends ContentProvider {
}
}
- private void addModifiedTime(ContentValues values) {
+ @Thunk static void addModifiedTime(ContentValues values) {
values.put(LauncherSettings.ChangeLogColumns.MODIFIED, System.currentTimeMillis());
}
@@ -258,32 +324,6 @@ public class LauncherProvider extends ContentProvider {
return mOpenHelper.generateNewScreenId();
}
- // This is only required one time while loading the workspace during the
- // upgrade path, and should never be called from anywhere else.
- public void updateMaxScreenId(long maxScreenId) {
- mOpenHelper.updateMaxScreenId(maxScreenId);
- }
-
- /**
- * @param Should we load the old db for upgrade? first run only.
- */
- synchronized public boolean justLoadedOldDb() {
- String spKey = LauncherAppState.getSharedPreferencesKey();
- SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
-
- boolean loadedOldDb = false || sJustLoadedFromOldDb;
-
- sJustLoadedFromOldDb = false;
- if (sp.getBoolean(UPGRADED_FROM_OLD_DATABASE, false)) {
-
- SharedPreferences.Editor editor = sp.edit();
- editor.remove(UPGRADED_FROM_OLD_DATABASE);
- editor.commit();
- loadedOldDb = true;
- }
- return loadedOldDb;
- }
-
/**
* Clears all the data for a fresh start.
*/
@@ -301,9 +341,10 @@ public class LauncherProvider extends ContentProvider {
/**
* Loads the default workspace based on the following priority scheme:
- * 1) From a package provided by play store
- * 2) From a partner configuration APK, already in the system image
- * 3) The default configuration for the particular device
+ * 1) From the app restrictions
+ * 2) From a package provided by play store
+ * 3) From a partner configuration APK, already in the system image
+ * 4) The default configuration for the particular device
*/
synchronized public void loadDefaultFavoritesIfNecessary() {
String spKey = LauncherAppState.getSharedPreferencesKey();
@@ -312,9 +353,11 @@ public class LauncherProvider extends ContentProvider {
if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
Log.d(TAG, "loading default workspace");
- AutoInstallsLayout loader = AutoInstallsLayout.get(getContext(),
- mOpenHelper.mAppWidgetHost, mOpenHelper);
-
+ AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction();
+ if (loader == null) {
+ loader = AutoInstallsLayout.get(getContext(),
+ mOpenHelper.mAppWidgetHost, mOpenHelper);
+ }
if (loader == null) {
final Partner partner = Partner.get(getContext().getPackageManager());
if (partner != null && partner.hasDefaultLayout()) {
@@ -332,6 +375,10 @@ public class LauncherProvider extends ContentProvider {
if (loader == null) {
loader = getDefaultLayoutParser();
}
+
+ // There might be some partially restored DB items, due to buggy restore logic in
+ // previous versions of launcher.
+ createEmptyDB();
// Populate favorites table with initial favorites
if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
&& usingExternallyProvidedLayout) {
@@ -344,9 +391,43 @@ public class LauncherProvider extends ContentProvider {
}
}
+ /**
+ * Creates workspace loader from an XML resource listed in the app restrictions.
+ *
+ * @return the loader if the restrictions are set and the resource exists; null otherwise.
+ */
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+ private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction() {
+ // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18
+ if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ return null;
+ }
+
+ Context ctx = getContext();
+ UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
+ Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
+ if (bundle == null) {
+ return null;
+ }
+
+ String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
+ if (packageName != null) {
+ try {
+ Resources targetResources = ctx.getPackageManager()
+ .getResourcesForApplication(packageName);
+ return AutoInstallsLayout.get(ctx, packageName, targetResources,
+ mOpenHelper.mAppWidgetHost, mOpenHelper);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Target package for restricted profile not found", e);
+ return null;
+ }
+ }
+ return null;
+ }
+
private DefaultLayoutParser getDefaultLayoutParser() {
int defaultLayout = LauncherAppState.getInstance()
- .getDynamicGrid().getDeviceProfile().defaultLayoutId;
+ .getInvariantDeviceProfile().defaultLayoutId;
return new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
mOpenHelper, getContext().getResources(), defaultLayout);
}
@@ -356,17 +437,15 @@ public class LauncherProvider extends ContentProvider {
Uri.parse(getContext().getString(R.string.old_launcher_provider_uri)));
}
- private static interface ContentValuesCallback {
- public void onRow(ContentValues values);
+ public void updateFolderItemsRank() {
+ mOpenHelper.updateFolderItemsRank(mOpenHelper.getWritableDatabase(), false);
}
- private static boolean shouldImportLauncher2Database(Context context) {
- boolean isTablet = context.getResources().getBoolean(R.bool.is_tablet);
-
- // We don't import the old databse for tablets, as the grid size has changed.
- return !isTablet && IMPORT_LAUNCHER2_DATABASE;
+ public void convertShortcutsToLauncherActivities() {
+ mOpenHelper.convertShortcutsToLauncherActivities(mOpenHelper.getWritableDatabase());
}
+
public void deleteDatabase() {
// Are you sure? (y/n)
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -376,16 +455,19 @@ public class LauncherProvider extends ContentProvider {
SQLiteDatabase.deleteDatabase(dbFile);
}
mOpenHelper = new DatabaseHelper(getContext());
+ mOpenHelper.mListener = mListener;
}
private static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback {
private final Context mContext;
- private final AppWidgetHost mAppWidgetHost;
+ @Thunk final AppWidgetHost mAppWidgetHost;
private long mMaxItemId = -1;
private long mMaxScreenId = -1;
private boolean mNewDbCreated = false;
+ @Thunk LauncherProviderChangeListener mListener;
+
DatabaseHelper(Context context) {
super(context, LauncherFiles.LAUNCHER_DB, null, DATABASE_VERSION);
mContext = context;
@@ -405,17 +487,6 @@ public class LauncherProvider extends ContentProvider {
return mNewDbCreated;
}
- /**
- * Send notification that we've deleted the {@link AppWidgetHost},
- * probably as part of the initial database creation. The receiver may
- * want to re-call {@link AppWidgetHost#startListening()} to ensure
- * callbacks are correctly set.
- */
- private void sendAppWidgetResetNotify() {
- final ContentResolver resolver = mContext.getContentResolver();
- resolver.notifyChange(CONTENT_APPWIDGET_RESET_URI, null);
- }
-
@Override
public void onCreate(SQLiteDatabase db) {
if (LOGD) Log.d(TAG, "creating new launcher database");
@@ -450,53 +521,44 @@ public class LauncherProvider extends ContentProvider {
"appWidgetProvider TEXT," +
"modified INTEGER NOT NULL DEFAULT 0," +
"restored INTEGER NOT NULL DEFAULT 0," +
- "profileId INTEGER DEFAULT " + userSerialNumber +
+ "profileId INTEGER DEFAULT " + userSerialNumber + "," +
+ "rank INTEGER NOT NULL DEFAULT 0," +
+ "options INTEGER NOT NULL DEFAULT 0" +
");");
addWorkspacesTable(db);
// Database was just created, so wipe any previous widgets
if (mAppWidgetHost != null) {
mAppWidgetHost.deleteHost();
- sendAppWidgetResetNotify();
- }
- if (shouldImportLauncher2Database(mContext)) {
- // Try converting the old database
- ContentValuesCallback permuteScreensCb = new ContentValuesCallback() {
- public void onRow(ContentValues values) {
- int container = values.getAsInteger(LauncherSettings.Favorites.CONTAINER);
- if (container == Favorites.CONTAINER_DESKTOP) {
- int screen = values.getAsInteger(LauncherSettings.Favorites.SCREEN);
- screen = (int) upgradeLauncherDb_permuteScreens(screen);
- values.put(LauncherSettings.Favorites.SCREEN, screen);
+ /**
+ * Send notification that we've deleted the {@link AppWidgetHost},
+ * probably as part of the initial database creation. The receiver may
+ * want to re-call {@link AppWidgetHost#startListening()} to ensure
+ * callbacks are correctly set.
+ */
+ new MainThreadExecutor().execute(new Runnable() {
+
+ @Override
+ public void run() {
+ if (mListener != null) {
+ mListener.onAppWidgetHostReset();
}
}
- };
- Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
- "/old_favorites?notify=true");
- if (!convertDatabase(db, uri, permuteScreensCb, true)) {
- // Try and upgrade from the Launcher2 db
- uri = Uri.parse(mContext.getString(R.string.old_launcher_provider_uri));
- if (!convertDatabase(db, uri, permuteScreensCb, false)) {
- // If we fail, then set a flag to load the default workspace
- setFlagEmptyDbCreated();
- return;
- }
- }
- // Right now, in non-default workspace cases, we want to run the final
- // upgrade code (ie. to fix workspace screen indices -> ids, etc.), so
- // set that flag too.
- setFlagJustLoadedOldDb();
- } else {
- // Fresh and clean launcher DB.
- mMaxItemId = initializeMaxItemId(db);
- setFlagEmptyDbCreated();
+ });
}
+
+ // Fresh and clean launcher DB.
+ mMaxItemId = initializeMaxItemId(db);
+ setFlagEmptyDbCreated();
+
+ // When a new DB is created, remove all previously stored managed profile information.
+ ManagedProfileHeuristic.processAllUsers(Collections.<UserHandleCompat>emptyList(), mContext);
}
private void addWorkspacesTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_WORKSPACE_SCREENS + " (" +
- LauncherSettings.WorkspaceScreens._ID + " INTEGER," +
+ LauncherSettings.WorkspaceScreens._ID + " INTEGER PRIMARY KEY," +
LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," +
LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" +
");");
@@ -536,333 +598,120 @@ public class LauncherProvider extends ContentProvider {
private void setFlagJustLoadedOldDb() {
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, true);
- editor.putBoolean(EMPTY_DATABASE_CREATED, false);
- editor.commit();
+ sp.edit().putBoolean(EMPTY_DATABASE_CREATED, false).commit();
}
private void setFlagEmptyDbCreated() {
String spKey = LauncherAppState.getSharedPreferencesKey();
SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sp.edit();
- editor.putBoolean(EMPTY_DATABASE_CREATED, true);
- editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, false);
- editor.commit();
- }
-
- // We rearrange the screens from the old launcher
- // 12345 -> 34512
- private long upgradeLauncherDb_permuteScreens(long screen) {
- if (screen >= 2) {
- return screen - 2;
- } else {
- return screen + 3;
- }
- }
-
- private boolean convertDatabase(SQLiteDatabase db, Uri uri,
- ContentValuesCallback cb, boolean deleteRows) {
- if (LOGD) Log.d(TAG, "converting database from an older format, but not onUpgrade");
- boolean converted = false;
-
- final ContentResolver resolver = mContext.getContentResolver();
- Cursor cursor = null;
-
- try {
- cursor = resolver.query(uri, null, null, null, null);
- } catch (Exception e) {
- // Ignore
- }
-
- // We already have a favorites database in the old provider
- if (cursor != null) {
- try {
- if (cursor.getCount() > 0) {
- converted = copyFromCursor(db, cursor, cb) > 0;
- if (converted && deleteRows) {
- resolver.delete(uri, null, null);
- }
- }
- } finally {
- cursor.close();
- }
- }
-
- if (converted) {
- // Convert widgets from this import into widgets
- if (LOGD) Log.d(TAG, "converted and now triggering widget upgrade");
- convertWidgets(db);
-
- // Update max item id
- mMaxItemId = initializeMaxItemId(db);
- if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId);
- }
-
- return converted;
- }
-
- private int copyFromCursor(SQLiteDatabase db, Cursor c, ContentValuesCallback cb) {
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
- final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
- final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
- final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
- final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
- final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
- final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
- final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
- final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
- final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
- final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
-
- ContentValues[] rows = new ContentValues[c.getCount()];
- int i = 0;
- while (c.moveToNext()) {
- ContentValues values = new ContentValues(c.getColumnCount());
- values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
- values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
- values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
- values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
- values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
- values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
- values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
- values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
- values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
- values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
- values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
- values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
- values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
- values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
- values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
- if (cb != null) {
- cb.onRow(values);
- }
- rows[i++] = values;
- }
-
- int total = 0;
- if (i > 0) {
- db.beginTransaction();
- try {
- int numValues = rows.length;
- for (i = 0; i < numValues; i++) {
- if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) {
- return 0;
- } else {
- total++;
- }
- }
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- return total;
+ sp.edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
-
- int version = oldVersion;
- if (version < 3) {
- // upgrade 1,2 -> 3 added appWidgetId column
- db.beginTransaction();
- try {
- // Insert new column for holding appWidgetIds
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
- db.setTransactionSuccessful();
- version = 3;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
+ switch (oldVersion) {
+ // The version cannot be lower that 12, as Launcher3 never supported a lower
+ // version of the DB.
+ case 12: {
+ // With the new shrink-wrapped and re-orderable workspaces, it makes sense
+ // to persist workspace screens and their relative order.
+ mMaxScreenId = 0;
+ addWorkspacesTable(db);
}
-
- // Convert existing widgets only if table upgrade was successful
- if (version == 3) {
- convertWidgets(db);
+ case 13: {
+ db.beginTransaction();
+ try {
+ // Insert new column for holding widget provider name
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN appWidgetProvider TEXT;");
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ } finally {
+ db.endTransaction();
+ }
}
- }
-
- if (version < 4) {
- version = 4;
- }
-
- // Where's version 5?
- // - Donut and sholes on 2.0 shipped with version 4 of launcher1.
- // - Passion shipped on 2.1 with version 6 of launcher3
- // - Sholes shipped on 2.1r1 (aka Mr. 3) with version 5 of launcher 1
- // but version 5 on there was the updateContactsShortcuts change
- // which was version 6 in launcher 2 (first shipped on passion 2.1r1).
- // The updateContactsShortcuts change is idempotent, so running it twice
- // is okay so we'll do that when upgrading the devices that shipped with it.
- if (version < 6) {
- // We went from 3 to 5 screens. Move everything 1 to the right
- db.beginTransaction();
- try {
- db.execSQL("UPDATE favorites SET screen=(screen + 1);");
- db.setTransactionSuccessful();
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
+ case 14: {
+ db.beginTransaction();
+ try {
+ // Insert new column for holding update timestamp
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+ db.execSQL("ALTER TABLE workspaceScreens " +
+ "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ } finally {
+ db.endTransaction();
+ }
}
-
- // We added the fast track.
- if (updateContactsShortcuts(db)) {
- version = 6;
+ case 15: {
+ if (!addIntegerColumn(db, Favorites.RESTORED, 0)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
}
- }
-
- if (version < 7) {
- // Version 7 gets rid of the special search widget.
- convertWidgets(db);
- version = 7;
- }
-
- if (version < 8) {
- // Version 8 (froyo) has the icons all normalized. This should
- // already be the case in practice, but we now rely on it and don't
- // resample the images each time.
- normalizeIcons(db);
- version = 8;
- }
-
- if (version < 9) {
- // The max id is not yet set at this point (onUpgrade is triggered in the ctor
- // before it gets a change to get set, so we need to read it here when we use it)
- if (mMaxItemId == -1) {
- mMaxItemId = initializeMaxItemId(db);
+ case 16: {
+ // We use the db version upgrade here to identify users who may not have seen
+ // clings yet (because they weren't available), but for whom the clings are now
+ // available (tablet users). Because one of the possible cling flows (migration)
+ // is very destructive (wipes out workspaces), we want to prevent this from showing
+ // until clear data. We do so by marking that the clings have been shown.
+ LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
}
-
- // Add default hotseat icons
- loadFavorites(db, new DefaultLayoutParser(mContext, mAppWidgetHost, this,
- mContext.getResources(), R.xml.update_workspace));
- version = 9;
- }
-
- // We bumped the version three time during JB, once to update the launch flags, once to
- // update the override for the default launch animation and once to set the mimetype
- // to improve startup performance
- if (version < 12) {
- // Contact shortcuts need a different set of flags to be launched now
- // The updateContactsShortcuts change is idempotent, so we can keep using it like
- // back in the Donut days
- updateContactsShortcuts(db);
- version = 12;
- }
-
- if (version < 13) {
- // With the new shrink-wrapped and re-orderable workspaces, it makes sense
- // to persist workspace screens and their relative order.
- mMaxScreenId = 0;
-
- // This will never happen in the wild, but when we switch to using workspace
- // screen ids, redo the import from old launcher.
- sJustLoadedFromOldDb = true;
-
- addWorkspacesTable(db);
- version = 13;
- }
-
- if (version < 14) {
- db.beginTransaction();
- try {
- // Insert new column for holding widget provider name
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN appWidgetProvider TEXT;");
- db.setTransactionSuccessful();
- version = 14;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
+ case 17: {
+ // No-op
}
- }
-
- if (version < 15) {
- db.beginTransaction();
- try {
- // Insert new column for holding update timestamp
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
- db.execSQL("ALTER TABLE workspaceScreens " +
- "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
- db.setTransactionSuccessful();
- version = 15;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
+ case 18: {
+ // Due to a data loss bug, some users may have items associated with screen ids
+ // which no longer exist. Since this can cause other problems, and since the user
+ // will never see these items anyway, we use database upgrade as an opportunity to
+ // clean things up.
+ removeOrphanedItems(db);
}
- }
-
-
- if (version < 16) {
- db.beginTransaction();
- try {
- // Insert new column for holding restore status
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN restored INTEGER NOT NULL DEFAULT 0;");
- db.setTransactionSuccessful();
- version = 16;
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- } finally {
- db.endTransaction();
+ case 19: {
+ // Add userId column
+ if (!addProfileColumn(db)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
}
- }
-
- if (version < 17) {
- // We use the db version upgrade here to identify users who may not have seen
- // clings yet (because they weren't available), but for whom the clings are now
- // available (tablet users). Because one of the possible cling flows (migration)
- // is very destructive (wipes out workspaces), we want to prevent this from showing
- // until clear data. We do so by marking that the clings have been shown.
- LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
- version = 17;
- }
-
- if (version < 18) {
- // No-op
- version = 18;
- }
-
- if (version < 19) {
- // Due to a data loss bug, some users may have items associated with screen ids
- // which no longer exist. Since this can cause other problems, and since the user
- // will never see these items anyway, we use database upgrade as an opportunity to
- // clean things up.
- removeOrphanedItems(db);
- version = 19;
- }
-
- if (version < 20) {
- // Add userId column
- if (addProfileColumn(db)) {
- version = 20;
+ case 20:
+ if (!updateFolderItemsRank(db, true)) {
+ break;
+ }
+ case 21:
+ // Recreate workspace table with screen id a primary key
+ if (!recreateWorkspaceTable(db)) {
+ break;
+ }
+ case 22: {
+ if (!addIntegerColumn(db, Favorites.OPTIONS, 0)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 23:
+ // No-op
+ case 24:
+ ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext);
+ case 25:
+ convertShortcutsToLauncherActivities(db);
+ case 26: {
+ // DB Upgraded successfully
+ return;
}
- // else old version remains, which means we wipe old data
}
- if (version != DATABASE_VERSION) {
- Log.w(TAG, "Destroying all old data.");
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS);
-
- onCreate(db);
- }
+ // DB was not upgraded
+ Log.w(TAG, "Destroying all old data.");
+ createEmptyDB(db);
}
@Override
@@ -873,7 +722,6 @@ public class LauncherProvider extends ContentProvider {
createEmptyDB(db);
}
-
/**
* Clears all the data for a fresh start.
*/
@@ -883,20 +731,102 @@ public class LauncherProvider extends ContentProvider {
onCreate(db);
}
- private boolean addProfileColumn(SQLiteDatabase db) {
+ /**
+ * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
+ * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
+ */
+ @Thunk void convertShortcutsToLauncherActivities(SQLiteDatabase db) {
db.beginTransaction();
+ Cursor c = null;
+ SQLiteStatement updateStmt = null;
+
try {
- UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
- // Default to the serial number of this user, for older
- // shortcuts.
- long userSerialNumber = userManager.getSerialNumberForUser(
- UserHandleCompat.myUserHandle());
- // Insert new column for holding user serial number
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN profileId INTEGER DEFAULT "
- + userSerialNumber + ";");
+ // Only consider the primary user as other users can't have a shortcut.
+ long userSerial = UserManagerCompat.getInstance(mContext)
+ .getSerialNumberForUser(UserHandleCompat.myUserHandle());
+ c = db.query(TABLE_FAVORITES, new String[] {
+ Favorites._ID,
+ Favorites.INTENT,
+ }, "itemType=" + Favorites.ITEM_TYPE_SHORTCUT + " AND profileId=" + userSerial,
+ null, null, null, null);
+
+ updateStmt = db.compileStatement("UPDATE favorites SET itemType="
+ + Favorites.ITEM_TYPE_APPLICATION + " WHERE _id=?");
+
+ final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
+ final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
+
+ while (c.moveToNext()) {
+ String intentDescription = c.getString(intentIndex);
+ Intent intent;
+ try {
+ intent = Intent.parseUri(intentDescription, 0);
+ } catch (URISyntaxException e) {
+ Log.e(TAG, "Unable to parse intent", e);
+ continue;
+ }
+
+ if (!Utilities.isLauncherAppTarget(intent)) {
+ continue;
+ }
+
+ long id = c.getLong(idIndex);
+ updateStmt.bindLong(1, id);
+ updateStmt.executeUpdateDelete();
+ }
db.setTransactionSuccessful();
} catch (SQLException ex) {
+ Log.w(TAG, "Error deduping shortcuts", ex);
+ } finally {
+ db.endTransaction();
+ if (c != null) {
+ c.close();
+ }
+ if (updateStmt != null) {
+ updateStmt.close();
+ }
+ }
+ }
+
+ /**
+ * Recreates workspace table and migrates data to the new table.
+ */
+ public boolean recreateWorkspaceTable(SQLiteDatabase db) {
+ db.beginTransaction();
+ try {
+ Cursor c = db.query(TABLE_WORKSPACE_SCREENS,
+ new String[] {LauncherSettings.WorkspaceScreens._ID},
+ null, null, null, null,
+ LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+ ArrayList<Long> sortedIDs = new ArrayList<Long>();
+ long maxId = 0;
+ try {
+ while (c.moveToNext()) {
+ Long id = c.getLong(0);
+ if (!sortedIDs.contains(id)) {
+ sortedIDs.add(id);
+ maxId = Math.max(maxId, id);
+ }
+ }
+ } finally {
+ c.close();
+ }
+
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS);
+ addWorkspacesTable(db);
+
+ // Add all screen ids back
+ int total = sortedIDs.size();
+ for (int i = 0; i < total; i++) {
+ ContentValues values = new ContentValues();
+ values.put(LauncherSettings.WorkspaceScreens._ID, sortedIDs.get(i));
+ values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
+ addModifiedTime(values);
+ db.insertOrThrow(TABLE_WORKSPACE_SCREENS, null, values);
+ }
+ db.setTransactionSuccessful();
+ mMaxScreenId = maxId;
+ } catch (SQLException ex) {
// Old version remains, which means we wipe old data
Log.e(TAG, ex.getMessage(), ex);
return false;
@@ -906,140 +836,60 @@ public class LauncherProvider extends ContentProvider {
return true;
}
- private boolean updateContactsShortcuts(SQLiteDatabase db) {
- final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
- new int[] { Favorites.ITEM_TYPE_SHORTCUT });
-
- Cursor c = null;
- final String actionQuickContact = "com.android.contacts.action.QUICK_CONTACT";
+ @Thunk boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
db.beginTransaction();
try {
- // Select and iterate through each matching widget
- c = db.query(TABLE_FAVORITES,
- new String[] { Favorites._ID, Favorites.INTENT },
- selectWhere, null, null, null, null);
- if (c == null) return false;
-
- if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
+ if (addRankColumn) {
+ // Insert new column for holding rank
+ db.execSQL("ALTER TABLE favorites ADD COLUMN rank INTEGER NOT NULL DEFAULT 0;");
+ }
- final int idIndex = c.getColumnIndex(Favorites._ID);
- final int intentIndex = c.getColumnIndex(Favorites.INTENT);
+ // Get a map for folder ID to folder width
+ Cursor c = db.rawQuery("SELECT container, MAX(cellX) FROM favorites"
+ + " WHERE container IN (SELECT _id FROM favorites WHERE itemType = ?)"
+ + " GROUP BY container;",
+ new String[] {Integer.toString(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)});
while (c.moveToNext()) {
- long favoriteId = c.getLong(idIndex);
- final String intentUri = c.getString(intentIndex);
- if (intentUri != null) {
- try {
- final Intent intent = Intent.parseUri(intentUri, 0);
- android.util.Log.d("Home", intent.toString());
- final Uri uri = intent.getData();
- if (uri != null) {
- final String data = uri.toString();
- if ((Intent.ACTION_VIEW.equals(intent.getAction()) ||
- actionQuickContact.equals(intent.getAction())) &&
- (data.startsWith("content://contacts/people/") ||
- data.startsWith("content://com.android.contacts/" +
- "contacts/lookup/"))) {
-
- final Intent newIntent = new Intent(actionQuickContact);
- // When starting from the launcher, start in a new, cleared task
- // CLEAR_WHEN_TASK_RESET cannot reset the root of a task, so we
- // clear the whole thing preemptively here since
- // QuickContactActivity will finish itself when launching other
- // detail activities.
- newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_CLEAR_TASK);
- newIntent.putExtra(
- Launcher.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
- newIntent.setData(uri);
- // Determine the type and also put that in the shortcut
- // (that can speed up launch a bit)
- newIntent.setDataAndType(uri, newIntent.resolveType(mContext));
-
- final ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.INTENT,
- newIntent.toUri(0));
-
- String updateWhere = Favorites._ID + "=" + favoriteId;
- db.update(TABLE_FAVORITES, values, updateWhere, null);
- }
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Problem upgrading shortcut", ex);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Problem upgrading shortcut", e);
- }
- }
+ db.execSQL("UPDATE favorites SET rank=cellX+(cellY*?) WHERE "
+ + "container=? AND cellX IS NOT NULL AND cellY IS NOT NULL;",
+ new Object[] {c.getLong(1) + 1, c.getLong(0)});
}
+ c.close();
db.setTransactionSuccessful();
} catch (SQLException ex) {
- Log.w(TAG, "Problem while upgrading contacts", ex);
+ // Old version remains, which means we wipe old data
+ Log.e(TAG, ex.getMessage(), ex);
return false;
} finally {
db.endTransaction();
- if (c != null) {
- c.close();
- }
}
-
return true;
}
- private void normalizeIcons(SQLiteDatabase db) {
- Log.d(TAG, "normalizing icons");
+ private boolean addProfileColumn(SQLiteDatabase db) {
+ UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
+ // Default to the serial number of this user, for older
+ // shortcuts.
+ long userSerialNumber = userManager.getSerialNumberForUser(
+ UserHandleCompat.myUserHandle());
+ return addIntegerColumn(db, Favorites.PROFILE_ID, userSerialNumber);
+ }
+ private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) {
db.beginTransaction();
- Cursor c = null;
- SQLiteStatement update = null;
try {
- boolean logged = false;
- update = db.compileStatement("UPDATE favorites "
- + "SET icon=? WHERE _id=?");
-
- c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" +
- Favorites.ICON_TYPE_BITMAP, null);
-
- final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
- final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
-
- while (c.moveToNext()) {
- long id = c.getLong(idIndex);
- byte[] data = c.getBlob(iconIndex);
- try {
- Bitmap bitmap = Utilities.createIconBitmap(
- BitmapFactory.decodeByteArray(data, 0, data.length),
- mContext);
- if (bitmap != null) {
- update.bindLong(1, id);
- data = ItemInfo.flattenBitmap(bitmap);
- if (data != null) {
- update.bindBlob(2, data);
- update.execute();
- }
- bitmap.recycle();
- }
- } catch (Exception e) {
- if (!logged) {
- Log.e(TAG, "Failed normalizing icon " + id, e);
- } else {
- Log.e(TAG, "Also failed normalizing icon " + id);
- }
- logged = true;
- }
- }
+ db.execSQL("ALTER TABLE favorites ADD COLUMN "
+ + columnName + " INTEGER NOT NULL DEFAULT " + defaultValue + ";");
db.setTransactionSuccessful();
} catch (SQLException ex) {
- Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
+ Log.e(TAG, ex.getMessage(), ex);
+ return false;
} finally {
db.endTransaction();
- if (update != null) {
- update.close();
- }
- if (c != null) {
- c.close();
- }
}
+ return true;
}
// Generates a new ID to use for an object in your database. This method should be only
@@ -1075,23 +925,7 @@ public class LauncherProvider extends ContentProvider {
}
private long initializeMaxItemId(SQLiteDatabase db) {
- Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null);
-
- // get the result
- final int maxIdIndex = 0;
- long id = -1;
- if (c != null && c.moveToNext()) {
- id = c.getLong(maxIdIndex);
- }
- if (c != null) {
- c.close();
- }
-
- if (id == -1) {
- throw new RuntimeException("Error: could not query max item id");
- }
-
- return id;
+ return getMaxId(db, TABLE_FAVORITES);
}
// Generates a new ID to use for an workspace screen in your database. This method
@@ -1104,128 +938,14 @@ public class LauncherProvider extends ContentProvider {
throw new RuntimeException("Error: max screen id was not initialized");
}
mMaxScreenId += 1;
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - generateNewScreenId(): " + mMaxScreenId, true);
return mMaxScreenId;
}
- public void updateMaxScreenId(long maxScreenId) {
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - updateMaxScreenId(): " + maxScreenId, true);
- mMaxScreenId = maxScreenId;
- }
-
private long initializeMaxScreenId(SQLiteDatabase db) {
- Cursor c = db.rawQuery("SELECT MAX(" + LauncherSettings.WorkspaceScreens._ID + ") FROM " + TABLE_WORKSPACE_SCREENS, null);
-
- // get the result
- final int maxIdIndex = 0;
- long id = -1;
- if (c != null && c.moveToNext()) {
- id = c.getLong(maxIdIndex);
- }
- if (c != null) {
- c.close();
- }
-
- if (id == -1) {
- throw new RuntimeException("Error: could not query max screen id");
- }
-
- // Log to disk
- Launcher.addDumpLog(TAG, "11683562 - initializeMaxScreenId(): " + id, true);
- return id;
+ return getMaxId(db, TABLE_WORKSPACE_SCREENS);
}
- /**
- * Upgrade existing clock and photo frame widgets into their new widget
- * equivalents.
- */
- private void convertWidgets(SQLiteDatabase db) {
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
- final int[] bindSources = new int[] {
- Favorites.ITEM_TYPE_WIDGET_CLOCK,
- Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
- Favorites.ITEM_TYPE_WIDGET_SEARCH,
- };
-
- final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
-
- Cursor c = null;
-
- db.beginTransaction();
- try {
- // Select and iterate through each matching widget
- c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID, Favorites.ITEM_TYPE },
- selectWhere, null, null, null, null);
-
- if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
-
- final ContentValues values = new ContentValues();
- while (c != null && c.moveToNext()) {
- long favoriteId = c.getLong(0);
- int favoriteType = c.getInt(1);
-
- // Allocate and update database with new appWidgetId
- try {
- int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
- if (LOGD) {
- Log.d(TAG, "allocated appWidgetId=" + appWidgetId
- + " for favoriteId=" + favoriteId);
- }
- values.clear();
- values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
- values.put(Favorites.APPWIDGET_ID, appWidgetId);
-
- // Original widgets might not have valid spans when upgrading
- if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
- values.put(LauncherSettings.Favorites.SPANX, 4);
- values.put(LauncherSettings.Favorites.SPANY, 1);
- } else {
- values.put(LauncherSettings.Favorites.SPANX, 2);
- values.put(LauncherSettings.Favorites.SPANY, 2);
- }
-
- String updateWhere = Favorites._ID + "=" + favoriteId;
- db.update(TABLE_FAVORITES, values, updateWhere, null);
-
- if (favoriteType == Favorites.ITEM_TYPE_WIDGET_CLOCK) {
- // TODO: check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- new ComponentName("com.android.alarmclock",
- "com.android.alarmclock.AnalogAppWidgetProvider"));
- } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
- // TODO: check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- new ComponentName("com.android.camera",
- "com.android.camera.PhotoAppWidgetProvider"));
- } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
- // TODO: check return value
- appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
- getSearchWidgetProvider());
- }
- } catch (RuntimeException ex) {
- Log.e(TAG, "Problem allocating appWidgetId", ex);
- }
- }
-
- db.setTransactionSuccessful();
- } catch (SQLException ex) {
- Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
- } finally {
- db.endTransaction();
- if (c != null) {
- c.close();
- }
- }
-
- // Update max item id
- mMaxItemId = initializeMaxItemId(db);
- if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId);
- }
-
- private boolean initializeExternalAdd(ContentValues values) {
+ @Thunk boolean initializeExternalAdd(ContentValues values) {
// 1. Ensure that externally added items have a valid item id
long id = generateNewItemId();
values.put(LauncherSettings.Favorites._ID, id);
@@ -1312,7 +1032,7 @@ public class LauncherProvider extends ContentProvider {
return rank;
}
- private int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
+ @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
ArrayList<Long> screenIds = new ArrayList<Long>();
// TODO: Use multiple loaders with fall-back and transaction.
int count = loader.loadLayout(db, screenIds);
@@ -1339,12 +1059,7 @@ public class LauncherProvider extends ContentProvider {
return count;
}
- private ComponentName getSearchWidgetProvider() {
- AppWidgetProviderInfo searchProvider = Utilities.getSearchWidgetProvider(mContext);
- return (searchProvider == null) ? null : searchProvider.provider;
- }
-
- private void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
+ @Thunk void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
final ContentResolver resolver = mContext.getContentResolver();
Cursor c = null;
int count = 0;
@@ -1395,10 +1110,10 @@ public class LauncherProvider extends ContentProvider {
int curY = 0;
final LauncherAppState app = LauncherAppState.getInstance();
- final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- final int width = (int) grid.numColumns;
- final int height = (int) grid.numRows;
- final int hotseatWidth = (int) grid.numHotseatIcons;
+ final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+ final int width = (int) profile.numColumns;
+ final int height = (int) profile.numRows;
+ final int hotseatWidth = (int) profile.numHotseatIcons;
final HashSet<String> seenIntents = new HashSet<String>(c.getCount());
@@ -1540,7 +1255,7 @@ public class LauncherProvider extends ContentProvider {
int hotseatX = hotseat.keyAt(idx);
ContentValues values = hotseat.valueAt(idx);
- if (hotseatX == grid.hotseatAllAppsRank) {
+ if (hotseatX == profile.hotseatAllAppsRank) {
// let's drop this in the next available hole in the hotseat
while (++hotseatX < hotseatWidth) {
if (hotseat.get(hotseatX) == null) {
@@ -1619,6 +1334,8 @@ public class LauncherProvider extends ContentProvider {
} finally {
db.endTransaction();
}
+
+ updateFolderItemsRank(db, false);
}
} finally {
c.close();
@@ -1639,18 +1356,24 @@ public class LauncherProvider extends ContentProvider {
}
/**
- * Build a query string that will match any row where the column matches
- * anything in the values list.
+ * @return the max _id in the provided table.
*/
- private static String buildOrWhereString(String column, int[] values) {
- StringBuilder selectWhere = new StringBuilder();
- for (int i = values.length - 1; i >= 0; i--) {
- selectWhere.append(column).append("=").append(values[i]);
- if (i > 0) {
- selectWhere.append(" OR ");
- }
+ @Thunk static long getMaxId(SQLiteDatabase db, String table) {
+ Cursor c = db.rawQuery("SELECT MAX(_id) FROM " + table, null);
+ // get the result
+ long id = -1;
+ if (c != null && c.moveToNext()) {
+ id = c.getLong(0);
}
- return selectWhere.toString();
+ if (c != null) {
+ c.close();
+ }
+
+ if (id == -1) {
+ throw new RuntimeException("Error: could not query max id in " + table);
+ }
+
+ return id;
}
static class SqlArguments {