1e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalpackage com.android.launcher3.model; 2e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 3e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.ComponentName; 4e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.ContentProviderOperation; 5e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.ContentValues; 6e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.Context; 7e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.Intent; 8e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.SharedPreferences; 9e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.content.pm.PackageInfo; 10a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyalimport android.content.pm.PackageManager; 11e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.database.Cursor; 12e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.graphics.Point; 13f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyalimport android.net.Uri; 14e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.text.TextUtils; 15e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport android.util.Log; 16e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 17e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.InvariantDeviceProfile; 18e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.ItemInfo; 19e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.LauncherAppState; 20e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.LauncherAppWidgetProviderInfo; 21e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.LauncherModel; 22e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.LauncherProvider; 23e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.LauncherSettings; 24e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.LauncherSettings.Favorites; 25e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.Utilities; 26da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyalimport com.android.launcher3.Workspace; 272e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyalimport com.android.launcher3.compat.AppWidgetManagerCompat; 28e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.compat.PackageInstallerCompat; 29a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyalimport com.android.launcher3.config.FeatureFlags; 30ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyalimport com.android.launcher3.util.GridOccupancy; 31e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport com.android.launcher3.util.LongArrayMap; 32e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 33e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport java.util.ArrayList; 34e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport java.util.Collections; 35e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport java.util.HashMap; 36e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyalimport java.util.HashSet; 37f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyalimport java.util.Locale; 38e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 39e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal/** 40e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * This class takes care of shrinking the workspace (by maximum of one row and one column), as a 41f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal * result of restoring from a larger device or device density change. 42e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 43f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyalpublic class GridSizeMigrationTask { 44e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 45f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal public static boolean ENABLED = Utilities.isNycOrAbove(); 466579e1eee8a6fce44f020d40c3bbdbf245d6c12cSunny Goyal 47f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal private static final String TAG = "GridSizeMigrationTask"; 48d934e0b0b7b60c9457fd0eb615355c16bac1a285Sunny Goyal private static final boolean DEBUG = true; 49e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 50f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal private static final String KEY_MIGRATION_SRC_WORKSPACE_SIZE = "migration_src_workspace_size"; 51bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal private static final String KEY_MIGRATION_SRC_HOTSEAT_COUNT = "migration_src_hotseat_count"; 52f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 53e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // These are carefully selected weights for various item types (Math.random?), to allow for 54f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // the least absurd migration experience. 55e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private static final float WT_SHORTCUT = 1; 56e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private static final float WT_APPLICATION = 0.8f; 57e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private static final float WT_WIDGET_MIN = 2; 58e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private static final float WT_WIDGET_FACTOR = 0.6f; 59e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private static final float WT_FOLDER_FACTOR = 0.5f; 60e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 61e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private final Context mContext; 62e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private final InvariantDeviceProfile mIdp; 63e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 64f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private final HashMap<String, Point> mWidgetMinSize = new HashMap<>(); 65f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private final ContentValues mTempValues = new ContentValues(); 66a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected final ArrayList<Long> mEntryToRemove = new ArrayList<>(); 67f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private final ArrayList<ContentProviderOperation> mUpdateOperations = new ArrayList<>(); 68a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected final ArrayList<DbEntry> mCarryOver = new ArrayList<>(); 69f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private final HashSet<String> mValidPackages; 70e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 71e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private final int mSrcX, mSrcY; 72f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal private final int mTrgX, mTrgY; 73e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private final boolean mShouldRemoveX, mShouldRemoveY; 74e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 75f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal private final int mSrcHotseatSize; 76f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private final int mDestHotseatSize; 77f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 78f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected GridSizeMigrationTask(Context context, InvariantDeviceProfile idp, 79eb77aaea8990ede3ba774c7b92d48d098bda0f24Sunny Goyal HashSet<String> validPackages, Point sourceSize, Point targetSize) { 80e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mContext = context; 81f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mValidPackages = validPackages; 82f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mIdp = idp; 83e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 84e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mSrcX = sourceSize.x; 85e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mSrcY = sourceSize.y; 86e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 87f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mTrgX = targetSize.x; 88f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mTrgY = targetSize.y; 89e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 90e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mShouldRemoveX = mTrgX < mSrcX; 91e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mShouldRemoveY = mTrgY < mSrcY; 92f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 93f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Non-used variables 94bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal mSrcHotseatSize = mDestHotseatSize = -1; 95e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 96e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 97f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected GridSizeMigrationTask(Context context, 98f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal InvariantDeviceProfile idp, HashSet<String> validPackages, 99bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal int srcHotseatSize, int destHotseatSize) { 100f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mContext = context; 101f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mIdp = idp; 102f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mValidPackages = validPackages; 103e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 104f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mSrcHotseatSize = srcHotseatSize; 105e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 106f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mDestHotseatSize = destHotseatSize; 107f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 108f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Non-used variables 109f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mSrcX = mSrcY = mTrgX = mTrgY = -1; 110f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mShouldRemoveX = mShouldRemoveY = false; 111f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 112f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 113f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 114f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * Applied all the pending DB operations 115f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * @return true if any DB operation was commited. 116f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 117f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private boolean applyOperations() throws Exception { 118f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // Update items 119f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (!mUpdateOperations.isEmpty()) { 120f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, mUpdateOperations); 121f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 122f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 123f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (!mEntryToRemove.isEmpty()) { 124f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (DEBUG) { 125f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Log.d(TAG, "Removing items: " + TextUtils.join(", ", mEntryToRemove)); 126f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 127f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI, 128f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Utilities.createDbSelectionQuery( 129f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal LauncherSettings.Favorites._ID, mEntryToRemove), null); 130f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 131f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 132f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return !mUpdateOperations.isEmpty() || !mEntryToRemove.isEmpty(); 133f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 134f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 135f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal /** 136f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal * To migrate hotseat, we load all the entries in order (LTR or RTL) and arrange them 137f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal * in the order in the new hotseat while keeping an empty space for all-apps. If the number of 138f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal * entries is more than what can fit in the new hotseat, we drop the entries with least weight. 139f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal * For weight calculation {@see #WT_SHORTCUT}, {@see #WT_APPLICATION} 140f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal * & {@see #WT_FOLDER_FACTOR}. 141f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * @return true if any DB change was made 142f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal */ 143f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected boolean migrateHotseat() throws Exception { 144f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal ArrayList<DbEntry> items = loadHotseatEntries(); 145f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 146803896767b37e447bcdff7be6b9872612e93b7bfSunny Goyal int requiredCount = FeatureFlags.NO_ALL_APPS_ICON ? mDestHotseatSize : mDestHotseatSize - 1; 147f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 148f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal while (items.size() > requiredCount) { 149f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // Pick the center item by default. 150f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal DbEntry toRemove = items.get(items.size() / 2); 151f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 152f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // Find the item with least weight. 153f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal for (DbEntry entry : items) { 154f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (entry.weight < toRemove.weight) { 155f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal toRemove = entry; 156f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 157f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 158f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 159f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal mEntryToRemove.add(toRemove.id); 160f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal items.remove(toRemove); 161f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 162f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 163f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // Update screen IDS 164f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal int newScreenId = 0; 165f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal for (DbEntry entry : items) { 166f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (entry.screenId != newScreenId) { 167f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.screenId = newScreenId; 168f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 169f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // These values does not affect the item position, but we should set them 170f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // to something other than -1. 171f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.cellX = newScreenId; 172f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.cellY = 0; 173f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 174f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal update(entry); 175f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 176f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 177f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal newScreenId++; 178bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal if (!FeatureFlags.NO_ALL_APPS_ICON && mIdp.isAllAppsButtonRank(newScreenId)) { 179f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal newScreenId++; 180f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 181f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 182f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 183f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return applyOperations(); 184f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 185f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 186f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 187f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * @return true if any DB change was made 188f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 189f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal protected boolean migrateWorkspace() throws Exception { 190e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<Long> allScreens = LauncherModel.loadWorkspaceScreensDb(mContext); 191e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (allScreens.isEmpty()) { 192e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal throw new Exception("Unable to get workspace screens"); 193e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 194e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 195e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (long screenId : allScreens) { 196e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (DEBUG) { 197e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal Log.d(TAG, "Migrating " + screenId); 198e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 199e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal migrateScreen(screenId); 200e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 201e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 202e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!mCarryOver.isEmpty()) { 203e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal LongArrayMap<DbEntry> itemMap = new LongArrayMap<>(); 204e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry e : mCarryOver) { 205e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal itemMap.put(e.id, e); 206e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 207e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 208e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal do { 209e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Some items are still remaining. Try adding a few new screens. 210e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 211e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // At every iteration, make sure that at least one item is removed from 212e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed, 213e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // break the loop and abort migration by throwing an exception. 214e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal OptimalPlacementSolution placement = new OptimalPlacementSolution( 215da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true); 216e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal placement.find(); 217e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (placement.finalPlacedItems.size() > 0) { 218d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal long newScreenId = LauncherSettings.Settings.call( 219d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal mContext.getContentResolver(), 220d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal LauncherSettings.Settings.METHOD_NEW_SCREEN_ID) 221d249748abf357925b326d57ab68eb6c2b23c4ef6Sunny Goyal .getLong(LauncherSettings.Settings.EXTRA_VALUE); 222f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 223e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal allScreens.add(newScreenId); 224e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry item : placement.finalPlacedItems) { 225e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!mCarryOver.remove(itemMap.get(item.id))) { 226e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal throw new Exception("Unable to find matching items"); 227e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 228e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal item.screenId = newScreenId; 229e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal update(item); 230e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 231e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else { 232e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal throw new Exception("None of the items can be placed on an empty screen"); 233e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 234e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 235e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } while (!mCarryOver.isEmpty()); 236e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 237f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Update screens 238f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; 239f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mUpdateOperations.add(ContentProviderOperation.newDelete(uri).build()); 240f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal int count = allScreens.size(); 241f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal for (int i = 0; i < count; i++) { 242f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal ContentValues v = new ContentValues(); 243f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal long screenId = allScreens.get(i); 244f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal v.put(LauncherSettings.WorkspaceScreens._ID, screenId); 245f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); 246f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mUpdateOperations.add(ContentProviderOperation.newInsert(uri).withValues(v).build()); 247f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 248e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 249f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return applyOperations(); 250e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 251e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 252e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 253e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Migrate a particular screen id. 254e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Strategy: 255e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * 1) For all possible combinations of row and column, pick the one which causes the least 256da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])} 257e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * 2) Maintain a list of all lost items before this screen, and add any new item lost from 258e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * this screen to that list as well. 259e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * 3) If all those items from the above list can be placed on this screen, place them 260e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * (otherwise they are placed on a new screen). 261e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 262a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected void migrateScreen(long screenId) { 263da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal // If we are migrating the first screen, do not touch the first row. 264a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal int startY = (FeatureFlags.QSB_ON_FIRST_SCREEN && screenId == Workspace.FIRST_SCREEN_ID) 265a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal ? 1 : 0; 266da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal 267f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal ArrayList<DbEntry> items = loadWorkspaceEntries(screenId); 268e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 269e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int removedCol = Integer.MAX_VALUE; 270e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int removedRow = Integer.MAX_VALUE; 271e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 272e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // removeWt represents the cost function for loss of items during migration, and moveWt 273e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // represents the cost function for repositioning the items. moveWt is only considered if 274e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // removeWt is same for two different configurations. 275e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Start with Float.MAX_VALUE (assuming full data) and pick the configuration with least 276e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // cost. 277e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float removeWt = Float.MAX_VALUE; 278e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float moveWt = Float.MAX_VALUE; 279e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float[] outLoss = new float[2]; 280e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> finalItems = null; 281e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 282e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Try removing all possible combinations 283e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (int x = 0; x < mSrcX; x++) { 284a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // Try removing the rows first from bottom. This keeps the workspace 285a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // nicely aligned with hotseat. 286a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal for (int y = mSrcY - 1; y >= startY; y--) { 287e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Use a deep copy when trying out a particular combination as it can change 288e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // the underlying object. 289da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss); 290e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 291e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) { 292e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal removeWt = outLoss[0]; 293e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal moveWt = outLoss[1]; 294e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal removedCol = mShouldRemoveX ? x : removedCol; 295e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal removedRow = mShouldRemoveY ? y : removedRow; 296e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal finalItems = itemsOnScreen; 297e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 298e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 299e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // No need to loop over all rows, if a row removal is not needed. 300e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!mShouldRemoveY) { 301e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal break; 302e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 303e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 304e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 305e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!mShouldRemoveX) { 306e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal break; 307e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 308e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 309e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 310e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (DEBUG) { 311e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal Log.d(TAG, String.format("Removing row %d, column %d on screen %d", 312e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal removedRow, removedCol, screenId)); 313e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 314e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 315e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal LongArrayMap<DbEntry> itemMap = new LongArrayMap<>(); 316e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry e : deepCopy(items)) { 317e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal itemMap.put(e.id, e); 318e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 319e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 320e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry item : finalItems) { 321e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal DbEntry org = itemMap.get(item.id); 322e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal itemMap.remove(item.id); 323e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 324e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Check if update is required 325e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!item.columnsSame(org)) { 326e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal update(item); 327e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 328e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 329e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 330e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // The remaining items in {@link #itemMap} are those which didn't get placed. 331e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry item : itemMap) { 332e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mCarryOver.add(item); 333e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 334e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 335e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!mCarryOver.isEmpty() && removeWt == 0) { 336e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // No new items were removed in this step. Try placing all the items on this screen. 337ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY); 338da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal occupied.markCells(0, 0, mTrgX, startY, true); 339e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry item : finalItems) { 340ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(item, true); 341e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 342e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 343e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, 344da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal deepCopy(mCarryOver), startY, true); 345e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal placement.find(); 346e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (placement.lowestWeightLoss == 0) { 347e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // All items got placed 348e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 349e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry item : placement.finalPlacedItems) { 350e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal item.screenId = screenId; 351e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal update(item); 352e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 353e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 354e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mCarryOver.clear(); 355e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 356e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 357e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 358e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 359e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 360e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Updates an item in the DB. 361e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 362a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected void update(DbEntry item) { 363e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mTempValues.clear(); 364e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal item.addToContentValues(mTempValues); 365e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mUpdateOperations.add(ContentProviderOperation 366e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal .newUpdate(LauncherSettings.Favorites.getContentUri(item.id)) 367e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal .withValues(mTempValues).build()); 368e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 369e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 370e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 371e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Tries the remove the provided row and column. 372e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @param items all the items on the screen under operation 373e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @param outLoss array of size 2. The first entry is filled with weight loss, and the second 374e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * with the overall item movement. 375e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 376da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal private ArrayList<DbEntry> tryRemove(int col, int row, int startY, 377da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal ArrayList<DbEntry> items, float[] outLoss) { 378ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY); 379da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal occupied.markCells(0, 0, mTrgX, startY, true); 380e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 381e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal col = mShouldRemoveX ? col : Integer.MAX_VALUE; 382e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal row = mShouldRemoveY ? row : Integer.MAX_VALUE; 383e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 384e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> finalItems = new ArrayList<>(); 385e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> removedItems = new ArrayList<>(); 386e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 387e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry item : items) { 388e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if ((item.cellX <= col && (item.spanX + item.cellX) > col) 389e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal || (item.cellY <= row && (item.spanY + item.cellY) > row)) { 390e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal removedItems.add(item); 391e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (item.cellX >= col) item.cellX --; 392e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (item.cellY >= row) item.cellY --; 393e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else { 394e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (item.cellX > col) item.cellX --; 395e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (item.cellY > row) item.cellY --; 396e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal finalItems.add(item); 397ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(item, true); 398e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 399e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 400e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 401da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal OptimalPlacementSolution placement = 402da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal new OptimalPlacementSolution(occupied, removedItems, startY); 403e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal placement.find(); 404e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal finalItems.addAll(placement.finalPlacedItems); 405e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal outLoss[0] = placement.lowestWeightLoss; 406e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal outLoss[1] = placement.lowestMoveCost; 407e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return finalItems; 408e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 409e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 410e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private class OptimalPlacementSolution { 411e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private final ArrayList<DbEntry> itemsToPlace; 412ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal private final GridOccupancy occupied; 413e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 414e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // If set to true, item movement are not considered in move cost, leading to a more 415e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // linear placement. 416e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private final boolean ignoreMove; 417e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 418da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal // The first row in the grid from where the placement should start. 419da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal private final int startY; 420da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal 421e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float lowestWeightLoss = Float.MAX_VALUE; 422e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float lowestMoveCost = Float.MAX_VALUE; 423e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> finalPlacedItems; 424e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 425da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal public OptimalPlacementSolution( 426da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace, int startY) { 427da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal this(occupied, itemsToPlace, startY, false); 428e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 429e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 430ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal public OptimalPlacementSolution(GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace, 431da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal int startY, boolean ignoreMove) { 432e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal this.occupied = occupied; 433e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal this.itemsToPlace = itemsToPlace; 434e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal this.ignoreMove = ignoreMove; 435da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal this.startY = startY; 436e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 437e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Sort the items such that larger widgets appear first followed by 1x1 items 438e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal Collections.sort(this.itemsToPlace); 439e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 440e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 441e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public void find() { 442e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(0, 0, 0, new ArrayList<DbEntry>()); 443e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 444e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 445e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 446e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Recursively finds a placement for the provided items. 447e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @param index the position in {@link #itemsToPlace} to start looking at. 448e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @param weightLoss total weight loss upto this point 449e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @param moveCost total move cost upto this point 450e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @param itemsPlaced all the items already placed upto this point 451e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 452e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public void find(int index, float weightLoss, float moveCost, 453e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> itemsPlaced) { 454e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if ((weightLoss >= lowestWeightLoss) || 455e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ((weightLoss == lowestWeightLoss) && (moveCost >= lowestMoveCost))) { 456e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Abort, as we already have a better solution. 457e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return; 458e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 459e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else if (index >= itemsToPlace.size()) { 460e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // End loop. 461e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal lowestWeightLoss = weightLoss; 462e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal lowestMoveCost = moveCost; 463e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 464e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Keep a deep copy of current configuration as it can change during recursion. 465e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal finalPlacedItems = deepCopy(itemsPlaced); 466e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return; 467e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 468e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 469e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal DbEntry me = itemsToPlace.get(index); 470e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int myX = me.cellX; 471e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int myY = me.cellY; 472e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 473e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // List of items to pass over if this item was placed. 474e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> itemsIncludingMe = new ArrayList<>(itemsPlaced.size() + 1); 475e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal itemsIncludingMe.addAll(itemsPlaced); 476e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal itemsIncludingMe.add(me); 477e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 478e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (me.spanX > 1 || me.spanY > 1) { 479e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // If the current item is a widget (and it greater than 1x1), try to place it at 480e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // all possible positions. This is because a widget placed at one position can 481e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // affect the placement of a different widget. 482e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int myW = me.spanX; 483e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int myH = me.spanY; 484e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 485da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal for (int y = startY; y < mTrgY; y++) { 486e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (int x = 0; x < mTrgX; x++) { 487e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float newMoveCost = moveCost; 488e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (x != myX) { 489e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellX = x; 490e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newMoveCost ++; 491e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 492e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (y != myY) { 493e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellY = y; 494e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newMoveCost ++; 495e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 496e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (ignoreMove) { 497e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newMoveCost = moveCost; 498e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 499e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 500ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal if (occupied.isRegionVacant(x, y, myW, myH)) { 501e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // place at this position and continue search. 502ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, true); 503e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss, newMoveCost, itemsIncludingMe); 504ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, false); 505e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 506e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 507e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Try resizing horizontally 508ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal if (myW > me.minSpanX && occupied.isRegionVacant(x, y, myW - 1, myH)) { 509e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanX --; 510ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, true); 511e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // 1 extra move cost 512e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe); 513ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, false); 514e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanX ++; 515e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 516e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 517e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Try resizing vertically 518ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal if (myH > me.minSpanY && occupied.isRegionVacant(x, y, myW, myH - 1)) { 519e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanY --; 520ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, true); 521e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // 1 extra move cost 522e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe); 523ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, false); 524e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanY ++; 525e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 526e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 527e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Try resizing horizontally & vertically 528e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (myH > me.minSpanY && myW > me.minSpanX && 529ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.isRegionVacant(x, y, myW - 1, myH - 1)) { 530e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanX --; 531e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanY --; 532ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, true); 533e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // 2 extra move cost 534e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss, newMoveCost + 2, itemsIncludingMe); 535ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, false); 536e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanX ++; 537e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.spanY ++; 538e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 539e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellX = myX; 540e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellY = myY; 541e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 542e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 543e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 544e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Finally also try a solution when this item is not included. Trying it in the end 545e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // causes it to get skipped in most cases due to higher weight loss, and prevents 546e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // unnecessary deep copies of various configurations. 547e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss + me.weight, moveCost, itemsPlaced); 548e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else { 549e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Since this is a 1x1 item and all the following items are also 1x1, just place 550e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // it at 'the most appropriate position' and hope for the best. 551e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // The most appropriate position: one with lease straight line distance 552e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int newDistance = Integer.MAX_VALUE; 553e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int newX = Integer.MAX_VALUE, newY = Integer.MAX_VALUE; 554e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 555da4fe1a6244457f144e0a331cada3ada17157809Sunny Goyal for (int y = startY; y < mTrgY; y++) { 556e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (int x = 0; x < mTrgX; x++) { 557ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal if (!occupied.cells[x][y]) { 558e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int dist = ignoreMove ? 0 : 559e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY - y)); 560e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (dist < newDistance) { 561e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newX = x; 562e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newY = y; 563e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newDistance = dist; 564e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 565e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 566e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 567e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 568e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 569e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (newX < mTrgX && newY < mTrgY) { 570e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal float newMoveCost = moveCost; 571e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (newX != myX) { 572e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellX = newX; 573e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newMoveCost ++; 574e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 575e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (newY != myY) { 576e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellY = newY; 577e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newMoveCost ++; 578e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 579e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (ignoreMove) { 580e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal newMoveCost = moveCost; 581e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 582ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, true); 583e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss, newMoveCost, itemsIncludingMe); 584ff4ba2d99593ed84963b3f71c555b529dd905835Sunny Goyal occupied.markCells(me, false); 585e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellX = myX; 586e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal me.cellY = myY; 587e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 588e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Try to find a solution without this item, only if 589e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // 1) there was at least one space, i.e., we were able to place this item 590e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // 2) if the next item has the same weight (all items are already sorted), as 591e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // if it has lower weight, that solution will automatically get discarded. 592e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // 3) ignoreMove false otherwise, move cost is ignored and the weight will 593e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // anyway be same. 594e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (index + 1 < itemsToPlace.size() 595e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal && itemsToPlace.get(index + 1).weight >= me.weight && !ignoreMove) { 596e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(index + 1, weightLoss + me.weight, moveCost, itemsPlaced); 597e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 598e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else { 599e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // No more space. Jump to the end. 600e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (int i = index + 1; i < itemsToPlace.size(); i++) { 601e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal weightLoss += itemsToPlace.get(i).weight; 602e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 603e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal find(itemsToPlace.size(), weightLoss + me.weight, moveCost, itemsPlaced); 604e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 605e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 606e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 607e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 608e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 609f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal private ArrayList<DbEntry> loadHotseatEntries() { 610f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, 611f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal new String[]{ 612f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Favorites._ID, // 0 613f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Favorites.ITEM_TYPE, // 1 614f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Favorites.INTENT, // 2 615f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Favorites.SCREEN}, // 3 616f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Favorites.CONTAINER + " = " + Favorites.CONTAINER_HOTSEAT, null, null, null); 617f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 618f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal final int indexId = c.getColumnIndexOrThrow(Favorites._ID); 619f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal final int indexItemType = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE); 620f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT); 621f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal final int indexScreen = c.getColumnIndexOrThrow(Favorites.SCREEN); 622f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 623f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal ArrayList<DbEntry> entries = new ArrayList<>(); 624f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal while (c.moveToNext()) { 625f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal DbEntry entry = new DbEntry(); 626f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.id = c.getLong(indexId); 627f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.itemType = c.getInt(indexItemType); 628f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.screenId = c.getLong(indexScreen); 629f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 630f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (entry.screenId >= mSrcHotseatSize) { 631f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal mEntryToRemove.add(entry.id); 632f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal continue; 633f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 634f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 635f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal try { 636f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal // calculate weight 637f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal switch (entry.itemType) { 638f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal case Favorites.ITEM_TYPE_SHORTCUT: 639bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham case Favorites.ITEM_TYPE_DEEP_SHORTCUT: 640f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal case Favorites.ITEM_TYPE_APPLICATION: { 641f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal verifyIntent(c.getString(indexIntent)); 642bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham entry.weight = entry.itemType == Favorites.ITEM_TYPE_APPLICATION ? 643bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham WT_APPLICATION : WT_SHORTCUT; 644f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal break; 645f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 646f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal case Favorites.ITEM_TYPE_FOLDER: { 647f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal int total = getFolderItemsCount(entry.id); 648f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (total == 0) { 649f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal throw new Exception("Folder is empty"); 650f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 651f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entry.weight = WT_FOLDER_FACTOR * total; 652f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal break; 653f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 654f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal default: 655f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal throw new Exception("Invalid item type"); 656f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 657f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } catch (Exception e) { 658f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal if (DEBUG) { 659f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal Log.d(TAG, "Removing item " + entry.id, e); 660f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 661f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal mEntryToRemove.add(entry.id); 662f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal continue; 663f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 664f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal entries.add(entry); 665f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 666f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal c.close(); 667f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal return entries; 668f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal } 669f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 670f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 671e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 672e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Loads entries for a particular screen id. 673e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 674a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected ArrayList<DbEntry> loadWorkspaceEntries(long screen) { 675a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal Cursor c = queryWorkspace( 676f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal new String[]{ 677f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites._ID, // 0 678f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites.ITEM_TYPE, // 1 679f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites.CELLX, // 2 680f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites.CELLY, // 3 681f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites.SPANX, // 4 682f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites.SPANY, // 5 683f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Favorites.INTENT, // 6 6842e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal Favorites.APPWIDGET_PROVIDER, // 7 6852e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal Favorites.APPWIDGET_ID}, // 8 686e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP 687a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal + " AND " + Favorites.SCREEN + " = " + screen); 688f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 689f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexId = c.getColumnIndexOrThrow(Favorites._ID); 690f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexItemType = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE); 691f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexCellX = c.getColumnIndexOrThrow(Favorites.CELLX); 692f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexCellY = c.getColumnIndexOrThrow(Favorites.CELLY); 693f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexSpanX = c.getColumnIndexOrThrow(Favorites.SPANX); 694f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexSpanY = c.getColumnIndexOrThrow(Favorites.SPANY); 695f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT); 696f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final int indexAppWidgetProvider = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER); 6972e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal final int indexAppWidgetId = c.getColumnIndexOrThrow(Favorites.APPWIDGET_ID); 698f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 699f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal ArrayList<DbEntry> entries = new ArrayList<>(); 700f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal while (c.moveToNext()) { 701f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal DbEntry entry = new DbEntry(); 702f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.id = c.getLong(indexId); 703f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.itemType = c.getInt(indexItemType); 704f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.cellX = c.getInt(indexCellX); 705f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.cellY = c.getInt(indexCellY); 706f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.spanX = c.getInt(indexSpanX); 707f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.spanY = c.getInt(indexSpanY); 708f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.screenId = screen; 709f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 710f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal try { 711f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // calculate weight 712f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal switch (entry.itemType) { 713f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal case Favorites.ITEM_TYPE_SHORTCUT: 714bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham case Favorites.ITEM_TYPE_DEEP_SHORTCUT: 715f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal case Favorites.ITEM_TYPE_APPLICATION: { 716f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal verifyIntent(c.getString(indexIntent)); 717bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham entry.weight = entry.itemType == Favorites.ITEM_TYPE_APPLICATION ? 718bfbf7f9f4a0b300613f0ff27a4eb592d88c08325Tony Wickham WT_APPLICATION : WT_SHORTCUT; 719f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal break; 720f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 721f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal case Favorites.ITEM_TYPE_APPWIDGET: { 722f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal String provider = c.getString(indexAppWidgetProvider); 723f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal ComponentName cn = ComponentName.unflattenFromString(provider); 724f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal verifyPackage(cn.getPackageName()); 725f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.weight = Math.max(WT_WIDGET_MIN, WT_WIDGET_FACTOR 726f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * entry.spanX * entry.spanY); 727f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 7282e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal int widgetId = c.getInt(indexAppWidgetId); 7292e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal LauncherAppWidgetProviderInfo pInfo = AppWidgetManagerCompat.getInstance( 7302e1efb480a9b77a97cb623d4f5faf6802a417422Sunny Goyal mContext).getLauncherAppWidgetInfo(widgetId); 731f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Point spans = pInfo == null ? 732f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mWidgetMinSize.get(provider) : pInfo.getMinSpans(mIdp, mContext); 733f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (spans != null) { 734f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX; 735f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.minSpanY = spans.y > 0 ? spans.y : entry.spanY; 736f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } else { 737f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Assume that the widget be resized down to 2x2 738f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.minSpanX = entry.minSpanY = 2; 739f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 740f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 741f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) { 742f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal throw new Exception("Widget can't be resized down to fit the grid"); 743f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 744f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal break; 745f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 746f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal case Favorites.ITEM_TYPE_FOLDER: { 747f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal int total = getFolderItemsCount(entry.id); 748f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (total == 0) { 749f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal throw new Exception("Folder is empty"); 750f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 751f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entry.weight = WT_FOLDER_FACTOR * total; 752f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal break; 753f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 754f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal default: 755f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal throw new Exception("Invalid item type"); 756f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 757f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } catch (Exception e) { 758f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (DEBUG) { 759f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Log.d(TAG, "Removing item " + entry.id, e); 760f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 761f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal mEntryToRemove.add(entry.id); 762f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal continue; 763f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 764f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal entries.add(entry); 765f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 766f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal c.close(); 767f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return entries; 768e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 769e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 770e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 771e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * @return the number of valid items in the folder. 772e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 773e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private int getFolderItemsCount(long folderId) { 774a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal Cursor c = queryWorkspace( 775f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal new String[]{Favorites._ID, Favorites.INTENT}, 776a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal Favorites.CONTAINER + " = " + folderId); 777e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 778e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal int total = 0; 779e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal while (c.moveToNext()) { 780e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal try { 781e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal verifyIntent(c.getString(1)); 782e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal total++; 783e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } catch (Exception e) { 784e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal mEntryToRemove.add(c.getLong(0)); 785e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 786e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 787fb062c63355f65e6df9e99cbf4cce49cee2900d1Tony Wickham c.close(); 788e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return total; 789e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 790e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 791a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected Cursor queryWorkspace(String[] columns, String where) { 792a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal return mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, 793a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal columns, where, null, null, null); 794a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal } 795a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal 796e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 797e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Verifies if the intent should be restored. 798e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 799e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private void verifyIntent(String intentStr) throws Exception { 800e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal Intent intent = Intent.parseUri(intentStr, 0); 801e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (intent.getComponent() != null) { 802e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal verifyPackage(intent.getComponent().getPackageName()); 803e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else if (intent.getPackage() != null) { 804e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Only verify package if the component was null. 805e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal verifyPackage(intent.getPackage()); 806e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 807e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 808e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 809e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 810e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Verifies if the package should be restored 811e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 812e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private void verifyPackage(String packageName) throws Exception { 813e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (!mValidPackages.contains(packageName)) { 814e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal throw new Exception("Package not available"); 815e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 816e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 817e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 818a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected static class DbEntry extends ItemInfo implements Comparable<DbEntry> { 819e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 820e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public float weight; 821e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 822e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public DbEntry() { } 823e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 824e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public DbEntry copy() { 825e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal DbEntry entry = new DbEntry(); 826e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal entry.copyFrom(this); 827e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal entry.weight = weight; 828e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal entry.minSpanX = minSpanX; 829e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal entry.minSpanY = minSpanY; 830e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return entry; 831e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 832e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 833e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal /** 834e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * Comparator such that larger widgets come first, followed by all 1x1 items 835e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal * based on their weights. 836e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal */ 837e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal @Override 838e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public int compareTo(DbEntry another) { 839e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (itemType == Favorites.ITEM_TYPE_APPWIDGET) { 840e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal if (another.itemType == Favorites.ITEM_TYPE_APPWIDGET) { 841e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return another.spanY * another.spanX - spanX * spanY; 842e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else { 843e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return -1; 844e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 845e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else if (another.itemType == Favorites.ITEM_TYPE_APPWIDGET) { 846e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return 1; 847e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } else { 848e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal // Place higher weight before lower weight. 849e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return Float.compare(another.weight, weight); 850e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 851e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 852e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 853e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public boolean columnsSame(DbEntry org) { 854e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return org.cellX == cellX && org.cellY == cellY && org.spanX == spanX && 855e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal org.spanY == spanY && org.screenId == screenId; 856e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 857e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 858e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal public void addToContentValues(ContentValues values) { 859e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal values.put(LauncherSettings.Favorites.SCREEN, screenId); 860e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal values.put(LauncherSettings.Favorites.CELLX, cellX); 861e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal values.put(LauncherSettings.Favorites.CELLY, cellY); 862e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal values.put(LauncherSettings.Favorites.SPANX, spanX); 863e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal values.put(LauncherSettings.Favorites.SPANY, spanY); 864e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 865e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 866e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 867f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal private static ArrayList<DbEntry> deepCopy(ArrayList<DbEntry> src) { 868e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal ArrayList<DbEntry> dup = new ArrayList<DbEntry>(src.size()); 869e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal for (DbEntry e : src) { 870e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal dup.add(e.copy()); 871e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 872e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return dup; 873e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 874e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 875e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal private static Point parsePoint(String point) { 876e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal String[] split = point.split(","); 877e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1])); 878e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal } 879e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 880f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal private static String getPointString(int x, int y) { 881f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return String.format(Locale.ENGLISH, "%d,%d", x, y); 882f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 883f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 884a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal public static void markForMigration( 885a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal Context context, int gridX, int gridY, int hotseatSize) { 886a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal Utilities.getPrefs(context).edit() 887a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, getPointString(gridX, gridY)) 888a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, hotseatSize) 889a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal .apply(); 890a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 891a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal 892f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal /** 893f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * Migrates the workspace and hotseat in case their sizes changed. 894f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal * @return false if the migration failed. 895f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal */ 896f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal public static boolean migrateGridIfNeeded(Context context) { 897f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal SharedPreferences prefs = Utilities.getPrefs(context); 898f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile(); 899f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 900f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal String gridSizeString = getPointString(idp.numColumns, idp.numRows); 901e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 902f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) && 903bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal idp.numHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)) { 904f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Skip if workspace and hotseat sizes have not changed. 905f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return true; 906f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 907f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 908f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal long migrationStartTime = System.currentTimeMillis(); 909f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal try { 910f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal boolean dbChanged = false; 911f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 912a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal HashSet validPackages = getValidPackages(context); 913f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Hotseat 914bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons); 915bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal if (srcHotseatCount != idp.numHotseatIcons) { 916f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Migrate hotseat. 917f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 918f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal dbChanged = new GridSizeMigrationTask(context, 919f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal LauncherAppState.getInstance().getInvariantDeviceProfile(), 920bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal validPackages, srcHotseatCount, idp.numHotseatIcons).migrateHotseat(); 921f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 922f862a26347b583bd84be22a8ceff4bc13158ec7eSunny Goyal 923f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Grid size 924f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Point targetSize = new Point(idp.numColumns, idp.numRows); 925f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Point sourceSize = parsePoint(prefs.getString( 926f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)); 927f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 928a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (new MultiStepMigrationTask(validPackages, context).migrate(sourceSize, targetSize)) { 929a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal dbChanged = true; 930f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 931e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal 932f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (dbChanged) { 933f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Make sure we haven't removed everything. 934f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal final Cursor c = context.getContentResolver().query( 935f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); 936f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal boolean hasData = c.moveToNext(); 937f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal c.close(); 938f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal if (!hasData) { 939f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal throw new Exception("Removed every thing during grid resize"); 940f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 941f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 942f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 943f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return true; 944f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } catch (Exception e) { 945f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Log.e(TAG, "Error during grid migration", e); 946f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 947f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal return false; 948f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } finally { 949f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal Log.v(TAG, "Workspace migration completed in " 950f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal + (System.currentTimeMillis() - migrationStartTime)); 951f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal 952f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal // Save current configuration, so that the migration does not run again. 953f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal prefs.edit() 954f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString) 955bb011dad4e69bec027be1e00d573a3095b318b43Sunny Goyal .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons) 956f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal .apply(); 957f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 958f076eae0cab10f035f7b187c72a680cd220acf1bSunny Goyal } 959a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal 960a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal protected static HashSet<String> getValidPackages(Context context) { 961a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal // Initialize list of valid packages. This contain all the packages which are already on 962a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal // the device and packages which are being installed. Any item which doesn't belong to 963a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal // this set is removed. 964a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal // Since the loader removes such items anyway, removing these items here doesn't cause 965a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal // any extra data loss and gives us more free space on the grid for better migration. 966a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal HashSet validPackages = new HashSet<>(); 967a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal for (PackageInfo info : context.getPackageManager() 968a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) { 969a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal validPackages.add(info.packageName); 970a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal } 971a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal validPackages.addAll(PackageInstallerCompat.getInstance(context) 972a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal .updateAndGetActiveSessionCache().keySet()); 973a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal return validPackages; 974a9e2f5abb3c21d9721939c625ffb0caabb34e8d9Sunny Goyal } 975a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal 976a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal /** 977d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal * Removes any broken item from the hotseat. 978d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal * @return a map with occupied hotseat position set to non-null value. 979d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal */ 980d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal public static LongArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception { 981d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal GridSizeMigrationTask task = new GridSizeMigrationTask(context, 982d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal LauncherAppState.getInstance().getInvariantDeviceProfile(), 983d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal getValidPackages(context), Integer.MAX_VALUE, Integer.MAX_VALUE); 984d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal 985d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal // Load all the valid entries 986d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal ArrayList<DbEntry> items = task.loadHotseatEntries(); 987d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal // Delete any entry marked for deletion by above load. 988d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal task.applyOperations(); 989d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal LongArrayMap<Object> positions = new LongArrayMap<>(); 990d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal for (DbEntry item : items) { 991d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal positions.put(item.screenId, item); 992d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal } 993d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal return positions; 994d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal } 995d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal 996d70ef242332e766b2c23e3b8bb537dc2d584e9ecSunny Goyal /** 997a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal * Task to run grid migration in multiple steps when the size difference is more than 1. 998a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal */ 999a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal protected static class MultiStepMigrationTask { 1000a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal private final HashSet<String> mValidPackages; 1001a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal private final Context mContext; 1002a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal 1003a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal public MultiStepMigrationTask(HashSet<String> validPackages, Context context) { 1004a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal mValidPackages = validPackages; 1005a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal mContext = context; 1006a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1007a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal 1008a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal public boolean migrate(Point sourceSize, Point targetSize) throws Exception { 1009a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal boolean dbChanged = false; 1010a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (!targetSize.equals(sourceSize)) { 1011a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (sourceSize.x < targetSize.x) { 1012a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // Source is smaller that target, just expand the grid without actual migration. 1013a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal sourceSize.x = targetSize.x; 1014a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1015a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (sourceSize.y < targetSize.y) { 1016a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // Source is smaller that target, just expand the grid without actual migration. 1017a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal sourceSize.y = targetSize.y; 1018a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1019a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal 1020a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // Migrate the workspace grid, such that the points differ by max 1 in x and y 1021a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // each on every step. 1022a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal while (!targetSize.equals(sourceSize)) { 1023a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal // Get the next size, such that the points differ by max 1 in x and y each 1024a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal Point nextSize = new Point(sourceSize); 1025a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (targetSize.x < nextSize.x) { 1026a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal nextSize.x--; 1027a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1028a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (targetSize.y < nextSize.y) { 1029a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal nextSize.y--; 1030a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1031a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal if (runStepTask(sourceSize, nextSize)) { 1032a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal dbChanged = true; 1033a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1034a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal sourceSize.set(nextSize.x, nextSize.y); 1035a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1036a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1037a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal return dbChanged; 1038a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1039a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal 1040a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception { 1041a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal return new GridSizeMigrationTask(mContext, 1042a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal LauncherAppState.getInstance().getInvariantDeviceProfile(), 1043a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal mValidPackages, sourceSize, nextSize).migrateWorkspace(); 1044a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1045a5c8a9eb666da16bc4c9ea4412868e22ace8d1f0Sunny Goyal } 1046e5bb705fb79f18df8680958dcf2c5460e16c90b6Sunny Goyal} 1047