Merge "Removing LauncherProvider dependency in DatabaseHeler" into ub-launcher3-calgary

This commit is contained in:
Sunny Goyal 2016-05-10 22:11:43 +00:00 committed by Android (Google) Code Review
commit 78508ec5ab
3 changed files with 155 additions and 198 deletions

View File

@ -630,7 +630,7 @@ public class AutoInstallsLayout {
copyInteger(myValues, childValues, Favorites.CELLY); copyInteger(myValues, childValues, Favorites.CELLY);
addedId = folderItems.get(0); addedId = folderItems.get(0);
mDb.update(LauncherProvider.TABLE_FAVORITES, childValues, mDb.update(Favorites.TABLE_NAME, childValues,
Favorites._ID + "=" + addedId, null); Favorites._ID + "=" + addedId, null);
} }
} }

View File

@ -42,20 +42,25 @@ import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Process; import android.os.Process;
import android.os.UserManager; import android.os.UserManager;
import android.provider.BaseColumns;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.WorkspaceScreens;
import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils; import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.util.ManagedProfileHeuristic; import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.NoLocaleSqliteContext; import com.android.launcher3.util.NoLocaleSqliteContext;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Thunk; import com.android.launcher3.util.Thunk;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -71,18 +76,19 @@ public class LauncherProvider extends ContentProvider {
public static final String AUTHORITY = ProviderConfig.AUTHORITY; public static final String AUTHORITY = ProviderConfig.AUTHORITY;
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"; static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name"; private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name";
private static final Object LISTENER_LOCK = new Object(); private final ChangeListenerWrapper mListenerWrapper = new ChangeListenerWrapper();
@Thunk LauncherProviderChangeListener mListener; private Handler mListenerHandler;
protected DatabaseHelper mOpenHelper; protected DatabaseHelper mOpenHelper;
@Override @Override
public boolean onCreate() { public boolean onCreate() {
mListenerHandler = new Handler(mListenerWrapper);
LauncherAppState.setLauncherProvider(this); LauncherAppState.setLauncherProvider(this);
return true; return true;
} }
@ -91,9 +97,8 @@ public class LauncherProvider extends ContentProvider {
* Sets a provider listener. * Sets a provider listener.
*/ */
public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) { public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) {
synchronized (LISTENER_LOCK) { Preconditions.assertUIThread();
mListener = listener; mListenerWrapper.mListener = listener;
}
} }
@Override @Override
@ -111,7 +116,7 @@ public class LauncherProvider extends ContentProvider {
*/ */
protected synchronized void createDbIfNotExists() { protected synchronized void createDbIfNotExists() {
if (mOpenHelper == null) { if (mOpenHelper == null) {
mOpenHelper = new DatabaseHelper(getContext(), this); mOpenHelper = new DatabaseHelper(getContext(), mListenerHandler);
} }
} }
@ -159,7 +164,7 @@ public class LauncherProvider extends ContentProvider {
// In very limited cases, we support system|signature permission apps to modify the db. // In very limited cases, we support system|signature permission apps to modify the db.
if (Binder.getCallingPid() != Process.myPid()) { if (Binder.getCallingPid() != Process.myPid()) {
if (!mOpenHelper.initializeExternalAdd(initialValues)) { if (!initializeExternalAdd(initialValues)) {
return null; return null;
} }
} }
@ -189,6 +194,59 @@ public class LauncherProvider extends ContentProvider {
return uri; return uri;
} }
private boolean initializeExternalAdd(ContentValues values) {
// 1. Ensure that externally added items have a valid item id
long id = mOpenHelper.generateNewItemId();
values.put(LauncherSettings.Favorites._ID, id);
// 2. In the case of an app widget, and if no app widget id is specified, we
// attempt allocate and bind the widget.
Integer itemType = values.getAsInteger(LauncherSettings.Favorites.ITEM_TYPE);
if (itemType != null &&
itemType.intValue() == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
!values.containsKey(LauncherSettings.Favorites.APPWIDGET_ID)) {
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getContext());
ComponentName cn = ComponentName.unflattenFromString(
values.getAsString(Favorites.APPWIDGET_PROVIDER));
if (cn != null) {
try {
int appWidgetId = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID)
.allocateAppWidgetId();
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
return false;
}
} catch (RuntimeException e) {
Log.e(TAG, "Failed to initialize external widget", e);
return false;
}
} else {
return false;
}
}
// Add screen id if not present
long screenId = values.getAsLong(LauncherSettings.Favorites.SCREEN);
SQLiteStatement stmp = null;
try {
stmp = mOpenHelper.getWritableDatabase().compileStatement(
"INSERT OR IGNORE INTO workspaceScreens (_id, screenRank) " +
"select ?, (ifnull(MAX(screenRank), -1)+1) from workspaceScreens");
stmp.bindLong(1, screenId);
ContentValues valuesInserted = new ContentValues();
valuesInserted.put(LauncherSettings.BaseLauncherColumns._ID, stmp.executeInsert());
mOpenHelper.checkId(WorkspaceScreens.TABLE_NAME, valuesInserted);
return true;
} catch (Exception e) {
return false;
} finally {
Utilities.closeSilently(stmp);
}
}
@Override @Override
public int bulkInsert(Uri uri, ContentValues[] values) { public int bulkInsert(Uri uri, ContentValues[] values) {
createDbIfNotExists(); createDbIfNotExists();
@ -295,17 +353,7 @@ public class LauncherProvider extends ContentProvider {
.putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors) .putString(ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, extractedColors)
.putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId) .putInt(ExtractionUtils.WALLPAPER_ID_PREFERENCE_KEY, wallpaperId)
.apply(); .apply();
new MainThreadExecutor().execute(new Runnable() { mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_EXTRACTED_COLORS_CHANGED);
@Override
public void run() {
synchronized (LISTENER_LOCK) {
if (mListener != null) {
mListener.onExtractedColorsChanged();
}
}
}
});
Bundle result = new Bundle(); Bundle result = new Bundle();
result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors); result.putString(LauncherSettings.Settings.EXTRA_VALUE, extractedColors);
return result; return result;
@ -340,6 +388,8 @@ public class LauncherProvider extends ContentProvider {
case LauncherSettings.Settings.METHOD_MIGRATE_LAUNCHER2_SHORTCUTS: { case LauncherSettings.Settings.METHOD_MIGRATE_LAUNCHER2_SHORTCUTS: {
mOpenHelper.migrateLauncher2Shortcuts(mOpenHelper.getWritableDatabase(), mOpenHelper.migrateLauncher2Shortcuts(mOpenHelper.getWritableDatabase(),
Uri.parse(getContext().getString(R.string.old_launcher_provider_uri))); Uri.parse(getContext().getString(R.string.old_launcher_provider_uri)));
Utilities.getPrefs(getContext()).edit().putBoolean(EMPTY_DATABASE_CREATED, false)
.commit();
return null; return null;
} }
case LauncherSettings.Settings.METHOD_UPDATE_FOLDER_ITEMS_RANK: { case LauncherSettings.Settings.METHOD_UPDATE_FOLDER_ITEMS_RANK: {
@ -373,8 +423,8 @@ public class LauncherProvider extends ContentProvider {
+ LauncherSettings.Favorites.ITEM_TYPE_FOLDER + " AND " + LauncherSettings.Favorites.ITEM_TYPE_FOLDER + " AND "
+ LauncherSettings.Favorites._ID + " NOT IN (SELECT " + + LauncherSettings.Favorites._ID + " NOT IN (SELECT " +
LauncherSettings.Favorites.CONTAINER + " FROM " LauncherSettings.Favorites.CONTAINER + " FROM "
+ TABLE_FAVORITES + ")"; + Favorites.TABLE_NAME + ")";
Cursor c = db.query(TABLE_FAVORITES, Cursor c = db.query(Favorites.TABLE_NAME,
new String[] {LauncherSettings.Favorites._ID}, new String[] {LauncherSettings.Favorites._ID},
selection, null, null, null, null); selection, null, null, null, null);
while (c.moveToNext()) { while (c.moveToNext()) {
@ -382,7 +432,7 @@ public class LauncherProvider extends ContentProvider {
} }
c.close(); c.close();
if (!folderIds.isEmpty()) { if (!folderIds.isEmpty()) {
db.delete(TABLE_FAVORITES, Utilities.createDbSelectionQuery( db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
LauncherSettings.Favorites._ID, folderIds), null); LauncherSettings.Favorites._ID, folderIds), null);
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();
@ -401,11 +451,7 @@ public class LauncherProvider extends ContentProvider {
protected void notifyListeners() { protected void notifyListeners() {
// always notify the backup agent // always notify the backup agent
LauncherBackupAgentHelper.dataChanged(getContext()); LauncherBackupAgentHelper.dataChanged(getContext());
synchronized (LISTENER_LOCK) { mListenerHandler.sendEmptyMessage(ChangeListenerWrapper.MSG_LAUNCHER_PROVIDER_CHANGED);
if (mListener != null) {
mListener.onLauncherProviderChange();
}
}
} }
@Thunk static void addModifiedTime(ContentValues values) { @Thunk static void addModifiedTime(ContentValues values) {
@ -436,10 +482,10 @@ public class LauncherProvider extends ContentProvider {
if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) { if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
Log.d(TAG, "loading default workspace"); Log.d(TAG, "loading default workspace");
AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(); AppWidgetHost widgetHost = new AppWidgetHost(getContext(), Launcher.APPWIDGET_HOST_ID);
AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost);
if (loader == null) { if (loader == null) {
loader = AutoInstallsLayout.get(getContext(), loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper);
mOpenHelper.mAppWidgetHost, mOpenHelper);
} }
if (loader == null) { if (loader == null) {
final Partner partner = Partner.get(getContext().getPackageManager()); final Partner partner = Partner.get(getContext().getPackageManager());
@ -448,7 +494,7 @@ public class LauncherProvider extends ContentProvider {
int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT,
"xml", partner.getPackageName()); "xml", partner.getPackageName());
if (workspaceResId != 0) { if (workspaceResId != 0) {
loader = new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost, loader = new DefaultLayoutParser(getContext(), widgetHost,
mOpenHelper, partnerRes, workspaceResId); mOpenHelper, partnerRes, workspaceResId);
} }
} }
@ -456,7 +502,7 @@ public class LauncherProvider extends ContentProvider {
final boolean usingExternallyProvidedLayout = loader != null; final boolean usingExternallyProvidedLayout = loader != null;
if (loader == null) { if (loader == null) {
loader = getDefaultLayoutParser(); loader = getDefaultLayoutParser(widgetHost);
} }
// There might be some partially restored DB items, due to buggy restore logic in // There might be some partially restored DB items, due to buggy restore logic in
@ -468,7 +514,7 @@ public class LauncherProvider extends ContentProvider {
// Unable to load external layout. Cleanup and load the internal layout. // Unable to load external layout. Cleanup and load the internal layout.
createEmptyDB(); createEmptyDB();
mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(),
getDefaultLayoutParser()); getDefaultLayoutParser(widgetHost));
} }
clearFlagEmptyDbCreated(); clearFlagEmptyDbCreated();
} }
@ -480,7 +526,7 @@ public class LauncherProvider extends ContentProvider {
* @return the loader if the restrictions are set and the resource exists; null otherwise. * @return the loader if the restrictions are set and the resource exists; null otherwise.
*/ */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction() { private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) {
// UserManager.getApplicationRestrictions() requires minSdkVersion >= 18 // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18
if (!Utilities.ATLEAST_JB_MR2) { if (!Utilities.ATLEAST_JB_MR2) {
return null; return null;
@ -499,7 +545,7 @@ public class LauncherProvider extends ContentProvider {
Resources targetResources = ctx.getPackageManager() Resources targetResources = ctx.getPackageManager()
.getResourcesForApplication(packageName); .getResourcesForApplication(packageName);
return AutoInstallsLayout.get(ctx, packageName, targetResources, return AutoInstallsLayout.get(ctx, packageName, targetResources,
mOpenHelper.mAppWidgetHost, mOpenHelper); widgetHost, mOpenHelper);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.e(TAG, "Target package for restricted profile not found", e); Log.e(TAG, "Target package for restricted profile not found", e);
return null; return null;
@ -508,50 +554,28 @@ public class LauncherProvider extends ContentProvider {
return null; return null;
} }
private DefaultLayoutParser getDefaultLayoutParser() { private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
int defaultLayout = LauncherAppState.getInstance() int defaultLayout = LauncherAppState.getInstance()
.getInvariantDeviceProfile().defaultLayoutId; .getInvariantDeviceProfile().defaultLayoutId;
return new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost, return new DefaultLayoutParser(getContext(), widgetHost,
mOpenHelper, getContext().getResources(), defaultLayout); mOpenHelper, getContext().getResources(), defaultLayout);
} }
/**
* 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.
*/
@Thunk void notifyAppHostReset() {
new MainThreadExecutor().execute(new Runnable() {
@Override
public void run() {
synchronized (LISTENER_LOCK) {
if (mListener != null) {
mListener.onAppWidgetHostReset();
}
}
}
});
}
/** /**
* The class is subclassed in tests to create an in-memory db. * The class is subclassed in tests to create an in-memory db.
*/ */
protected static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback { protected static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback {
private final LauncherProvider mProvider; private final Handler mWidgetHostResetHandler;
private final Context mContext; private final Context mContext;
@Thunk final AppWidgetHost mAppWidgetHost;
private long mMaxItemId = -1; private long mMaxItemId = -1;
private long mMaxScreenId = -1; private long mMaxScreenId = -1;
DatabaseHelper(Context context, LauncherProvider provider) { DatabaseHelper(Context context, Handler widgetHostResetHandler) {
this(context, provider, LauncherFiles.LAUNCHER_DB, this(context, widgetHostResetHandler, LauncherFiles.LAUNCHER_DB);
new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID));
// Table creation sometimes fails silently, which leads to a crash loop. // Table creation sometimes fails silently, which leads to a crash loop.
// This way, we will try to create a table every time after crash, so the device // This way, we will try to create a table every time after crash, so the device
// would eventually be able to recover. // would eventually be able to recover.
if (!tableExists(TABLE_FAVORITES) || !tableExists(TABLE_WORKSPACE_SCREENS)) { if (!tableExists(Favorites.TABLE_NAME) || !tableExists(WorkspaceScreens.TABLE_NAME)) {
Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate");
// This operation is a no-op if the table already exists. // This operation is a no-op if the table already exists.
addFavoritesTable(getWritableDatabase(), true); addFavoritesTable(getWritableDatabase(), true);
@ -565,11 +589,10 @@ public class LauncherProvider extends ContentProvider {
* Constructor used only in tests. * Constructor used only in tests.
*/ */
public DatabaseHelper( public DatabaseHelper(
Context context, LauncherProvider provider, String tableName, AppWidgetHost host) { Context context, Handler widgetHostResetHandler, String tableName) {
super(new NoLocaleSqliteContext(context), tableName, null, DATABASE_VERSION); super(new NoLocaleSqliteContext(context), tableName, null, DATABASE_VERSION);
mContext = context; mContext = context;
mProvider = provider; mWidgetHostResetHandler = widgetHostResetHandler;
mAppWidgetHost = host;
} }
protected void initIds() { protected void initIds() {
@ -605,12 +628,6 @@ public class LauncherProvider extends ContentProvider {
addFavoritesTable(db, false); addFavoritesTable(db, false);
addWorkspacesTable(db, false); addWorkspacesTable(db, false);
// Database was just created, so wipe any previous widgets
if (mAppWidgetHost != null) {
mAppWidgetHost.deleteHost();
mProvider.notifyAppHostReset();
}
// Fresh and clean launcher DB. // Fresh and clean launcher DB.
mMaxItemId = initializeMaxItemId(db); mMaxItemId = initializeMaxItemId(db);
onEmptyDbCreated(); onEmptyDbCreated();
@ -620,6 +637,13 @@ public class LauncherProvider extends ContentProvider {
* Overriden in tests. * Overriden in tests.
*/ */
protected void onEmptyDbCreated() { protected void onEmptyDbCreated() {
// Database was just created, so wipe any previous widgets
if (mWidgetHostResetHandler != null) {
new AppWidgetHost(mContext, Launcher.APPWIDGET_HOST_ID).deleteHost();
mWidgetHostResetHandler.sendEmptyMessage(
ChangeListenerWrapper.MSG_APP_WIDGET_HOST_RESET);
}
// Set the flag for empty DB // Set the flag for empty DB
Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit(); Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit();
@ -635,7 +659,7 @@ public class LauncherProvider extends ContentProvider {
private void addFavoritesTable(SQLiteDatabase db, boolean optional) { private void addFavoritesTable(SQLiteDatabase db, boolean optional) {
String ifNotExists = optional ? " IF NOT EXISTS " : ""; String ifNotExists = optional ? " IF NOT EXISTS " : "";
db.execSQL("CREATE TABLE " + ifNotExists + TABLE_FAVORITES + " (" + db.execSQL("CREATE TABLE " + ifNotExists + Favorites.TABLE_NAME + " (" +
"_id INTEGER PRIMARY KEY," + "_id INTEGER PRIMARY KEY," +
"title TEXT," + "title TEXT," +
"intent TEXT," + "intent TEXT," +
@ -662,7 +686,7 @@ public class LauncherProvider extends ContentProvider {
private void addWorkspacesTable(SQLiteDatabase db, boolean optional) { private void addWorkspacesTable(SQLiteDatabase db, boolean optional) {
String ifNotExists = optional ? " IF NOT EXISTS " : ""; String ifNotExists = optional ? " IF NOT EXISTS " : "";
db.execSQL("CREATE TABLE " + ifNotExists + TABLE_WORKSPACE_SCREENS + " (" + db.execSQL("CREATE TABLE " + ifNotExists + WorkspaceScreens.TABLE_NAME + " (" +
LauncherSettings.WorkspaceScreens._ID + " INTEGER PRIMARY KEY," + LauncherSettings.WorkspaceScreens._ID + " INTEGER PRIMARY KEY," +
LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," + LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," +
LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" + LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" +
@ -673,10 +697,10 @@ public class LauncherProvider extends ContentProvider {
// Delete items directly on the workspace who's screen id doesn't exist // Delete items directly on the workspace who's screen id doesn't exist
// "DELETE FROM favorites WHERE screen NOT IN (SELECT _id FROM workspaceScreens) // "DELETE FROM favorites WHERE screen NOT IN (SELECT _id FROM workspaceScreens)
// AND container = -100" // AND container = -100"
String removeOrphanedDesktopItems = "DELETE FROM " + TABLE_FAVORITES + String removeOrphanedDesktopItems = "DELETE FROM " + Favorites.TABLE_NAME +
" WHERE " + " WHERE " +
LauncherSettings.Favorites.SCREEN + " NOT IN (SELECT " + LauncherSettings.Favorites.SCREEN + " NOT IN (SELECT " +
LauncherSettings.WorkspaceScreens._ID + " FROM " + TABLE_WORKSPACE_SCREENS + ")" + LauncherSettings.WorkspaceScreens._ID + " FROM " + WorkspaceScreens.TABLE_NAME + ")" +
" AND " + " AND " +
LauncherSettings.Favorites.CONTAINER + " = " + LauncherSettings.Favorites.CONTAINER + " = " +
LauncherSettings.Favorites.CONTAINER_DESKTOP; LauncherSettings.Favorites.CONTAINER_DESKTOP;
@ -685,7 +709,7 @@ public class LauncherProvider extends ContentProvider {
// Delete items contained in folders which no longer exist (after above statement) // Delete items contained in folders which no longer exist (after above statement)
// "DELETE FROM favorites WHERE container <> -100 AND container <> -101 AND container // "DELETE FROM favorites WHERE container <> -100 AND container <> -101 AND container
// NOT IN (SELECT _id FROM favorites WHERE itemType = 2)" // NOT IN (SELECT _id FROM favorites WHERE itemType = 2)"
String removeOrphanedFolderItems = "DELETE FROM " + TABLE_FAVORITES + String removeOrphanedFolderItems = "DELETE FROM " + Favorites.TABLE_NAME +
" WHERE " + " WHERE " +
LauncherSettings.Favorites.CONTAINER + " <> " + LauncherSettings.Favorites.CONTAINER + " <> " +
LauncherSettings.Favorites.CONTAINER_DESKTOP + LauncherSettings.Favorites.CONTAINER_DESKTOP +
@ -694,16 +718,12 @@ public class LauncherProvider extends ContentProvider {
LauncherSettings.Favorites.CONTAINER_HOTSEAT + LauncherSettings.Favorites.CONTAINER_HOTSEAT +
" AND " " AND "
+ LauncherSettings.Favorites.CONTAINER + " NOT IN (SELECT " + + LauncherSettings.Favorites.CONTAINER + " NOT IN (SELECT " +
LauncherSettings.Favorites._ID + " FROM " + TABLE_FAVORITES + LauncherSettings.Favorites._ID + " FROM " + Favorites.TABLE_NAME +
" WHERE " + LauncherSettings.Favorites.ITEM_TYPE + " = " + " WHERE " + LauncherSettings.Favorites.ITEM_TYPE + " = " +
LauncherSettings.Favorites.ITEM_TYPE_FOLDER + ")"; LauncherSettings.Favorites.ITEM_TYPE_FOLDER + ")";
db.execSQL(removeOrphanedFolderItems); db.execSQL(removeOrphanedFolderItems);
} }
private void setFlagJustLoadedOldDb() {
Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, false).commit();
}
@Override @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion); if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
@ -823,8 +843,8 @@ public class LauncherProvider extends ContentProvider {
* Clears all the data for a fresh start. * Clears all the data for a fresh start.
*/ */
public void createEmptyDB(SQLiteDatabase db) { public void createEmptyDB(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); db.execSQL("DROP TABLE IF EXISTS " + Favorites.TABLE_NAME);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS); db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME);
onCreate(db); onCreate(db);
} }
@ -839,9 +859,8 @@ public class LauncherProvider extends ContentProvider {
try { try {
// Only consider the primary user as other users can't have a shortcut. // Only consider the primary user as other users can't have a shortcut.
long userSerial = UserManagerCompat.getInstance(mContext) long userSerial = getDefaultUserSerial();
.getSerialNumberForUser(UserHandleCompat.myUserHandle()); c = db.query(Favorites.TABLE_NAME, new String[] {
c = db.query(TABLE_FAVORITES, new String[] {
Favorites._ID, Favorites._ID,
Favorites.INTENT, Favorites.INTENT,
}, "itemType=" + Favorites.ITEM_TYPE_SHORTCUT + " AND profileId=" + userSerial, }, "itemType=" + Favorites.ITEM_TYPE_SHORTCUT + " AND profileId=" + userSerial,
@ -891,7 +910,7 @@ public class LauncherProvider extends ContentProvider {
public boolean recreateWorkspaceTable(SQLiteDatabase db) { public boolean recreateWorkspaceTable(SQLiteDatabase db) {
db.beginTransaction(); db.beginTransaction();
try { try {
Cursor c = db.query(TABLE_WORKSPACE_SCREENS, Cursor c = db.query(WorkspaceScreens.TABLE_NAME,
new String[] {LauncherSettings.WorkspaceScreens._ID}, new String[] {LauncherSettings.WorkspaceScreens._ID},
null, null, null, null, null, null, null, null,
LauncherSettings.WorkspaceScreens.SCREEN_RANK); LauncherSettings.WorkspaceScreens.SCREEN_RANK);
@ -909,7 +928,7 @@ public class LauncherProvider extends ContentProvider {
c.close(); c.close();
} }
db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS); db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME);
addWorkspacesTable(db, false); addWorkspacesTable(db, false);
// Add all screen ids back // Add all screen ids back
@ -919,7 +938,7 @@ public class LauncherProvider extends ContentProvider {
values.put(LauncherSettings.WorkspaceScreens._ID, sortedIDs.get(i)); values.put(LauncherSettings.WorkspaceScreens._ID, sortedIDs.get(i));
values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
addModifiedTime(values); addModifiedTime(values);
db.insertOrThrow(TABLE_WORKSPACE_SCREENS, null, values); db.insertOrThrow(WorkspaceScreens.TABLE_NAME, null, values);
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();
mMaxScreenId = maxId; mMaxScreenId = maxId;
@ -966,12 +985,7 @@ public class LauncherProvider extends ContentProvider {
} }
private boolean addProfileColumn(SQLiteDatabase db) { private boolean addProfileColumn(SQLiteDatabase db) {
UserManagerCompat userManager = UserManagerCompat.getInstance(mContext); return addIntegerColumn(db, Favorites.PROFILE_ID, getDefaultUserSerial());
// 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) { private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) {
@ -1005,12 +1019,12 @@ public class LauncherProvider extends ContentProvider {
@Override @Override
public long insertAndCheck(SQLiteDatabase db, ContentValues values) { public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
return dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values); return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values);
} }
public void checkId(String table, ContentValues values) { public void checkId(String table, ContentValues values) {
long id = values.getAsLong(LauncherSettings.BaseLauncherColumns._ID); long id = values.getAsLong(LauncherSettings.BaseLauncherColumns._ID);
if (table == LauncherProvider.TABLE_WORKSPACE_SCREENS) { if (table == WorkspaceScreens.TABLE_NAME) {
mMaxScreenId = Math.max(id, mMaxScreenId); mMaxScreenId = Math.max(id, mMaxScreenId);
} else { } else {
mMaxItemId = Math.max(id, mMaxItemId); mMaxItemId = Math.max(id, mMaxItemId);
@ -1018,7 +1032,7 @@ public class LauncherProvider extends ContentProvider {
} }
private long initializeMaxItemId(SQLiteDatabase db) { private long initializeMaxItemId(SQLiteDatabase db) {
return getMaxId(db, TABLE_FAVORITES); return getMaxId(db, Favorites.TABLE_NAME);
} }
// Generates a new ID to use for an workspace screen in your database. This method // Generates a new ID to use for an workspace screen in your database. This method
@ -1035,94 +1049,7 @@ public class LauncherProvider extends ContentProvider {
} }
private long initializeMaxScreenId(SQLiteDatabase db) { private long initializeMaxScreenId(SQLiteDatabase db) {
return getMaxId(db, TABLE_WORKSPACE_SCREENS); return getMaxId(db, WorkspaceScreens.TABLE_NAME);
}
@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);
// 2. In the case of an app widget, and if no app widget id is specified, we
// attempt allocate and bind the widget.
Integer itemType = values.getAsInteger(LauncherSettings.Favorites.ITEM_TYPE);
if (itemType != null &&
itemType.intValue() == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
!values.containsKey(LauncherSettings.Favorites.APPWIDGET_ID)) {
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
ComponentName cn = ComponentName.unflattenFromString(
values.getAsString(Favorites.APPWIDGET_PROVIDER));
if (cn != null) {
try {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) {
return false;
}
} catch (RuntimeException e) {
Log.e(TAG, "Failed to initialize external widget", e);
return false;
}
} else {
return false;
}
}
// Add screen id if not present
long screenId = values.getAsLong(LauncherSettings.Favorites.SCREEN);
if (!addScreenIdIfNecessary(screenId)) {
return false;
}
return true;
}
// Returns true of screen id exists, or if successfully added
private boolean addScreenIdIfNecessary(long screenId) {
if (!hasScreenId(screenId)) {
int rank = getMaxScreenRank() + 1;
ContentValues v = new ContentValues();
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank);
if (dbInsertAndCheck(this, getWritableDatabase(),
TABLE_WORKSPACE_SCREENS, null, v) < 0) {
return false;
}
}
return true;
}
private boolean hasScreenId(long screenId) {
SQLiteDatabase db = getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM " + TABLE_WORKSPACE_SCREENS + " WHERE "
+ LauncherSettings.WorkspaceScreens._ID + " = " + screenId, null);
if (c != null) {
int count = c.getCount();
c.close();
return count > 0;
} else {
return false;
}
}
private int getMaxScreenRank() {
SQLiteDatabase db = getWritableDatabase();
Cursor c = db.rawQuery("SELECT MAX(" + LauncherSettings.WorkspaceScreens.SCREEN_RANK
+ ") FROM " + TABLE_WORKSPACE_SCREENS, null);
// get the result
final int maxRankIndex = 0;
int rank = -1;
if (c != null && c.moveToNext()) {
rank = c.getInt(maxRankIndex);
}
if (c != null) {
c.close();
}
return rank;
} }
@Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) { @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
@ -1138,7 +1065,7 @@ public class LauncherProvider extends ContentProvider {
values.clear(); values.clear();
values.put(LauncherSettings.WorkspaceScreens._ID, id); values.put(LauncherSettings.WorkspaceScreens._ID, id);
values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank); values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank);
if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, null, values) < 0) { if (dbInsertAndCheck(this, db, WorkspaceScreens.TABLE_NAME, null, values) < 0) {
throw new RuntimeException("Failed initialize screen table" throw new RuntimeException("Failed initialize screen table"
+ "from default layout"); + "from default layout");
} }
@ -1383,7 +1310,7 @@ public class LauncherProvider extends ContentProvider {
try { try {
for (ContentValues row: allItems) { for (ContentValues row: allItems) {
if (row == null) continue; if (row == null) continue;
if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, row) if (dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, row)
< 0) { < 0) {
return; return;
} else { } else {
@ -1402,7 +1329,7 @@ public class LauncherProvider extends ContentProvider {
final ContentValues values = new ContentValues(); final ContentValues values = new ContentValues();
values.put(LauncherSettings.WorkspaceScreens._ID, i); values.put(LauncherSettings.WorkspaceScreens._ID, i);
values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, null, values) if (dbInsertAndCheck(this, db, WorkspaceScreens.TABLE_NAME, null, values)
< 0) { < 0) {
return; return;
} }
@ -1422,9 +1349,6 @@ public class LauncherProvider extends ContentProvider {
Log.d(TAG, "migrated " + count + " icons from Launcher2 into " Log.d(TAG, "migrated " + count + " icons from Launcher2 into "
+ (curScreen+1) + " screens"); + (curScreen+1) + " screens");
// ensure that new screens are created to hold these icons
setFlagJustLoadedOldDb();
// Update max IDs; very important since we just grabbed IDs from another database // Update max IDs; very important since we just grabbed IDs from another database
mMaxItemId = initializeMaxItemId(db); mMaxItemId = initializeMaxItemId(db);
mMaxScreenId = initializeMaxScreenId(db); mMaxScreenId = initializeMaxScreenId(db);
@ -1484,4 +1408,31 @@ public class LauncherProvider extends ContentProvider {
} }
} }
} }
private static class ChangeListenerWrapper implements Handler.Callback {
private static final int MSG_LAUNCHER_PROVIDER_CHANGED = 1;
private static final int MSG_EXTRACTED_COLORS_CHANGED = 2;
private static final int MSG_APP_WIDGET_HOST_RESET = 3;
private LauncherProviderChangeListener mListener;
@Override
public boolean handleMessage(Message msg) {
if (mListener != null) {
switch (msg.what) {
case MSG_LAUNCHER_PROVIDER_CHANGED:
mListener.onLauncherProviderChange();
break;
case MSG_EXTRACTED_COLORS_CHANGED:
mListener.onExtractedColorsChanged();
break;
case MSG_APP_WIDGET_HOST_RESET:
mListener.onAppWidgetHostReset();
break;
}
}
return true;
}
}
} }

View File

@ -1,6 +1,7 @@
package com.android.launcher3.util; package com.android.launcher3.util;
import android.content.Context; import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import com.android.launcher3.LauncherProvider; import com.android.launcher3.LauncherProvider;
@ -17,16 +18,21 @@ public class TestLauncherProvider extends LauncherProvider {
@Override @Override
protected synchronized void createDbIfNotExists() { protected synchronized void createDbIfNotExists() {
if (mOpenHelper == null) { if (mOpenHelper == null) {
mOpenHelper = new MyDatabaseHelper(getContext(), this); mOpenHelper = new MyDatabaseHelper(getContext());
} }
} }
public SQLiteOpenHelper getHelper() {
createDbIfNotExists();
return mOpenHelper;
}
@Override @Override
protected void notifyListeners() { } protected void notifyListeners() { }
private static class MyDatabaseHelper extends DatabaseHelper { private static class MyDatabaseHelper extends DatabaseHelper {
public MyDatabaseHelper(Context context, LauncherProvider provider) { public MyDatabaseHelper(Context context) {
super(context, provider, null, null); super(context, null, null);
initIds(); initIds();
} }