From b87f3cdc1c6948f85179526d50d20e47fa47fc9e Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 7 Apr 2021 15:02:37 -0700 Subject: [PATCH] Add support for having more hotseat icons in the DB than we show Split InvariantDeviceProfile#numHotseatIcons into two variables: numDatabaseHotseatIcons and numShownHotseatIcons. These are generally the same, but different DisplayOptions within the same GridOption can choose to show different numbers of hotseat icons while sharing the same database. numDatabaseHotseatIcons is used for all reading/writing/migrating purposes, while numShownHotseatIcons determines how many Hotseat icons to show in the UI. Test: Existing tests pass, added two new migration tests Bug: 184789479 Bug: 171917176 Change-Id: I54583504f61a47a4444b6a637ebb7e3ab31528b7 --- .../hybridhotseat/HotseatEduController.java | 6 +- .../hybridhotseat/HotseatEduDialog.java | 6 +- .../HotseatPredictionController.java | 14 +-- .../hybridhotseat/HotseatRestoreHelper.java | 4 +- .../model/QuickstepModelDelegate.java | 4 +- .../taskbar/TaskbarHotseatController.java | 2 +- res/values/attrs.xml | 3 + .../launcher3/model/BackupRestoreTest.java | 2 +- .../model/GridSizeMigrationTaskTest.java | 4 +- .../model/GridSizeMigrationTaskV2Test.java | 104 +++++++++++++++++- .../launcher3/model/LoaderCursorTest.java | 6 +- .../launcher3/util/LauncherModelHelper.java | 2 +- .../android/launcher3/AutoInstallsLayout.java | 2 +- src/com/android/launcher3/DeviceProfile.java | 4 +- src/com/android/launcher3/Hotseat.java | 4 +- .../launcher3/InvariantDeviceProfile.java | 30 +++-- .../android/launcher3/LauncherProvider.java | 2 +- .../search/AppsSearchContainerLayout.java | 2 +- .../graphics/LauncherPreviewRenderer.java | 4 +- .../model/GridSizeMigrationTask.java | 10 +- .../model/GridSizeMigrationTaskV2.java | 11 +- .../android/launcher3/model/LoaderCursor.java | 6 +- .../android/launcher3/model/ModelWriter.java | 2 +- .../launcher3/provider/ImportDataTask.java | 5 +- .../launcher3/provider/RestoreDbTask.java | 4 +- 25 files changed, 181 insertions(+), 62 deletions(-) diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java index 4451e7a6c1..a6844e48b7 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java @@ -89,7 +89,7 @@ public class HotseatEduController { ArrayList putIntoFolder = new ArrayList<>(); //separate folders and items that can get in folders - for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) { + for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) { View view = mHotseat.getChildAt(i, 0); if (view == null) continue; ItemInfo info = (ItemInfo) view.getTag(); @@ -188,7 +188,7 @@ public class HotseatEduController { .getInt(LauncherSettings.Settings.EXTRA_VALUE); mNewScreens = IntArray.wrap(pageId); } - for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) { + for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) { View child = mHotseat.getChildAt(i, 0); if (child == null || child.getTag() == null) continue; ItemInfo tag = (ItemInfo) child.getTag(); @@ -224,7 +224,7 @@ public class HotseatEduController { void showDimissTip() { if (mHotseat.getShortcutsAndWidgets().getChildCount() - < mLauncher.getDeviceProfile().inv.numHotseatIcons) { + < mLauncher.getDeviceProfile().numShownHotseatIcons) { Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, R.string.hotseat_prediction_settings, null, () -> mLauncher.startActivity(getSettingsIntent())); diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index c3677ea41e..a2ed21143c 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -88,7 +88,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable Rect padding = grid.getHotseatLayoutPadding(); mSampleHotseat.getLayoutParams().height = grid.cellHeightPx; - mSampleHotseat.setGridSize(grid.inv.numHotseatIcons, 1); + mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1); mSampleHotseat.setPadding(padding.left, 0, padding.right, 0); Button turnOnBtn = findViewById(R.id.turn_predictions_on); @@ -178,7 +178,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable } private void populatePreview(List predictions) { - for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) { + for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) { WorkspaceItemInfo info = predictions.get(i); PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info); icon.setEnabled(false); @@ -194,7 +194,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable */ public void show(List predictions) { if (getParent() != null - || predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons + || predictions.size() < mLauncher.getDeviceProfile().numShownHotseatIcons || mHotseatEduController == null) { return; } diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index f297343552..67ed5fb5e5 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -33,10 +33,10 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.Hotseat; -import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; @@ -68,7 +68,7 @@ import java.util.stream.Collectors; * pinning of predicted apps and manages replacement of predicted apps with user drag. */ public class HotseatPredictionController implements DragController.DragListener, - SystemShortcut.Factory, InvariantDeviceProfile.OnIDPChangeListener, + SystemShortcut.Factory, DeviceProfile.OnDeviceProfileChangeListener, DragSource, ViewGroup.OnHierarchyChangeListener { private static final int FLAG_UPDATE_PAUSED = 1 << 0; @@ -115,10 +115,10 @@ public class HotseatPredictionController implements DragController.DragListener, public HotseatPredictionController(QuickstepLauncher launcher) { mLauncher = launcher; mHotseat = launcher.getHotseat(); - mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; + mHotSeatItemsCount = mLauncher.getDeviceProfile().numShownHotseatIcons; mLauncher.getDragController().addDragListener(this); - launcher.getDeviceProfile().inv.addOnChangeListener(this); + launcher.addOnDeviceProfileChangeListener(this); mHotseat.getShortcutsAndWidgets().setOnHierarchyChangeListener(this); } @@ -281,7 +281,7 @@ public class HotseatPredictionController implements DragController.DragListener, * Unregisters callbacks and frees resources */ public void destroy() { - mLauncher.getDeviceProfile().inv.removeOnChangeListener(this); + mLauncher.removeOnDeviceProfileChangeListener(this); } /** @@ -446,8 +446,8 @@ public class HotseatPredictionController implements DragController.DragListener, } @Override - public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) { - this.mHotSeatItemsCount = profile.numHotseatIcons; + public void onDeviceProfileChanged(DeviceProfile profile) { + this.mHotSeatItemsCount = profile.numShownHotseatIcons; } @Override diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java index 90f762e24c..4956fa1b86 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java @@ -44,7 +44,7 @@ public class HotseatRestoreHelper { .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) { InvariantDeviceProfile idp = LauncherAppState.getIDP(context); GridBackupTable backupTable = new GridBackupTable(context, - transaction.getDb(), idp.numHotseatIcons, idp.numColumns, + transaction.getDb(), idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows); backupTable.createCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE); transaction.commit(); @@ -69,7 +69,7 @@ public class HotseatRestoreHelper { } InvariantDeviceProfile idp = LauncherAppState.getIDP(context); GridBackupTable backupTable = new GridBackupTable(context, - transaction.getDb(), idp.numHotseatIcons, idp.numColumns, + transaction.getDb(), idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows); backupTable.restoreFromCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE, true); transaction.commit(); diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index df3657d01d..8c6887250e 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -111,7 +111,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange mDataModel.extraItems.put(CONTAINER_PREDICTION, mAllAppsState.items); WorkspaceItemFactory hotseatFactory = - new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numHotseatIcons); + new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, mIDP.numDatabaseHotseatIcons); mHotseatState.items.setItems( mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get)); mDataModel.extraItems.put(CONTAINER_HOTSEAT_PREDICTION, mHotseatState.items); @@ -211,7 +211,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange registerPredictor(mHotseatState, apm.createAppPredictionSession( new AppPredictionContext.Builder(context) .setUiSurface("hotseat") - .setPredictedTargetCount(mIDP.numHotseatIcons) + .setPredictedTargetCount(mIDP.numDatabaseHotseatIcons) .setExtras(convertDataModelToAppTargetBundle(context, mDataModel)) .build())); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java index b1bafdb879..68829cd0fb 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java @@ -52,7 +52,7 @@ public class TaskbarHotseatController { mLauncher = launcher; mHotseat = mLauncher.getHotseat(); mTaskbarCallbacks = taskbarCallbacks; - mNumHotseatIcons = mLauncher.getDeviceProfile().inv.numHotseatIcons; + mNumHotseatIcons = mLauncher.getDeviceProfile().numShownHotseatIcons; } protected void init() { diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 381b0fef21..699c2e317f 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -175,6 +175,9 @@ + + + diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java index 8baf5a3f27..e7606f734f 100644 --- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java @@ -134,7 +134,7 @@ public class BackupRestoreTest { { APP_ICON, SHORTCUT, SHORTCUT, NO__ICON}, }}, 2, OLD_WORK_PROFILE_ID); // simulates the creation of backup upon restore - new GridBackupTable(RuntimeEnvironment.application, mDb, mIdp.numHotseatIcons, + new GridBackupTable(RuntimeEnvironment.application, mDb, mIdp.numDatabaseHotseatIcons, mIdp.numColumns, mIdp.numRows).doBackup( MY_OLD_PROFILE_ID, GridBackupTable.OPTION_REQUIRES_SANITIZATION); // reset favorites table diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java index 8e00dcb854..d544a0b5f3 100644 --- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java @@ -64,7 +64,7 @@ public class GridSizeMigrationTaskTest { mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0), }; - mIdp.numHotseatIcons = 3; + mIdp.numDatabaseHotseatIcons = 3; new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3) .migrateHotseat(); // First item is dropped as it has the least weight. @@ -81,7 +81,7 @@ public class GridSizeMigrationTaskTest { mModelHelper.addItem(10, 4, HOTSEAT, 0, 0), }; - mIdp.numHotseatIcons = 3; + mIdp.numDatabaseHotseatIcons = 3; new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3) .migrateHotseat(); // First item is dropped as it has the least weight. diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java index cca333c14f..8e49fae1c7 100644 --- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java +++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java @@ -120,7 +120,7 @@ public class GridSizeMigrationTaskV2Test { }; mModelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage7); - mIdp.numHotseatIcons = 4; + mIdp.numDatabaseHotseatIcons = 4; mIdp.numColumns = 4; mIdp.numRows = 4; GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb, @@ -128,16 +128,16 @@ public class GridSizeMigrationTaskV2Test { srcHotseatItems.length); GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb, LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages, - mIdp.numHotseatIcons); + mIdp.numDatabaseHotseatIcons); GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader, - destReader, mIdp.numHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows)); + destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows)); task.migrate(); // Check hotseat items Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT}, "container=" + CONTAINER_HOTSEAT, null, null, null); - assertEquals(c.getCount(), mIdp.numHotseatIcons); + assertEquals(c.getCount(), mIdp.numDatabaseHotseatIcons); int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN); int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT); c.moveToNext(); @@ -186,5 +186,101 @@ public class GridSizeMigrationTaskV2Test { assertTrue(c.getString(intentIndex).contains(testPackage8)); assertEquals(c.getInt(cellXIndex), 0); assertEquals(c.getInt(cellYIndex), 2); + + c.close(); + } + + @Test + public void migrateToLargerHotseat() { + int[] srcHotseatItems = { + mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI), + mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI), + mModelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI), + mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI), + }; + + int numSrcDatabaseHotseatIcons = srcHotseatItems.length; + mIdp.numDatabaseHotseatIcons = 6; + mIdp.numColumns = 4; + mIdp.numRows = 4; + GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb, + LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages, + numSrcDatabaseHotseatIcons); + GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb, + LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages, + mIdp.numDatabaseHotseatIcons); + GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader, + destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows)); + task.migrate(); + + // Check hotseat items + Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT}, + "container=" + CONTAINER_HOTSEAT, null, null, null); + assertEquals(c.getCount(), numSrcDatabaseHotseatIcons); + int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN); + int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 0); + assertTrue(c.getString(intentIndex).contains(testPackage1)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 1); + assertTrue(c.getString(intentIndex).contains(testPackage2)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 2); + assertTrue(c.getString(intentIndex).contains(testPackage3)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 3); + assertTrue(c.getString(intentIndex).contains(testPackage4)); + + c.close(); + } + + @Test + public void migrateFromLargerHotseat() { + int[] srcHotseatItems = { + mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI), + -1, + mModelHelper.addItem(SHORTCUT, 2, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI), + mModelHelper.addItem(APP_ICON, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI), + mModelHelper.addItem(SHORTCUT, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI), + mModelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI), + }; + + int numSrcDatabaseHotseatIcons = srcHotseatItems.length; + mIdp.numDatabaseHotseatIcons = 4; + mIdp.numColumns = 4; + mIdp.numRows = 4; + GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb, + LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages, + numSrcDatabaseHotseatIcons); + GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb, + LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages, + mIdp.numDatabaseHotseatIcons); + GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader, + destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows)); + task.migrate(); + + // Check hotseat items + Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + new String[]{LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.INTENT}, + "container=" + CONTAINER_HOTSEAT, null, null, null); + assertEquals(c.getCount(), mIdp.numDatabaseHotseatIcons); + int screenIndex = c.getColumnIndex(LauncherSettings.Favorites.SCREEN); + int intentIndex = c.getColumnIndex(LauncherSettings.Favorites.INTENT); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 0); + assertTrue(c.getString(intentIndex).contains(testPackage1)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 1); + assertTrue(c.getString(intentIndex).contains(testPackage2)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 2); + assertTrue(c.getString(intentIndex).contains(testPackage3)); + c.moveToNext(); + assertEquals(c.getInt(screenIndex), 3); + assertTrue(c.getString(intentIndex).contains(testPackage4)); + + c.close(); } } diff --git a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java index fb08c56a40..800311afb6 100644 --- a/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -160,7 +160,7 @@ public class LoaderCursorTest { public void checkItemPlacement_outsideBounds() { mIDP.numRows = 4; mIDP.numColumns = 4; - mIDP.numHotseatIcons = 3; + mIDP.numDatabaseHotseatIcons = 3; // Item outside screen bounds are not placed assertFalse(mLoaderCursor.checkItemPlacement( @@ -171,7 +171,7 @@ public class LoaderCursorTest { public void checkItemPlacement_overlappingItems() { mIDP.numRows = 4; mIDP.numColumns = 4; - mIDP.numHotseatIcons = 3; + mIDP.numDatabaseHotseatIcons = 3; // Overlapping mItems are not placed assertTrue(mLoaderCursor.checkItemPlacement( @@ -197,7 +197,7 @@ public class LoaderCursorTest { public void checkItemPlacement_hotseat() { mIDP.numRows = 4; mIDP.numColumns = 4; - mIDP.numHotseatIcons = 3; + mIDP.numDatabaseHotseatIcons = 3; // Hotseat mItems are only placed based on screenId assertTrue(mLoaderCursor.checkItemPlacement( diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java index 849f98b8ff..846e2019a0 100644 --- a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -355,7 +355,7 @@ public class LauncherModelHelper { throws Exception { Context context = RuntimeEnvironment.application; InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context); - idp.numRows = idp.numColumns = idp.numHotseatIcons = DEFAULT_GRID_SIZE; + idp.numRows = idp.numColumns = idp.numDatabaseHotseatIcons = DEFAULT_GRID_SIZE; idp.iconBitmapSize = DEFAULT_BITMAP_SIZE; Settings.Secure.putString(context.getContentResolver(), diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index f61bc055e2..5b655a4740 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -89,7 +89,7 @@ public class AutoInstallsLayout { // Try with grid size and hotseat count String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT, - grid.numColumns, grid.numRows, grid.numHotseatIcons); + grid.numColumns, grid.numRows, grid.numDatabaseHotseatIcons); int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg); // Try with only grid size diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 35b0f27c79..985a445f81 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -137,6 +137,7 @@ public class DeviceProfile { public int folderChildDrawablePaddingPx; // Hotseat + public final int numShownHotseatIcons; public int hotseatCellHeightPx; // In portrait: size = height, in landscape: size = width public int hotseatBarSizePx; @@ -293,6 +294,7 @@ public class DeviceProfile { workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x); + numShownHotseatIcons = inv.numShownHotseatIcons; hotseatBarTopPaddingPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding); hotseatBarBottomPaddingPx = (isTallDevice ? 0 @@ -735,7 +737,7 @@ public class DeviceProfile { // for this, we pad the left and right of the hotseat with half of the difference of a // workspace cell vs a hotseat cell. float workspaceCellWidth = (float) widthPx / inv.numColumns; - float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons; + float hotseatCellWidth = (float) widthPx / inv.numShownHotseatIcons; int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2); mHotseatPadding.set( hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 5429806ede..da41200040 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -92,9 +92,9 @@ public class Hotseat extends CellLayout implements Insettable { mHasVerticalHotseat = hasVerticalHotseat; InvariantDeviceProfile idp = mActivity.getDeviceProfile().inv; if (hasVerticalHotseat) { - setGridSize(1, idp.numHotseatIcons); + setGridSize(1, idp.numShownHotseatIcons); } else { - setGridSize(idp.numHotseatIcons, 1); + setGridSize(idp.numShownHotseatIcons, 1); } } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 5612dafe23..f19877793b 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -122,7 +122,14 @@ public class InvariantDeviceProfile { /** * Number of icons inside the hotseat area. */ - public int numHotseatIcons; + protected int numShownHotseatIcons; + + /** + * Number of icons inside the hotseat area that is stored in the database. This is greater than + * or equal to numnShownHotseatIcons, allowing for a seamless transition between two hotseat + * sizes that share the same DB. + */ + public int numDatabaseHotseatIcons; /** * Number of columns in the all apps list. @@ -165,7 +172,8 @@ public class InvariantDeviceProfile { iconBitmapSize = p.iconBitmapSize; iconTextSize = p.iconTextSize; landscapeIconTextSize = p.landscapeIconTextSize; - numHotseatIcons = p.numHotseatIcons; + numShownHotseatIcons = p.numShownHotseatIcons; + numDatabaseHotseatIcons = p.numDatabaseHotseatIcons; numAllAppsColumns = p.numAllAppsColumns; isScalable = p.isScalable; devicePaddingId = p.devicePaddingId; @@ -190,7 +198,7 @@ public class InvariantDeviceProfile { Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply(); } Utilities.getPrefs(context).edit() - .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, numHotseatIcons) + .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, numDatabaseHotseatIcons) .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, getPointString(numColumns, numRows)) .apply(); @@ -229,6 +237,7 @@ public class InvariantDeviceProfile { .add(myDisplayOption); result.iconSize = defaultDisplayOption.iconSize; result.landscapeIconSize = defaultDisplayOption.landscapeIconSize; + result.numShownHotseatIcons = myDisplayOption.numShownHotseatIcons; if (defaultDisplayOption.allAppsIconSize < myDisplayOption.allAppsIconSize) { result.allAppsIconSize = defaultDisplayOption.allAppsIconSize; result.numAllAppsColumns = defaultDisplayOption.numAllAppsColumns; @@ -279,7 +288,7 @@ public class InvariantDeviceProfile { GridOption closestProfile = displayOption.grid; numRows = closestProfile.numRows; numColumns = closestProfile.numColumns; - numHotseatIcons = closestProfile.numHotseatIcons; + numDatabaseHotseatIcons = closestProfile.numDatabaseHotseatIcons; dbFile = closestProfile.dbFile; defaultLayoutId = closestProfile.defaultLayoutId; demoModeLayoutId = closestProfile.demoModeLayoutId; @@ -301,6 +310,7 @@ public class InvariantDeviceProfile { minCellHeight = displayOption.minCellHeight; minCellWidth = displayOption.minCellWidth; borderSpacing = displayOption.borderSpacing; + numShownHotseatIcons = Math.round(displayOption.numShownHotseatIcons); numAllAppsColumns = Math.round(displayOption.numAllAppsColumns); if (Utilities.isGridOptionsEnabled(context)) { @@ -391,7 +401,7 @@ public class InvariantDeviceProfile { numColumns != oldProfile.numColumns || numFolderColumns != oldProfile.numFolderColumns || numFolderRows != oldProfile.numFolderRows || - numHotseatIcons != oldProfile.numHotseatIcons) { + numDatabaseHotseatIcons != oldProfile.numDatabaseHotseatIcons) { changeFlags |= CHANGE_FLAG_GRID; } @@ -619,7 +629,7 @@ public class InvariantDeviceProfile { private final int numFolderRows; private final int numFolderColumns; - private final int numHotseatIcons; + private final int numDatabaseHotseatIcons; private final String dbFile; @@ -645,7 +655,7 @@ public class InvariantDeviceProfile { R.styleable.GridDisplayOption_defaultLayoutId, 0); demoModeLayoutId = a.getResourceId( R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId); - numHotseatIcons = a.getInt( + numDatabaseHotseatIcons = a.getInt( R.styleable.GridDisplayOption_numHotseatIcons, numColumns); numFolderRows = a.getInt( R.styleable.GridDisplayOption_numFolderRows, numRows); @@ -673,6 +683,7 @@ public class InvariantDeviceProfile { private final float minHeightDps; private final boolean canBeDefault; + private float numShownHotseatIcons; private float numAllAppsColumns; private float minCellHeight; private float minCellWidth; @@ -695,6 +706,8 @@ public class InvariantDeviceProfile { minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0); canBeDefault = a.getBoolean( R.styleable.ProfileDisplayOption_canBeDefault, false); + numShownHotseatIcons = a.getInt(R.styleable.ProfileDisplayOption_numShownHotseatIcons, + grid.numDatabaseHotseatIcons); numAllAppsColumns = a.getInt(R.styleable.ProfileDisplayOption_numAllAppsColumns, grid.numColumns); @@ -725,6 +738,7 @@ public class InvariantDeviceProfile { minWidthDps = 0; minHeightDps = 0; canBeDefault = false; + numShownHotseatIcons = 0; numAllAppsColumns = 0; minCellHeight = 0; minCellWidth = 0; @@ -732,6 +746,7 @@ public class InvariantDeviceProfile { } private DisplayOption multiply(float w) { + numShownHotseatIcons *= w; numAllAppsColumns *= w; iconSize *= w; landscapeIconSize *= w; @@ -746,6 +761,7 @@ public class InvariantDeviceProfile { } private DisplayOption add(DisplayOption p) { + numShownHotseatIcons += p.numShownHotseatIcons; numAllAppsColumns += p.numAllAppsColumns; iconSize += p.iconSize; landscapeIconSize += p.landscapeIconSize; diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 2ec5e90280..39b16fd8d6 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -618,7 +618,7 @@ public class LauncherProvider extends ContentProvider { .appendQueryParameter("version", "1") .appendQueryParameter("gridWidth", Integer.toString(grid.numColumns)) .appendQueryParameter("gridHeight", Integer.toString(grid.numRows)) - .appendQueryParameter("hotseatSize", Integer.toString(grid.numHotseatIcons)) + .appendQueryParameter("hotseatSize", Integer.toString(grid.numDatabaseHotseatIcons)) .build(); } diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index a8185d6eba..24912173ff 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -106,7 +106,7 @@ public class AppsSearchContainerLayout extends ExtendedEditText - mAppsView.getActiveRecyclerView().getPaddingRight(); int cellWidth = DeviceProfile.calculateCellWidth(rowWidth, dp.cellLayoutBorderSpacingPx, - dp.inv.numHotseatIcons); + dp.numShownHotseatIcons); int iconVisibleSize = Math.round(ICON_VISIBLE_AREA_FACTOR * dp.iconSizePx); int iconPadding = cellWidth - iconVisibleSize; diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index 5e9b179d6a..31764c57f5 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -467,7 +467,7 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper } } IntArray ranks = getMissingHotseatRanks(currentWorkspaceItems, - mIdp.numHotseatIcons); + mDp.numShownHotseatIcons); List predictions = workspaceResult.mHotseatPredictions == null ? Collections.emptyList() : workspaceResult.mHotseatPredictions.items; int count = Math.min(ranks.size(), predictions.size()); @@ -484,7 +484,7 @@ public class LauncherPreviewRenderer extends ContextThemeWrapper } } else { // Add hotseat icons - for (int i = 0; i < mIdp.numHotseatIcons; i++) { + for (int i = 0; i < mDp.numShownHotseatIcons; i++) { WorkspaceItemInfo info = new WorkspaceItemInfo(mWorkspaceItemInfo); info.container = Favorites.CONTAINER_HOTSEAT; info.screenId = i; diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index 804e72ee29..6a75e6254d 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -893,7 +893,7 @@ public class GridSizeMigrationTask { 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, -1); + || idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1); } /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ @@ -928,7 +928,7 @@ public class GridSizeMigrationTask { .getBinder(Settings.EXTRA_VALUE)) { int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, - idp.numHotseatIcons); + idp.numDatabaseHotseatIcons); Point sourceSize = parsePoint(prefs.getString( KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)); @@ -948,10 +948,10 @@ public class GridSizeMigrationTask { HashSet validPackages = getValidPackages(context); // Hotseat. - if (srcHotseatCount != idp.numHotseatIcons + if (srcHotseatCount != idp.numDatabaseHotseatIcons && new GridSizeMigrationTask(context, transaction.getDb(), validPackages, migrateForPreview, srcHotseatCount, - idp.numHotseatIcons).migrateHotseat()) { + idp.numDatabaseHotseatIcons).migrateHotseat()) { dbChanged = true; } @@ -991,7 +991,7 @@ public class GridSizeMigrationTask { // 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) + .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons) .apply(); } } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java index c6c0791a17..cee93041e5 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java @@ -110,7 +110,7 @@ public class GridSizeMigrationTaskV2 { 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, -1); + || idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1); } /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ @@ -148,7 +148,8 @@ public class GridSizeMigrationTaskV2 { SharedPreferences prefs = Utilities.getPrefs(context); String gridSizeString = getPointString(idp.numColumns, idp.numRows); HashSet validPackages = getValidPackages(context); - int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons); + int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, + idp.numDatabaseHotseatIcons); if (migrateForPreview) { if (!LauncherSettings.Settings.call( @@ -177,11 +178,11 @@ public class GridSizeMigrationTaskV2 { DbReader destReader = new DbReader(t.getDb(), migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME : LauncherSettings.Favorites.TABLE_NAME, - context, validPackages, idp.numHotseatIcons); + context, validPackages, idp.numDatabaseHotseatIcons); Point targetSize = new Point(idp.numColumns, idp.numRows); GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(), - srcReader, destReader, idp.numHotseatIcons, targetSize); + srcReader, destReader, idp.numDatabaseHotseatIcons, targetSize); task.migrate(); if (!migrateForPreview) { @@ -202,7 +203,7 @@ public class GridSizeMigrationTaskV2 { // 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) + .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons) .apply(); } } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 19d9af98dc..897b02ede2 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -410,10 +410,10 @@ public class LoaderCursor extends CursorWrapper { final GridOccupancy hotseatOccupancy = occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT); - if (item.screenId >= mIDP.numHotseatIcons) { + if (item.screenId >= mIDP.numDatabaseHotseatIcons) { Log.e(TAG, "Error loading shortcut " + item + " into hotseat position " + item.screenId - + ", position out of bounds: (0 to " + (mIDP.numHotseatIcons - 1) + + ", position out of bounds: (0 to " + (mIDP.numDatabaseHotseatIcons - 1) + ")"); return false; } @@ -429,7 +429,7 @@ public class LoaderCursor extends CursorWrapper { return true; } } else { - final GridOccupancy occupancy = new GridOccupancy(mIDP.numHotseatIcons, 1); + final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1); occupancy.cells[item.screenId][0] = true; occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy); return true; diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 312435d175..080ce20f31 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -91,7 +91,7 @@ public class ModelWriter { // in the hotseat if (container == Favorites.CONTAINER_HOTSEAT) { item.screenId = mHasVerticalHotseat - ? LauncherAppState.getIDP(mContext).numHotseatIcons - cellY - 1 : cellX; + ? LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons - cellY - 1 : cellX; } else { item.screenId = screenId; } diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java index a5462a6c34..c9af2fe6fc 100644 --- a/src/com/android/launcher3/provider/ImportDataTask.java +++ b/src/com/android/launcher3/provider/ImportDataTask.java @@ -284,8 +284,9 @@ public class ImportDataTask { insertOperations.clear(); } - IntSparseArrayMap hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext); - int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons; + IntSparseArrayMap hotseatItems = GridSizeMigrationTask + .removeBrokenHotseatItems(mContext); + int myHotseatCount = LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons; if (hotseatItems.size() < myHotseatCount) { // Insufficient hotseat items. Add a few more. HotseatParserCallback parserCallback = new HotseatParserCallback( diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index 53183bf210..223f4f1937 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -103,7 +103,7 @@ public class RestoreDbTask { */ private void backupWorkspace(Context context, SQLiteDatabase db) throws Exception { InvariantDeviceProfile idp = LauncherAppState.getIDP(context); - new GridBackupTable(context, db, idp.numHotseatIcons, idp.numColumns, idp.numRows) + new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows) .doBackup(getDefaultProfileId(db), GridBackupTable.OPTION_REQUIRES_SANITIZATION); } @@ -111,7 +111,7 @@ public class RestoreDbTask { @NonNull DatabaseHelper helper, @NonNull BackupManager backupManager) throws Exception { final InvariantDeviceProfile idp = LauncherAppState.getIDP(context); - GridBackupTable backupTable = new GridBackupTable(context, db, idp.numHotseatIcons, + GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows); if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) { int itemsDeleted = sanitizeDB(helper, db, backupManager);