diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java index 1ed4bca3ee..c426dc593f 100644 --- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java @@ -65,7 +65,7 @@ public class GridSizeMigrationTaskTest { }; mIdp.numHotseatIcons = 3; - new GridSizeMigrationTask(mContext, mDb, mValidPackages, 5, 3) + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3) .migrateHotseat(); // First item is dropped as it has the least weight. verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]); @@ -82,7 +82,7 @@ public class GridSizeMigrationTaskTest { }; mIdp.numHotseatIcons = 3; - new GridSizeMigrationTask(mContext, mDb, mValidPackages, 5, 3) + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3) .migrateHotseat(); // First item is dropped as it has the least weight. verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]); @@ -127,7 +127,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, -1, 6}, }}); - new GridSizeMigrationTask(mContext, mDb, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Column 2 and row 2 got removed. @@ -147,7 +147,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, -1, 6}, }}); - new GridSizeMigrationTask(mContext, mDb, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column get moved to new screen @@ -172,7 +172,7 @@ public class GridSizeMigrationTaskTest { { 3, 1, -1, 4}, }}); - new GridSizeMigrationTask(mContext, mDb, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column of the first screen should get placed on the 3rd @@ -204,7 +204,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, -1, 6}, }}); - new GridSizeMigrationTask(mContext, mDb, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column of the first screen should get placed on a new screen. @@ -235,7 +235,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, 7, -1}, }}, 0); - new GridSizeMigrationTask(mContext, mDb, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, new Point(4, 4), new Point(3, 4)).migrateWorkspace(); // Items in the second column of the first screen should get placed on a new screen. @@ -262,7 +262,7 @@ public class GridSizeMigrationTaskTest { { 5, 6, 7, -1}, }}, 0); - new GridSizeMigrationTask(mContext, mDb, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column of the first screen should get placed on a new screen. @@ -282,7 +282,7 @@ public class GridSizeMigrationTaskTest { * represent the workspace grid. */ private void verifyWorkspace(int[][][] ids) { - IntArray allScreens = getWorkspaceScreenIds(mDb); + IntArray allScreens = getWorkspaceScreenIds(mDb, LauncherSettings.Favorites.TABLE_NAME); assertEquals(ids.length, allScreens.size()); int total = 0; @@ -351,7 +351,7 @@ public class GridSizeMigrationTaskTest { private final LinkedList mPoints; public MultiStepMigrationTaskVerifier(int... points) { - super(null, null, null); + super(null, null, null, false); mPoints = new LinkedList<>(); for (int i = 0; i < points.length; i += 2) { diff --git a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java index 7fa3ee96bf..6e41a4f3e8 100644 --- a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -52,6 +52,7 @@ import android.os.Process; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.util.Executors; import com.android.launcher3.util.LauncherRoboTestRunner; @@ -91,7 +92,7 @@ public class LoaderCursorTest { SCREEN, CELLX, CELLY, RESTORED, INTENT }); - mLoaderCursor = new LoaderCursor(mCursor, mApp); + mLoaderCursor = new LoaderCursor(mCursor, LauncherSettings.Favorites.CONTENT_URI, mApp); mLoaderCursor.allUsers.put(0, Process.myUserHandle()); } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 857db8e715..2ad84b9f9c 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -47,6 +47,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.graphics.IconShape; +import com.android.launcher3.graphics.LauncherPreviewRenderer; import com.android.launcher3.util.ConfigMonitor; import com.android.launcher3.util.DefaultDisplay; import com.android.launcher3.util.DefaultDisplay.Info; @@ -156,6 +157,11 @@ public class InvariantDeviceProfile { @TargetApi(23) private InvariantDeviceProfile(Context context) { + if (context instanceof LauncherPreviewRenderer.PreviewContext) { + throw new IllegalArgumentException( + "PreviewContext is passed into this IDP constructor"); + } + String gridName = Utilities.getPrefs(context).getBoolean(GRID_OPTIONS_PREFERENCE_KEY, false) ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null) : null; diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index d77285d7be..2f38037892 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -27,6 +27,8 @@ import android.content.pm.LauncherApps; import android.os.Handler; import android.util.Log; +import androidx.annotation.Nullable; + import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconProvider; @@ -55,12 +57,12 @@ public class LauncherAppState { private final IconCache mIconCache; private final WidgetPreviewLoader mWidgetCache; private final InvariantDeviceProfile mInvariantDeviceProfile; - private final SecureSettingsObserver mNotificationDotsObserver; - private final InstallSessionTracker mInstallSessionTracker; - private final SimpleBroadcastReceiver mModelChangeReceiver; - private final SafeCloseable mCalendarChangeTracker; - private final SafeCloseable mUserChangeListener; + private SecureSettingsObserver mNotificationDotsObserver; + private InstallSessionTracker mInstallSessionTracker; + private SimpleBroadcastReceiver mModelChangeReceiver; + private SafeCloseable mCalendarChangeTracker; + private SafeCloseable mUserChangeListener; public static LauncherAppState getInstance(final Context context) { return INSTANCE.get(context); @@ -74,15 +76,8 @@ public class LauncherAppState { return mContext; } - private LauncherAppState(Context context) { - Log.v(Launcher.TAG, "LauncherAppState initiated"); - Preconditions.assertUIThread(); - mContext = context; - - mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext); - mIconCache = new IconCache(mContext, mInvariantDeviceProfile); - mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); - mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); + public LauncherAppState(Context context) { + this(context, LauncherFiles.APP_ICONS_DB); mModelChangeReceiver = new SimpleBroadcastReceiver(mModel::onBroadcastIntent); @@ -123,6 +118,17 @@ public class LauncherAppState { } } + public LauncherAppState(Context context, @Nullable String iconCacheFileName) { + Log.v(Launcher.TAG, "LauncherAppState initiated"); + Preconditions.assertUIThread(); + mContext = context; + + mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context); + mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName); + mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); + mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); + } + protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) { if (areNotificationDotsEnabled) { NotificationListener.requestRebind(new ComponentName( @@ -148,11 +154,19 @@ public class LauncherAppState { * Call from Application.onTerminate(), which is not guaranteed to ever be called. */ public void onTerminate() { - mContext.unregisterReceiver(mModelChangeReceiver); + if (mModelChangeReceiver != null) { + mContext.unregisterReceiver(mModelChangeReceiver); + } mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel); - mInstallSessionTracker.unregister(); - mCalendarChangeTracker.close(); - mUserChangeListener.close(); + if (mInstallSessionTracker != null) { + mInstallSessionTracker.unregister(); + } + if (mCalendarChangeTracker != null) { + mCalendarChangeTracker.close(); + } + if (mUserChangeListener != null) { + mUserChangeListener.close(); + } CustomWidgetManager.INSTANCE.get(mContext).setWidgetRefreshCallback(null); if (mNotificationDotsObserver != null) { diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 49831f6495..216c221dc6 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -93,15 +93,26 @@ public class LauncherSettings { public static final String TABLE_NAME = "favorites"; /** - * Backup table created when when the favorites table is modified during grid migration + * Backup table created when the favorites table is modified during grid migration */ public static final String BACKUP_TABLE_NAME = "favorites_bakup"; /** - * The content:// style URL for this table + * Temporary table used specifically for grid migrations during wallpaper preview */ - public static final Uri CONTENT_URI = Uri.parse("content://" + - LauncherProvider.AUTHORITY + "/" + TABLE_NAME); + public static final String PREVIEW_TABLE_NAME = "favorites_preview"; + + /** + * The content:// style URL for "favorites" table + */ + public static final Uri CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + TABLE_NAME); + + /** + * The content:// style URL for "favorites_preview" table + */ + public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME); /** * The content:// style URL for a given row, identified by its id. @@ -111,8 +122,8 @@ public class LauncherSettings { * @return The unique content URL for the specified row. */ public static Uri getContentUri(int id) { - return Uri.parse("content://" + LauncherProvider.AUTHORITY + - "/" + TABLE_NAME + "/" + id); + return Uri.parse("content://" + LauncherProvider.AUTHORITY + + "/" + TABLE_NAME + "/" + id); } /** diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index a429af22d4..0927b26505 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -20,14 +20,19 @@ import static android.view.View.MeasureSpec.makeMeasureSpec; import static android.view.View.VISIBLE; import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER; +import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO; +import static com.android.launcher3.model.GridSizeMigrationTask.needsToMigrate; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.annotation.TargetApi; import android.app.Fragment; import android.appwidget.AppWidgetHostView; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; +import android.content.pm.ShortcutInfo; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -70,17 +75,31 @@ import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapRenderer; +import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.AllAppsList; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.Callbacks; +import com.android.launcher3.model.GridSizeMigrationTask; +import com.android.launcher3.model.GridSizeMigrationTaskV2; import com.android.launcher3.model.LoaderResults; +import com.android.launcher3.model.LoaderTask; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.WidgetsModel; +import com.android.launcher3.pm.InstallSessionHelper; +import com.android.launcher3.pm.UserCache; +import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; @@ -101,6 +120,81 @@ public class LauncherPreviewRenderer implements Callable { private static final String TAG = "LauncherPreviewRenderer"; + /** + * Context used just for preview. It also provides a few objects (e.g. UserCache) just for + * preview purposes. + */ + public static class PreviewContext extends ContextWrapper { + + private static final Set WHITELIST = new HashSet<>( + Arrays.asList(UserCache.INSTANCE, InstallSessionHelper.INSTANCE, + LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE)); + + private final InvariantDeviceProfile mIdp; + private final Map mObjectMap = new HashMap<>(); + private final ConcurrentLinkedQueue mIconPool = + new ConcurrentLinkedQueue<>(); + + public PreviewContext(Context base, InvariantDeviceProfile idp) { + super(base); + mIdp = idp; + } + + @Override + public Context getApplicationContext() { + return this; + } + + /** + * Find a cached object from mObjectMap if we have already created one. If not, generate + * an object using the provider. + */ + public T getObject(MainThreadInitializedObject mainThreadInitializedObject, + MainThreadInitializedObject.ObjectProvider provider) { + if (!WHITELIST.contains(mainThreadInitializedObject)) { + throw new IllegalStateException("Leaking unknown objects"); + } + if (mainThreadInitializedObject == LauncherAppState.INSTANCE) { + throw new IllegalStateException( + "Should not use MainThreadInitializedObject to initialize this with " + + "PreviewContext"); + } + if (mainThreadInitializedObject == InvariantDeviceProfile.INSTANCE) { + return (T) mIdp; + } + if (mObjectMap.containsKey(mainThreadInitializedObject)) { + return (T) mObjectMap.get(mainThreadInitializedObject); + } + T t = provider.get(this); + mObjectMap.put(mainThreadInitializedObject, t); + return t; + } + + public LauncherIcons newLauncherIcons(Context context, boolean shapeDetection) { + LauncherIconsForPreview launcherIconsForPreview = mIconPool.poll(); + if (launcherIconsForPreview != null) { + return launcherIconsForPreview; + } + return new LauncherIconsForPreview(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize, + -1 /* poolId */, shapeDetection); + } + + private final class LauncherIconsForPreview extends LauncherIcons { + + private LauncherIconsForPreview(Context context, int fillResIconDpi, int iconBitmapSize, + int poolId, boolean shapeDetection) { + super(context, fillResIconDpi, iconBitmapSize, poolId, shapeDetection); + } + + @Override + public void recycle() { + // Clear any temporary state variables + clear(); + mIconPool.offer(this); + } + } + } + private final Handler mUiHandler; private final Context mContext; private final InvariantDeviceProfile mIdp; @@ -282,15 +376,28 @@ public class LauncherPreviewRenderer implements Callable { private void renderScreenShot(Canvas canvas) { if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) { - final LauncherModel launcherModel = LauncherAppState.getInstance( - mContext).getModel(); - final WorkspaceItemsInfoFetcher fetcher = new WorkspaceItemsInfoFetcher(); - launcherModel.enqueueModelUpdateTask(fetcher); - WorkspaceResult workspaceResult; - try { - workspaceResult = fetcher.mTask.get(5, TimeUnit.SECONDS); - } catch (InterruptedException | ExecutionException | TimeoutException e) { - Log.d(TAG, "Error fetching workspace items info", e); + boolean needsToMigrate = needsToMigrate(mContext, mIdp); + boolean success = false; + if (needsToMigrate) { + success = MULTI_DB_GRID_MIRATION_ALGO.get() + ? GridSizeMigrationTaskV2.migrateGridIfNeeded(mContext, mIdp) + : GridSizeMigrationTask.migrateGridIfNeeded(mContext, mIdp); + } + + WorkspaceFetcher fetcher; + if (needsToMigrate && success) { + LauncherAppState appForPreview = new LauncherAppState( + new PreviewContext(mContext, mIdp), null /* iconCacheFileName */); + fetcher = new WorkspaceItemsInfoFromPreviewFetcher(appForPreview); + MODEL_EXECUTOR.execute(fetcher); + } else { + fetcher = new WorkspaceItemsInfoFetcher(); + LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask( + (LauncherModel.ModelUpdateTask) fetcher); + } + WorkspaceResult workspaceResult = fetcher.get(); + + if (workspaceResult == null) { return; } @@ -379,8 +486,13 @@ public class LauncherPreviewRenderer implements Callable { } } - private static class WorkspaceItemsInfoFetcher implements Callable, - LauncherModel.ModelUpdateTask { + private static void measureView(View view, int width, int height) { + view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); + view.layout(0, 0, width, height); + } + + private static class WorkspaceItemsInfoFetcher implements LauncherModel.ModelUpdateTask, + WorkspaceFetcher { private final FutureTask mTask = new FutureTask<>(this); @@ -398,6 +510,11 @@ public class LauncherPreviewRenderer implements Callable { mAllAppsList = allAppsList; } + @Override + public FutureTask getTask() { + return mTask; + } + @Override public void run() { mTask.run(); @@ -417,9 +534,45 @@ public class LauncherPreviewRenderer implements Callable { } } - private static void measureView(View view, int width, int height) { - view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); - view.layout(0, 0, width, height); + private static class WorkspaceItemsInfoFromPreviewFetcher extends LoaderTask implements + WorkspaceFetcher { + + private final FutureTask mTask = new FutureTask<>(this); + + WorkspaceItemsInfoFromPreviewFetcher(LauncherAppState app) { + super(app, null, new BgDataModel(), null); + } + + @Override + public FutureTask getTask() { + return mTask; + } + + @Override + public void run() { + mTask.run(); + } + + @Override + public WorkspaceResult call() throws Exception { + List allShortcuts = new ArrayList<>(); + loadWorkspace(allShortcuts, LauncherSettings.Favorites.PREVIEW_CONTENT_URI); + return new WorkspaceResult(mBgDataModel.workspaceItems, mBgDataModel.appWidgets, + mBgDataModel.widgetsModel); + } + } + + private interface WorkspaceFetcher extends Runnable, Callable { + FutureTask getTask(); + + default WorkspaceResult get() { + try { + return getTask().get(5, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + Log.d(TAG, "Error fetching workspace items info", e); + return null; + } + } } private static class WorkspaceResult { diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 804acc3d8c..f27c9da284 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -81,9 +81,13 @@ public class IconCache extends BaseIconCache { private int mPendingIconRequestCount = 0; - public IconCache(Context context, InvariantDeviceProfile inv) { - super(context, LauncherFiles.APP_ICONS_DB, MODEL_EXECUTOR.getLooper(), - inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); + public IconCache(Context context, InvariantDeviceProfile idp) { + this(context, idp, LauncherFiles.APP_ICONS_DB); + } + + public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName) { + super(context, dbFileName, MODEL_EXECUTOR.getLooper(), + idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); mShortcutCachingLogic = new ShortcutCachingLogic(); diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index cbd7c530c5..bf7897e8cc 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -19,8 +19,8 @@ package com.android.launcher3.icons; import android.content.Context; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.graphics.IconShape; +import com.android.launcher3.graphics.LauncherPreviewRenderer; /** * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class @@ -41,6 +41,11 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { * avoid allocating new objects in many cases. */ public static LauncherIcons obtain(Context context, boolean shapeDetection) { + if (context instanceof LauncherPreviewRenderer.PreviewContext) { + return ((LauncherPreviewRenderer.PreviewContext) context).newLauncherIcons(context, + shapeDetection); + } + int poolId; synchronized (sPoolSync) { if (sPool != null) { @@ -52,7 +57,7 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { poolId = sPoolId; } - InvariantDeviceProfile idp = LauncherAppState.getIDP(context); + InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context); return new LauncherIcons(context, idp.fillResIconDpi, idp.iconBitmapSize, poolId, shapeDetection); } @@ -68,7 +73,7 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { private LauncherIcons next; - private LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId, + protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId, boolean shapeDetection) { super(context, fillResIconDpi, iconBitmapSize, shapeDetection); mPoolId = poolId; diff --git a/src/com/android/launcher3/model/GridBackupTable.java b/src/com/android/launcher3/model/GridBackupTable.java index 07a7551c4c..4a1bc4df88 100644 --- a/src/com/android/launcher3/model/GridBackupTable.java +++ b/src/com/android/launcher3/model/GridBackupTable.java @@ -100,12 +100,24 @@ public class GridBackupTable { Process.myUserHandle()), 0); return false; } + return restoreIfBackupExists(Favorites.TABLE_NAME); + } + + public boolean restoreToPreviewIfBackupExists() { + if (!tableExists(mDb, BACKUP_TABLE_NAME)) { + return false; + } + + return restoreIfBackupExists(Favorites.PREVIEW_TABLE_NAME); + } + + private boolean restoreIfBackupExists(String toTableName) { if (loadDBProperties() != STATE_SANITIZED) { return false; } long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser( Process.myUserHandle()); - copyTable(mDb, BACKUP_TABLE_NAME, Favorites.TABLE_NAME, userSerial); + copyTable(mDb, BACKUP_TABLE_NAME, toTableName, userSerial); Log.d(TAG, "Backup table found"); return true; } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index c35c4b9076..3ba740d4d1 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -3,6 +3,7 @@ package com.android.launcher3.model; import static com.android.launcher3.LauncherSettings.Settings.EXTRA_VALUE; import static com.android.launcher3.Utilities.getPointString; import static com.android.launcher3.Utilities.parsePoint; +import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import android.content.ComponentName; import android.content.ContentValues; @@ -14,6 +15,7 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Point; +import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; @@ -29,6 +31,7 @@ import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.graphics.LauncherPreviewRenderer; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; @@ -69,6 +72,7 @@ public class GridSizeMigrationTask { private final SparseArray mUpdateOperations = new SparseArray<>(); private final HashSet mValidPackages; + private final String mTableName; private final int mSrcX, mSrcY; private final int mTrgX, mTrgY; @@ -78,10 +82,12 @@ public class GridSizeMigrationTask { private final int mDestHotseatSize; protected GridSizeMigrationTask(Context context, SQLiteDatabase db, - HashSet validPackages, Point sourceSize, Point targetSize) { + HashSet validPackages, boolean usePreviewTable, Point sourceSize, + Point targetSize) { mContext = context; mDb = db; mValidPackages = validPackages; + mTableName = usePreviewTable ? Favorites.PREVIEW_TABLE_NAME : Favorites.TABLE_NAME; mSrcX = sourceSize.x; mSrcY = sourceSize.y; @@ -97,10 +103,12 @@ public class GridSizeMigrationTask { } protected GridSizeMigrationTask(Context context, SQLiteDatabase db, - HashSet validPackages, int srcHotseatSize, int destHotseatSize) { + HashSet validPackages, boolean usePreviewTable, int srcHotseatSize, + int destHotseatSize) { mContext = context; mDb = db; mValidPackages = validPackages; + mTableName = usePreviewTable ? Favorites.PREVIEW_TABLE_NAME : Favorites.TABLE_NAME; mSrcHotseatSize = srcHotseatSize; @@ -120,7 +128,7 @@ public class GridSizeMigrationTask { // Update items int updateCount = mUpdateOperations.size(); for (int i = 0; i < updateCount; i++) { - mDb.update(Favorites.TABLE_NAME, mUpdateOperations.valueAt(i), + mDb.update(mTableName, mUpdateOperations.valueAt(i), "_id=" + mUpdateOperations.keyAt(i), null); } @@ -128,8 +136,8 @@ public class GridSizeMigrationTask { if (DEBUG) { Log.d(TAG, "Removing items: " + mEntryToRemove.toConcatString()); } - mDb.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery( - Favorites._ID, mEntryToRemove), null); + mDb.delete(mTableName, Utilities.createDbSelectionQuery(Favorites._ID, mEntryToRemove), + null); } return updateCount > 0 || !mEntryToRemove.isEmpty(); @@ -182,8 +190,8 @@ public class GridSizeMigrationTask { } @VisibleForTesting - static IntArray getWorkspaceScreenIds(SQLiteDatabase db) { - return LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME, Favorites.SCREEN, + static IntArray getWorkspaceScreenIds(SQLiteDatabase db, String tableName) { + return LauncherDbUtils.queryIntArray(db, tableName, Favorites.SCREEN, Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP, Favorites.SCREEN, Favorites.SCREEN); } @@ -192,7 +200,7 @@ public class GridSizeMigrationTask { * @return true if any DB change was made */ protected boolean migrateWorkspace() throws Exception { - IntArray allScreens = getWorkspaceScreenIds(mDb); + IntArray allScreens = getWorkspaceScreenIds(mDb, mTableName); if (allScreens.isEmpty()) { throw new Exception("Unable to get workspace screens"); } @@ -244,12 +252,12 @@ public class GridSizeMigrationTask { /** * Migrate a particular screen id. * Strategy: - * 1) For all possible combinations of row and column, pick the one which causes the least - * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])} - * 2) Maintain a list of all lost items before this screen, and add any new item lost from - * this screen to that list as well. - * 3) If all those items from the above list can be placed on this screen, place them - * (otherwise they are placed on a new screen). + * 1) For all possible combinations of row and column, pick the one which causes the least + * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])} + * 2) Maintain a list of all lost items before this screen, and add any new item lost from + * this screen to that list as well. + * 3) If all those items from the above list can be placed on this screen, place them + * (otherwise they are placed on a new screen). */ protected void migrateScreen(int screenId) { // If we are migrating the first screen, do not touch the first row. @@ -362,9 +370,9 @@ public class GridSizeMigrationTask { /** * Tries the remove the provided row and column. * - * @param items all the items on the screen under operation + * @param items all the items on the screen under operation * @param outLoss array of size 2. The first entry is filled with weight loss, and the second - * with the overall item movement. + * with the overall item movement. */ private ArrayList tryRemove(int col, int row, int startY, ArrayList items, float[] outLoss) { @@ -379,13 +387,13 @@ public class GridSizeMigrationTask { for (DbEntry item : items) { if ((item.cellX <= col && (item.spanX + item.cellX) > col) - || (item.cellY <= row && (item.spanY + item.cellY) > row)) { + || (item.cellY <= row && (item.spanY + item.cellY) > row)) { removedItems.add(item); - if (item.cellX >= col) item.cellX --; - if (item.cellY >= row) item.cellY --; + if (item.cellX >= col) item.cellX--; + if (item.cellY >= row) item.cellY--; } else { - if (item.cellX > col) item.cellX --; - if (item.cellY > row) item.cellY --; + if (item.cellX > col) item.cellX--; + if (item.cellY > row) item.cellY--; finalItems.add(item); occupied.markCells(item, true); } @@ -438,9 +446,9 @@ public class GridSizeMigrationTask { /** * Recursively finds a placement for the provided items. * - * @param index the position in {@link #itemsToPlace} to start looking at. - * @param weightLoss total weight loss upto this point - * @param moveCost total move cost upto this point + * @param index the position in {@link #itemsToPlace} to start looking at. + * @param weightLoss total weight loss upto this point + * @param moveCost total move cost upto this point * @param itemsPlaced all the items already placed upto this point */ public void find(int index, float weightLoss, float moveCost, @@ -481,11 +489,11 @@ public class GridSizeMigrationTask { float newMoveCost = moveCost; if (x != myX) { me.cellX = x; - newMoveCost ++; + newMoveCost++; } if (y != myY) { me.cellY = y; - newMoveCost ++; + newMoveCost++; } if (ignoreMove) { newMoveCost = moveCost; @@ -500,35 +508,35 @@ public class GridSizeMigrationTask { // Try resizing horizontally if (myW > me.minSpanX && occupied.isRegionVacant(x, y, myW - 1, myH)) { - me.spanX --; + me.spanX--; occupied.markCells(me, true); // 1 extra move cost find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe); occupied.markCells(me, false); - me.spanX ++; + me.spanX++; } // Try resizing vertically if (myH > me.minSpanY && occupied.isRegionVacant(x, y, myW, myH - 1)) { - me.spanY --; + me.spanY--; occupied.markCells(me, true); // 1 extra move cost find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe); occupied.markCells(me, false); - me.spanY ++; + me.spanY++; } // Try resizing horizontally & vertically if (myH > me.minSpanY && myW > me.minSpanX && occupied.isRegionVacant(x, y, myW - 1, myH - 1)) { - me.spanX --; - me.spanY --; + me.spanX--; + me.spanY--; occupied.markCells(me, true); // 2 extra move cost find(index + 1, weightLoss, newMoveCost + 2, itemsIncludingMe); occupied.markCells(me, false); - me.spanX ++; - me.spanY ++; + me.spanX++; + me.spanY++; } me.cellX = myX; me.cellY = myY; @@ -565,11 +573,11 @@ public class GridSizeMigrationTask { float newMoveCost = moveCost; if (newX != myX) { me.cellX = newX; - newMoveCost ++; + newMoveCost++; } if (newY != myY) { me.cellY = newY; - newMoveCost ++; + newMoveCost++; } if (ignoreMove) { newMoveCost = moveCost; @@ -602,7 +610,7 @@ public class GridSizeMigrationTask { } private ArrayList loadHotseatEntries() { - Cursor c = queryWorkspace( + Cursor c = queryWorkspace( new String[]{ Favorites._ID, // 0 Favorites.ITEM_TYPE, // 1 @@ -787,7 +795,7 @@ public class GridSizeMigrationTask { } protected Cursor queryWorkspace(String[] columns, String where) { - return mDb.query(Favorites.TABLE_NAME, columns, where, null, null, null, null); + return mDb.query(mTableName, columns, where, null, null, null, null); } /** @@ -879,24 +887,44 @@ public class GridSizeMigrationTask { } /** - * Migrates the workspace and hotseat in case their sizes changed. + * Check given a new IDP, if migration is necessary. + */ + public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) { + SharedPreferences prefs = Utilities.getPrefs(context); + String gridSizeString = getPointString(idp.numColumns, idp.numRows); + + return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) + || idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, + idp.numHotseatIcons); + } + + /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ + public static boolean migrateGridIfNeeded(Context context) { + if (context instanceof LauncherPreviewRenderer.PreviewContext) { + return true; + } + return migrateGridIfNeeded(context, null); + } + + /** + * Run the migration algorithm if needed. For preview, we provide the intended idp because it + * has not been changed. If idp is null, we read it from the context, for actual grid migration. * * @return false if the migration failed. */ - public static boolean migrateGridIfNeeded(Context context) { - SharedPreferences prefs = Utilities.getPrefs(context); - InvariantDeviceProfile idp = LauncherAppState.getIDP(context); + public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) { + boolean migrateForPreview = idp != null; + if (!migrateForPreview) { + idp = LauncherAppState.getIDP(context); + } - String gridSizeString = getPointString(idp.numColumns, idp.numRows); - - if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) && - idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, - idp.numHotseatIcons)) { - // Skip if workspace and hotseat sizes have not changed. + if (!needsToMigrate(context, idp)) { return true; } - long migrationStartTime = System.currentTimeMillis(); + SharedPreferences prefs = Utilities.getPrefs(context); + String gridSizeString = getPointString(idp.numColumns, idp.numRows); + long migrationStartTime = SystemClock.elapsedRealtime(); try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call( context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION) .getBinder(Settings.EXTRA_VALUE)) { @@ -907,33 +935,39 @@ public class GridSizeMigrationTask { KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)); boolean dbChanged = false; + if (migrateForPreview) { + copyTable(transaction.getDb(), Favorites.TABLE_NAME, Favorites.PREVIEW_TABLE_NAME, + context); + } GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(), srcHotseatCount, sourceSize.x, sourceSize.y); - if (backupTable.backupOrRestoreAsNeeded()) { + if (migrateForPreview ? backupTable.restoreToPreviewIfBackupExists() + : backupTable.backupOrRestoreAsNeeded()) { dbChanged = true; srcHotseatCount = backupTable.getRestoreHotseatAndGridSize(sourceSize); } HashSet validPackages = getValidPackages(context); - // Hotseat + // Hotseat. if (srcHotseatCount != idp.numHotseatIcons) { // Migrate hotseat. - dbChanged = new GridSizeMigrationTask(context, transaction.getDb(), - validPackages, srcHotseatCount, idp.numHotseatIcons).migrateHotseat(); + dbChanged = new GridSizeMigrationTask(context, transaction.getDb(), validPackages, + migrateForPreview, srcHotseatCount, idp.numHotseatIcons).migrateHotseat(); } // Grid size Point targetSize = new Point(idp.numColumns, idp.numRows); - if (new MultiStepMigrationTask(validPackages, context, transaction.getDb()) - .migrate(sourceSize, targetSize)) { + if (new MultiStepMigrationTask(validPackages, context, transaction.getDb(), + migrateForPreview).migrate(sourceSize, targetSize)) { dbChanged = true; } if (dbChanged) { // Make sure we haven't removed everything. final Cursor c = context.getContentResolver().query( - Favorites.CONTENT_URI, null, null, null, null); + migrateForPreview ? Favorites.PREVIEW_CONTENT_URI : Favorites.CONTENT_URI, + null, null, null, null); boolean hasData = c.moveToNext(); c.close(); if (!hasData) { @@ -942,21 +976,25 @@ public class GridSizeMigrationTask { } transaction.commit(); - Settings.call(context.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + if (!migrateForPreview) { + Settings.call(context.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + } return true; } catch (Exception e) { - Log.e(TAG, "Error during grid migration", e); + Log.e(TAG, "Error during preview grid migration", e); return false; } finally { - Log.v(TAG, "Workspace migration completed in " - + (System.currentTimeMillis() - migrationStartTime)); + Log.v(TAG, "Preview workspace migration completed in " + + (SystemClock.elapsedRealtime() - migrationStartTime)); - // Save current configuration, so that the migration does not run again. - prefs.edit() - .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString) - .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons) - .apply(); + if (!migrateForPreview) { + // Save current configuration, so that the migration does not run again. + prefs.edit() + .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString) + .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons) + .apply(); + } } } @@ -989,7 +1027,7 @@ public class GridSizeMigrationTask { .getBinder(Settings.EXTRA_VALUE)) { GridSizeMigrationTask task = new GridSizeMigrationTask( context, transaction.getDb(), getValidPackages(context), - Integer.MAX_VALUE, Integer.MAX_VALUE); + false /* usePreviewTable */, Integer.MAX_VALUE, Integer.MAX_VALUE); // Load all the valid entries ArrayList items = task.loadHotseatEntries(); @@ -1011,12 +1049,14 @@ public class GridSizeMigrationTask { private final HashSet mValidPackages; private final Context mContext; private final SQLiteDatabase mDb; + private final boolean mUsePreviewTable; public MultiStepMigrationTask(HashSet validPackages, Context context, - SQLiteDatabase db) { + SQLiteDatabase db, boolean usePreviewTable) { mValidPackages = validPackages; mContext = context; mDb = db; + mUsePreviewTable = usePreviewTable; } public boolean migrate(Point sourceSize, Point targetSize) throws Exception { @@ -1052,8 +1092,8 @@ public class GridSizeMigrationTask { } protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception { - return new GridSizeMigrationTask(mContext, mDb, - mValidPackages, sourceSize, nextSize).migrateWorkspace(); + return new GridSizeMigrationTask(mContext, mDb, mValidPackages, mUsePreviewTable, + sourceSize, nextSize).migrateWorkspace(); } } } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java index 63b7191a92..197b29c688 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java @@ -18,6 +18,8 @@ package com.android.launcher3.model; import android.content.Context; +import com.android.launcher3.InvariantDeviceProfile; + /** * This class takes care of shrinking the workspace (by maximum of one row and one column), as a * result of restoring from a larger device or device density change. @@ -28,13 +30,20 @@ public class GridSizeMigrationTaskV2 { } - /** - * Migrates the workspace and hotseat in case their sizes changed. - * - * @return false if the migration failed. - */ + /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ public static boolean migrateGridIfNeeded(Context context) { // To be implemented. return true; } + + /** + * Run the migration algorithm if needed. For preview, we provide the intended idp because it + * has not been changed. If idp is null, we read it from the context, for actual grid migration. + * + * @return false if the migration failed. + */ + public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) { + // To be implemented. + return true; + } } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 49614327ff..2311dcce44 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -28,6 +28,7 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; +import android.net.Uri; import android.os.UserHandle; import android.provider.BaseColumns; import android.text.TextUtils; @@ -64,6 +65,7 @@ public class LoaderCursor extends CursorWrapper { public final LongSparseArray allUsers = new LongSparseArray<>(); + private final Uri mContentUri; private final Context mContext; private final PackageManager mPM; private final IconCache mIconCache; @@ -96,8 +98,10 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor c, LauncherAppState app) { - super(c); + public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app) { + super(cursor); + + mContentUri = contentUri; mContext = app.getContext(); mIconCache = app.getIconCache(); mIDP = app.getInvariantDeviceProfile(); @@ -312,9 +316,8 @@ public class LoaderCursor extends CursorWrapper { public boolean commitDeleted() { if (itemsToRemove.size() > 0) { // Remove dead items - mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI, - Utilities.createDbSelectionQuery( - LauncherSettings.Favorites._ID, itemsToRemove), null); + mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery( + LauncherSettings.Favorites._ID, itemsToRemove), null); return true; } return false; @@ -339,7 +342,7 @@ public class LoaderCursor extends CursorWrapper { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.RESTORED, 0); - mContext.getContentResolver().update(LauncherSettings.Favorites.CONTENT_URI, values, + mContext.getContentResolver().update(mContentUri, values, Utilities.createDbSelectionQuery( LauncherSettings.Favorites._ID, restoredRows), null); } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 6223a2342c..fbf01fc777 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -36,6 +36,7 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.ShortcutInfo; +import android.net.Uri; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; @@ -76,7 +77,6 @@ import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IOUtils; import com.android.launcher3.util.LooperIdleLock; @@ -106,7 +106,7 @@ public class LoaderTask implements Runnable { private final LauncherAppState mApp; private final AllAppsList mBgAllAppsList; - private final BgDataModel mBgDataModel; + protected final BgDataModel mBgDataModel; private FirstScreenBroadcast mFirstScreenBroadcast; @@ -284,6 +284,10 @@ public class LoaderTask implements Runnable { @VisibleForTesting void loadWorkspace(List allDeepShortcuts) { + loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI); + } + + protected void loadWorkspace(List allDeepShortcuts, Uri contentUri) { final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -327,8 +331,8 @@ public class LoaderTask implements Runnable { mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); Map shortcutKeyToPinnedShortcuts = new HashMap<>(); - final LoaderCursor c = new LoaderCursor(contentResolver.query( - LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp); + final LoaderCursor c = new LoaderCursor( + contentResolver.query(contentUri, null, null, null, null), contentUri, mApp); Map widgetProvidersMap = null; diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index 2c843f96ce..f7ecc3f1d7 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -22,10 +22,12 @@ import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.os.Binder; +import android.os.Process; import android.util.Log; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.pm.UserCache; import com.android.launcher3.util.IntArray; import java.util.Locale; @@ -116,6 +118,15 @@ public class LauncherDbUtils { db.execSQL("DROP TABLE IF EXISTS " + tableName); } + /** Copy from table to the to table. */ + public static void copyTable(SQLiteDatabase db, String from, String to, Context context) { + long userSerial = UserCache.INSTANCE.get(context).getSerialNumberForUser( + Process.myUserHandle()); + dropTable(db, to); + Favorites.addTableToDb(db, userSerial, false, to); + db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from); + } + /** * Utility class to simplify managing sqlite transactions */ diff --git a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java index 6d839f3528..c0111b9388 100644 --- a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java +++ b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java @@ -18,7 +18,6 @@ package com.android.launcher3.provider; import android.content.ContentValues; import android.content.Context; -import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Point; @@ -43,7 +42,7 @@ public class LossyScreenMigrationTask extends GridSizeMigrationTask { protected LossyScreenMigrationTask( Context context, InvariantDeviceProfile idp, SQLiteDatabase db) { // Decrease the rows count by 1 - super(context, db, getValidPackages(context), + super(context, db, getValidPackages(context), false /* usePreviewTable */, new Point(idp.numColumns, idp.numRows + 1), new Point(idp.numColumns, idp.numRows)); diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java index 520a9edd57..fc9f8f7ec4 100644 --- a/src/com/android/launcher3/util/MainThreadInitializedObject.java +++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java @@ -22,6 +22,7 @@ import android.os.Looper; import androidx.annotation.VisibleForTesting; +import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext; import com.android.launcher3.util.ResourceBasedOverride.Overrides; import java.util.concurrent.ExecutionException; @@ -39,6 +40,10 @@ public class MainThreadInitializedObject { } public T get(Context context) { + if (context instanceof PreviewContext) { + return ((PreviewContext) context).getObject(this, mProvider); + } + if (mValue == null) { if (Looper.myLooper() == Looper.getMainLooper()) { mValue = TraceHelper.whitelistIpcs("main.thread.object",