From dcd297f05a866e07090d6e2af8fb4b15f28cb555 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Tue, 18 Jun 2013 13:13:40 -0700 Subject: Initial implementation of Shrink-wrap Change-Id: If73c7f7ca19ca62ff43134f515584354afef8507 --- src/com/android/launcher3/CellLayout.java | 7 +- src/com/android/launcher3/Folder.java | 6 +- src/com/android/launcher3/Hotseat.java | 4 +- .../android/launcher3/InstallShortcutReceiver.java | 3 +- src/com/android/launcher3/ItemInfo.java | 8 +- src/com/android/launcher3/Launcher.java | 127 +++++---- src/com/android/launcher3/LauncherModel.java | 283 +++++++++++++++------ src/com/android/launcher3/LauncherProvider.java | 124 +++++++-- src/com/android/launcher3/LauncherSettings.java | 20 ++ src/com/android/launcher3/PagedView.java | 4 +- src/com/android/launcher3/ShortcutInfo.java | 2 +- src/com/android/launcher3/Workspace.java | 276 ++++++++++++++------ 12 files changed, 609 insertions(+), 255 deletions(-) (limited to 'src/com/android/launcher3') diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index e115e43f5..35598a2f2 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -709,7 +709,10 @@ public class CellLayout extends ViewGroup { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this); + if (getParent() instanceof Workspace) { + Workspace workspace = (Workspace) getParent(); + mCellInfo.screenId = workspace.getIdForScreen(this); + } } public void setTagToCellInfoForPoint(int touchX, int touchY) { @@ -3334,7 +3337,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { int cellY = -1; int spanX; int spanY; - int screen; + long screenId; long container; @Override diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 7b15e9edf..9eafc2231 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -1066,7 +1066,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList Runnable onCompleteRunnable = new Runnable() { @Override public void run() { - CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen); + CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screenId); View child = null; // Move the item from the folder to the workspace, in the position of the folder @@ -1075,7 +1075,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList child = mLauncher.createShortcut(R.layout.application, cellLayout, finalItem); LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container, - mInfo.screen, mInfo.cellX, mInfo.cellY); + mInfo.screenId, mInfo.cellX, mInfo.cellY); } if (getItemCount() <= 1) { // Remove the folder @@ -1089,7 +1089,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList // We add the child after removing the folder to prevent both from existing at // the same time in the CellLayout. if (child != null) { - mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen, + mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screenId, mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY); } } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 50f7efd20..93f39ff3b 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -122,10 +122,10 @@ public class Hotseat extends FrameLayout { fi.spanX = 1; fi.spanY = 1; fi.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT; - fi.screen = mAllAppsButtonRank; + fi.screenId = mAllAppsButtonRank; fi.itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER; fi.title = "All Apps"; - LauncherModel.addItemToDatabase(launcher, fi, fi.container, fi.screen, fi.cellX, + LauncherModel.addItemToDatabase(launcher, fi, fi.container, fi.screenId, fi.cellX, fi.cellY, false); FolderIcon folder = FolderIcon.fromXml(R.layout.folder_icon, launcher, getLayout(), fi, iconCache); diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 07d68da35..d647d96a4 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -333,6 +333,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return false; } + // TODO: this needs to be updated to take a screenId instead of a screen index private static boolean findEmptyCell(Context context, ArrayList items, int[] xy, int screen) { final int xCount = LauncherModel.getCellCountX(); @@ -344,7 +345,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { for (int i = 0; i < items.size(); ++i) { item = items.get(i); if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { - if (item.screen == screen) { + if (item.screenId == screen) { cellX = item.cellX; cellY = item.cellY; spanX = item.spanX; diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java index fb4183423..1d7ebba95 100644 --- a/src/com/android/launcher3/ItemInfo.java +++ b/src/com/android/launcher3/ItemInfo.java @@ -55,7 +55,7 @@ class ItemInfo { /** * Iindicates the screen in which the shortcut appears. */ - int screen = -1; + long screenId = -1; /** * Indicates the X position of the associated cell. @@ -111,7 +111,7 @@ class ItemInfo { cellY = info.cellY; spanX = info.spanX; spanY = info.spanY; - screen = info.screen; + screenId = info.screenId; itemType = info.itemType; container = info.container; // tempdebug: @@ -141,7 +141,7 @@ class ItemInfo { void onAddToDatabase(ContentValues values) { values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType); values.put(LauncherSettings.Favorites.CONTAINER, container); - values.put(LauncherSettings.Favorites.SCREEN, screen); + values.put(LauncherSettings.Favorites.SCREEN, screenId); values.put(LauncherSettings.Favorites.CELLX, cellX); values.put(LauncherSettings.Favorites.CELLY, cellY); values.put(LauncherSettings.Favorites.SPANX, spanX); @@ -188,7 +188,7 @@ class ItemInfo { @Override public String toString() { return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container - + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + dropPos + ")"; } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 0253103ea..305f249d9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -295,7 +295,7 @@ public class Launcher extends Activity // Holds the page that we need to animate to, and the icon views that we need to animate up // when we scroll to that page on resume. - private int mNewShortcutAnimatePage = -1; + private long mNewShortcutAnimateScreenId = -1; private ArrayList mNewShortcutAnimateViews = new ArrayList(); private ImageView mFolderIconImageView; private Bitmap mFolderIconBitmap; @@ -324,7 +324,7 @@ public class Launcher extends Activity int requestCode; Intent intent; long container; - int screen; + long screenId; int cellX; int cellY; } @@ -592,20 +592,20 @@ public class Launcher extends Activity boolean result = false; switch (args.requestCode) { case REQUEST_PICK_APPLICATION: - completeAddApplication(args.intent, args.container, args.screen, args.cellX, + completeAddApplication(args.intent, args.container, args.screenId, args.cellX, args.cellY); break; case REQUEST_PICK_SHORTCUT: processShortcut(args.intent); break; case REQUEST_CREATE_SHORTCUT: - completeAddShortcut(args.intent, args.container, args.screen, args.cellX, + completeAddShortcut(args.intent, args.container, args.screenId, args.cellX, args.cellY); result = true; break; case REQUEST_CREATE_APPWIDGET: int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - completeAddAppWidget(appWidgetId, args.container, args.screen, null, null); + completeAddAppWidget(appWidgetId, args.container, args.screenId, null, null); result = true; break; case REQUEST_PICK_WALLPAPER: @@ -661,7 +661,7 @@ public class Launcher extends Activity args.requestCode = requestCode; args.intent = data; args.container = mPendingAddInfo.container; - args.screen = mPendingAddInfo.screen; + args.screenId = mPendingAddInfo.screenId; args.cellX = mPendingAddInfo.cellX; args.cellY = mPendingAddInfo.cellY; if (isWorkspaceLocked()) { @@ -678,7 +678,7 @@ public class Launcher extends Activity private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) { CellLayout cellLayout = - (CellLayout) mWorkspace.getChildAt(mPendingAddInfo.screen); + (CellLayout) mWorkspace.getScreenWithId(mPendingAddInfo.screenId); Runnable onCompleteRunnable = null; int animationType = 0; @@ -692,7 +692,7 @@ public class Launcher extends Activity @Override public void run() { completeAddAppWidget(appWidgetId, mPendingAddInfo.container, - mPendingAddInfo.screen, layout, null); + mPendingAddInfo.screenId, layout, null); exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), false, null); } @@ -826,22 +826,7 @@ public class Launcher extends Activity // Add a fullscreen unpadded view to the workspace to the left all other screens. public void addCustomContentToLeft(View customContent) { - CellLayout customScreen = (CellLayout) - getLayoutInflater().inflate(R.layout.workspace_custom_content, null); - - int spanX = customScreen.getCountX(); - int spanY = customScreen.getCountY(); - - CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY); - lp.canReorder = false; - - customScreen.addViewToCellLayout(customContent, 0, 0, lp, true); - - mWorkspace.addView(customScreen, 0); - - // Ensure that the current page and default page are maintained. - mWorkspace.incrementNumScreensToLeft(); - mWorkspace.setCurrentPage(mWorkspace.getCurrentPage() + 1); + mWorkspace.addCustomContentToLeft(customContent); } @Override @@ -955,11 +940,11 @@ public class Launcher extends Activity } final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1); - final int pendingAddScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1); + final long pendingAddScreen = savedState.getLong(RUNTIME_STATE_PENDING_ADD_SCREEN, -1); if (pendingAddContainer != ItemInfo.NO_ID && pendingAddScreen > -1) { mPendingAddInfo.container = pendingAddContainer; - mPendingAddInfo.screen = pendingAddScreen; + mPendingAddInfo.screenId = pendingAddScreen; mPendingAddInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X); mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y); mPendingAddInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X); @@ -969,7 +954,6 @@ public class Launcher extends Activity mRestoring = true; } - boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false); if (renameFolder) { long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID); @@ -977,7 +961,6 @@ public class Launcher extends Activity mRestoring = true; } - // Restore the AppsCustomize tab if (mAppsCustomizeTabHost != null) { String curTab = savedState.getString("apps_customize_currentTab"); @@ -1086,9 +1069,9 @@ public class Launcher extends Activity * @param data The intent describing the application. * @param cellInfo The position on screen where to create the shortcut. */ - void completeAddApplication(Intent data, long container, int screen, int cellX, int cellY) { + void completeAddApplication(Intent data, long container, long screenId, int cellX, int cellY) { final int[] cellXY = mTmpAddItemCellCoordinates; - final CellLayout layout = getCellLayout(container, screen); + final CellLayout layout = getCellLayout(container, screenId); // First we check if we already know the exact location where we want to add this item. if (cellX >= 0 && cellY >= 0) { @@ -1105,7 +1088,7 @@ public class Launcher extends Activity info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); info.container = ItemInfo.NO_ID; - mWorkspace.addApplicationShortcut(info, layout, container, screen, cellXY[0], cellXY[1], + mWorkspace.addApplicationShortcut(info, layout, container, screenId, cellXY[0], cellXY[1], isWorkspaceLocked(), cellX, cellY); } else { Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data); @@ -1118,11 +1101,11 @@ public class Launcher extends Activity * @param data The intent describing the shortcut. * @param cellInfo The position on screen where to create the shortcut. */ - private void completeAddShortcut(Intent data, long container, int screen, int cellX, + private void completeAddShortcut(Intent data, long container, long screenId, int cellX, int cellY) { int[] cellXY = mTmpAddItemCellCoordinates; int[] touchXY = mPendingAddInfo.dropPos; - CellLayout layout = getCellLayout(container, screen); + CellLayout layout = getCellLayout(container, screenId); boolean foundCellSpan = false; @@ -1162,11 +1145,10 @@ public class Launcher extends Activity return; } - int adjustedScreen = screen - getWorkspace().mNumPagesToLeft; - LauncherModel.addItemToDatabase(this, info, container, adjustedScreen, cellXY[0], cellXY[1], false); + LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1], false); if (!mRestoring) { - mWorkspace.addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, + mWorkspace.addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked()); } } @@ -1204,14 +1186,14 @@ public class Launcher extends Activity * @param appWidgetId The app widget id * @param cellInfo The position on screen where to create the widget. */ - private void completeAddAppWidget(final int appWidgetId, long container, int screen, + private void completeAddAppWidget(final int appWidgetId, long container, long screenId, AppWidgetHostView hostView, AppWidgetProviderInfo appWidgetInfo) { if (appWidgetInfo == null) { appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); } // Calculate the grid spans needed to fit this widget - CellLayout layout = getCellLayout(container, screen); + CellLayout layout = getCellLayout(container, screenId); int[] minSpanXY = getMinSpanForWidget(this, appWidgetInfo); int[] spanXY = getSpanForWidget(this, appWidgetInfo); @@ -1263,9 +1245,8 @@ public class Launcher extends Activity launcherInfo.minSpanX = mPendingAddInfo.minSpanX; launcherInfo.minSpanY = mPendingAddInfo.minSpanY; - int adjustedScreen = screen - getWorkspace().mNumPagesToLeft; LauncherModel.addItemToDatabase(this, launcherInfo, - container, adjustedScreen, cellXY[0], cellXY[1], false); + container, screenId, cellXY[0], cellXY[1], false); if (!mRestoring) { if (hostView == null) { @@ -1281,7 +1262,7 @@ public class Launcher extends Activity launcherInfo.hostView.setVisibility(View.VISIBLE); launcherInfo.notifyWidgetSizeChanged(this); - mWorkspace.addInScreen(launcherInfo.hostView, container, screen, cellXY[0], cellXY[1], + mWorkspace.addInScreen(launcherInfo.hostView, container, screenId, cellXY[0], cellXY[1], launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked()); addWidgetToAutoAdvanceIfNeeded(launcherInfo.hostView, appWidgetInfo); @@ -1560,10 +1541,10 @@ public class Launcher extends Activity // this state is reflected. closeFolder(); - if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screen > -1 && + if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screenId > -1 && mWaitingForResult) { outState.putLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, mPendingAddInfo.container); - outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, mPendingAddInfo.screen); + outState.putLong(RUNTIME_STATE_PENDING_ADD_SCREEN, mPendingAddInfo.screenId); outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, mPendingAddInfo.cellX); outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, mPendingAddInfo.cellY); outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_X, mPendingAddInfo.spanX); @@ -1789,7 +1770,7 @@ public class Launcher extends Activity private void resetAddInfo() { mPendingAddInfo.container = ItemInfo.NO_ID; - mPendingAddInfo.screen = -1; + mPendingAddInfo.screenId = -1; mPendingAddInfo.cellX = mPendingAddInfo.cellY = -1; mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1; mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = -1; @@ -1808,7 +1789,7 @@ public class Launcher extends Activity startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET); } else { // Otherwise just add it - completeAddAppWidget(appWidgetId, info.container, info.screen, boundWidget, + completeAddAppWidget(appWidgetId, info.container, info.screenId, boundWidget, appWidgetInfo); // Exit spring loaded mode if necessary after adding the widget exitSpringLoadedDragModeDelayed(true, false, null); @@ -1819,15 +1800,15 @@ public class Launcher extends Activity * Process a shortcut drop. * * @param componentName The name of the component - * @param screen The screen where it should be added + * @param screenId The ID of the screen where it should be added * @param cell The cell it should be added to, optional * @param position The location on the screen where it was dropped, optional */ - void processShortcutFromDrop(ComponentName componentName, long container, int screen, + void processShortcutFromDrop(ComponentName componentName, long container, long screenId, int[] cell, int[] loc) { resetAddInfo(); mPendingAddInfo.container = container; - mPendingAddInfo.screen = screen; + mPendingAddInfo.screenId = screenId; mPendingAddInfo.dropPos = loc; if (cell != null) { @@ -1844,15 +1825,15 @@ public class Launcher extends Activity * Process a widget drop. * * @param info The PendingAppWidgetInfo of the widget being added. - * @param screen The screen where it should be added + * @param screenId The ID of the screen where it should be added * @param cell The cell it should be added to, optional * @param position The location on the screen where it was dropped, optional */ - void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, int screen, + void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, long screenId, int[] cell, int[] span, int[] loc) { resetAddInfo(); mPendingAddInfo.container = info.container = container; - mPendingAddInfo.screen = info.screen = screen; + mPendingAddInfo.screenId = info.screenId = screenId; mPendingAddInfo.dropPos = loc; mPendingAddInfo.minSpanX = info.minSpanX; mPendingAddInfo.minSpanY = info.minSpanY; @@ -1921,20 +1902,20 @@ public class Launcher extends Activity startActivityForResult(intent, REQUEST_PICK_WALLPAPER); } - FolderIcon addFolder(CellLayout layout, long container, final int screen, int cellX, + FolderIcon addFolder(CellLayout layout, long container, final long screenId, int cellX, int cellY) { final FolderInfo folderInfo = new FolderInfo(); folderInfo.title = getText(R.string.folder_name); // Update the model - LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screen, cellX, cellY, + LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId, cellX, cellY, false); sFolders.put(folderInfo.id, folderInfo); // Create the view FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo, mIconCache); - mWorkspace.addInScreen(newFolder, container, screen, cellX, cellY, 1, 1, + mWorkspace.addInScreen(newFolder, container, screenId, cellX, cellY, 1, 1, isWorkspaceLocked()); return newFolder; } @@ -2231,7 +2212,7 @@ public class Launcher extends Activity // it is actually opened. There have been a few instances where this gets out of sync. if (info.opened && openFolder == null) { Log.d(TAG, "Folder info marked as open, but associated folder is not open. Screen: " - + info.screen + " (" + info.cellX + ", " + info.cellY + ")"); + + info.screenId + " (" + info.cellX + ", " + info.cellY + ")"); info.opened = false; } @@ -2469,7 +2450,7 @@ public class Launcher extends Activity /** * Returns the CellLayout of the specified container at the specified screen. */ - CellLayout getCellLayout(long container, int screen) { + CellLayout getCellLayout(long container, long screenId) { if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { if (mHotseat != null) { return mHotseat.getLayout(); @@ -2477,7 +2458,7 @@ public class Launcher extends Activity return null; } } else { - return (CellLayout) mWorkspace.getChildAt(screen); + return (CellLayout) mWorkspace.getScreenWithId(screenId); } } @@ -3440,7 +3421,7 @@ public class Launcher extends Activity mOnResumeCallbacks.clear(); final Workspace workspace = mWorkspace; - mNewShortcutAnimatePage = -1; + mNewShortcutAnimateScreenId = -1; mNewShortcutAnimateViews.clear(); mWorkspace.clearDropTargets(); int count = workspace.getChildCount(); @@ -3455,6 +3436,15 @@ public class Launcher extends Activity } } + @Override + public void bindScreens(ArrayList orderedScreenIds) { + int count = orderedScreenIds.size(); + for (int i = 0; i < count; i++) { + mWorkspace.insertNewWorkspaceScreenOnBind(orderedScreenIds.get(i)); + } + mWorkspace.addExtraEmptyScreen(); + } + /** * Bind the items start-end from the list. * @@ -3489,8 +3479,9 @@ public class Launcher extends Activity ShortcutInfo info = (ShortcutInfo) item; String uri = info.intent.toUri(0).toString(); View shortcut = createShortcut(info); - workspace.addInScreen(shortcut, item.container, item.screen, item.cellX, - item.cellY, 1, 1, false); + + workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX, + item.cellY, 1, 1); boolean animateIconUp = false; synchronized (newApps) { if (newApps.contains(uri)) { @@ -3502,7 +3493,7 @@ public class Launcher extends Activity shortcut.setAlpha(0f); shortcut.setScaleX(0f); shortcut.setScaleY(0f); - mNewShortcutAnimatePage = item.screen; + mNewShortcutAnimateScreenId = item.screenId; if (!mNewShortcutAnimateViews.contains(shortcut)) { mNewShortcutAnimateViews.add(shortcut); } @@ -3512,8 +3503,8 @@ public class Launcher extends Activity FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()), (FolderInfo) item, mIconCache); - workspace.addInScreen(newFolder, item.container, item.screen, item.cellX, - item.cellY, 1, 1, false); + workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX, + item.cellY, 1, 1); break; } } @@ -3567,7 +3558,7 @@ public class Launcher extends Activity item.hostView.setTag(item); item.onBindAppWidget(this); - workspace.addInScreen(item.hostView, item.container, item.screen, item.cellX, + workspace.addInScreen(item.hostView, item.container, item.screenId, item.cellX, item.cellY, item.spanX, item.spanY, false); addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo); @@ -3625,13 +3616,13 @@ public class Launcher extends Activity } }; - boolean willSnapPage = mNewShortcutAnimatePage > -1 && - mNewShortcutAnimatePage != mWorkspace.getCurrentPage(); + boolean willSnapPage = mNewShortcutAnimateScreenId > -1 && + mNewShortcutAnimateScreenId != mWorkspace.getCurrentPage(); if (canRunNewAppsAnimation()) { // If the user has not interacted recently, then either snap to the new page to show // the new-apps animation or just run them if they are to appear on the current page if (willSnapPage) { - mWorkspace.snapToPage(mNewShortcutAnimatePage, newAppsRunnable); + mWorkspace.snapToScreenId(mNewShortcutAnimateScreenId, newAppsRunnable); } else { runNewAppsAnimation(false); } @@ -3715,7 +3706,7 @@ public class Launcher extends Activity } // Clean up - mNewShortcutAnimatePage = -1; + mNewShortcutAnimateScreenId = -1; mNewShortcutAnimateViews.clear(); new Thread("clearNewAppsThread") { public void run() { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 2e76a6506..041882fd9 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -48,14 +48,13 @@ import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; -import com.android.launcher3.R; import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData; import java.lang.ref.WeakReference; import java.net.URISyntaxException; import java.text.Collator; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -63,6 +62,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.TreeMap; /** * Maintains in-memory state of the Launcher. It is expected that there should be only one @@ -138,6 +138,10 @@ public class LauncherModel extends BroadcastReceiver { // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database static final HashMap sBgDbIconCache = new HashMap(); + + // sBgWorkspaceScreens is the ordered set of workspace screens. + static final ArrayList sBgWorkspaceScreens = new ArrayList(); + // private IconCache mIconCache; @@ -153,6 +157,7 @@ public class LauncherModel extends BroadcastReceiver { public int getCurrentWorkspaceScreen(); public void startBinding(); public void bindItems(ArrayList shortcuts, int start, int end); + public void bindScreens(ArrayList orderedScreenIds); public void bindFolders(HashMap folders); public void finishBindingItems(boolean upgradePath); public void bindAppWidget(LauncherAppWidgetInfo info); @@ -257,13 +262,13 @@ public class LauncherModel extends BroadcastReceiver { * */ static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container, - int screen, int cellX, int cellY) { + long screenId, int cellX, int cellY) { if (item.container == ItemInfo.NO_ID) { // From all apps - addItemToDatabase(context, item, container, screen, cellX, cellY, false); + addItemToDatabase(context, item, container, screenId, cellX, cellY, false); } else { // From somewhere else - moveItemInDatabase(context, item, container, screen, cellX, cellY); + moveItemInDatabase(context, item, container, screenId, cellX, cellY); } } @@ -280,7 +285,7 @@ public class LauncherModel extends BroadcastReceiver { modelShortcut.id == shortcut.id && modelShortcut.itemType == shortcut.itemType && modelShortcut.container == shortcut.container && - modelShortcut.screen == shortcut.screen && + modelShortcut.screenId == shortcut.screenId && modelShortcut.cellX == shortcut.cellX && modelShortcut.cellY == shortcut.cellY && modelShortcut.spanX == shortcut.spanX && @@ -444,10 +449,10 @@ public class LauncherModel extends BroadcastReceiver { * Move an item in the DB to a new */ static void moveItemInDatabase(Context context, final ItemInfo item, final long container, - final int screen, final int cellX, final int cellY) { + final long screenId, final int cellX, final int cellY) { String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " + item.id + - " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY + - ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")"; + " (" + item.container + ", " + item.screenId + ", " + item.cellX + ", " + item.cellY + + ") --> " + "(" + container + ", " + screenId + ", " + cellX + ", " + cellY + ")"; Launcher.sDumpLogs.add(transaction); Log.d(TAG, transaction); item.container = container; @@ -456,18 +461,18 @@ public class LauncherModel extends BroadcastReceiver { // We store hotseat items in canonical form which is this orientation invariant position // in the hotseat - if (context instanceof Launcher && screen < 0 && + if (context instanceof Launcher && screenId < 0 && container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); + item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); } else { - item.screen = screen; + item.screenId = screenId; } final ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.CONTAINER, item.container); values.put(LauncherSettings.Favorites.CELLX, item.cellX); values.put(LauncherSettings.Favorites.CELLY, item.cellY); - values.put(LauncherSettings.Favorites.SCREEN, item.screen); + values.put(LauncherSettings.Favorites.SCREEN, item.screenId); updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase"); } @@ -485,7 +490,7 @@ public class LauncherModel extends BroadcastReceiver { for (int i = 0; i < count; i++) { ItemInfo item = items.get(i); String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " - + item.id + " (" + item.container + ", " + item.screen + ", " + item.cellX + + item.id + " (" + item.container + ", " + item.screenId + ", " + item.cellX + ", " + item.cellY + ") --> " + "(" + container + ", " + screen + ", " + item.cellX + ", " + item.cellY + ")"; Launcher.sDumpLogs.add(transaction); @@ -495,17 +500,17 @@ public class LauncherModel extends BroadcastReceiver { // in the hotseat if (context instanceof Launcher && screen < 0 && container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX, + item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX, item.cellY); } else { - item.screen = screen; + item.screenId = screen; } final ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.CONTAINER, item.container); values.put(LauncherSettings.Favorites.CELLX, item.cellX); values.put(LauncherSettings.Favorites.CELLY, item.cellY); - values.put(LauncherSettings.Favorites.SCREEN, item.screen); + values.put(LauncherSettings.Favorites.SCREEN, item.screenId); contentValues.add(values); } @@ -516,10 +521,10 @@ public class LauncherModel extends BroadcastReceiver { * Move and/or resize item in the DB to a new */ static void modifyItemInDatabase(Context context, final ItemInfo item, final long container, - final int screen, final int cellX, final int cellY, final int spanX, final int spanY) { + final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) { String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " + item.id + - " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY + - ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")"; + " (" + item.container + ", " + item.screenId + ", " + item.cellX + ", " + item.cellY + + ") --> " + "(" + container + ", " + screenId + ", " + cellX + ", " + cellY + ")"; Launcher.sDumpLogs.add(transaction); Log.d(TAG, transaction); item.cellX = cellX; @@ -529,11 +534,11 @@ public class LauncherModel extends BroadcastReceiver { // We store hotseat items in canonical form which is this orientation invariant position // in the hotseat - if (context instanceof Launcher && screen < 0 && + if (context instanceof Launcher && screenId < 0 && container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); + item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); } else { - item.screen = screen; + item.screenId = screenId; } final ContentValues values = new ContentValues(); @@ -542,7 +547,7 @@ public class LauncherModel extends BroadcastReceiver { values.put(LauncherSettings.Favorites.CELLY, item.cellY); values.put(LauncherSettings.Favorites.SPANX, item.spanX); values.put(LauncherSettings.Favorites.SPANY, item.spanY); - values.put(LauncherSettings.Favorites.SCREEN, item.screen); + values.put(LauncherSettings.Favorites.SCREEN, item.screenId); updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase"); } @@ -604,7 +609,7 @@ public class LauncherModel extends BroadcastReceiver { item.spanY = c.getInt(spanYIndex); item.container = c.getInt(containerIndex); item.itemType = c.getInt(itemTypeIndex); - item.screen = c.getInt(screenIndex); + item.screenId = c.getInt(screenIndex); items.add(item); } @@ -646,7 +651,7 @@ public class LauncherModel extends BroadcastReceiver { folderInfo.title = c.getString(titleIndex); folderInfo.id = id; folderInfo.container = c.getInt(containerIndex); - folderInfo.screen = c.getInt(screenIndex); + folderInfo.screenId = c.getInt(screenIndex); folderInfo.cellX = c.getInt(cellXIndex); folderInfo.cellY = c.getInt(cellYIndex); @@ -664,17 +669,17 @@ public class LauncherModel extends BroadcastReceiver { * cellY fields of the item. Also assigns an ID to the item. */ static void addItemToDatabase(Context context, final ItemInfo item, final long container, - final int screen, final int cellX, final int cellY, final boolean notify) { + final long screenId, final int cellX, final int cellY, final boolean notify) { item.container = container; item.cellX = cellX; item.cellY = cellY; // We store hotseat items in canonical form which is this orientation invariant position // in the hotseat - if (context instanceof Launcher && screen < 0 && + if (context instanceof Launcher && screenId < 0 && container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); + item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); } else { - item.screen = screen; + item.screenId = screenId; } final ContentValues values = new ContentValues(); @@ -682,14 +687,14 @@ public class LauncherModel extends BroadcastReceiver { item.onAddToDatabase(values); LauncherAppState app = LauncherAppState.getInstance(); - item.id = app.getLauncherProvider().generateNewId(); + item.id = app.getLauncherProvider().generateNewItemId(); values.put(LauncherSettings.Favorites._ID, item.id); item.updateValuesWithCoordinates(values, item.cellX, item.cellY); Runnable r = new Runnable() { public void run() { String transaction = "DbDebug Add item (" + item.title + ") to db, id: " - + item.id + " (" + container + ", " + screen + ", " + cellX + ", " + + item.id + " (" + container + ", " + screenId + ", " + cellX + ", " + cellY + ")"; Launcher.sDumpLogs.add(transaction); Log.d(TAG, transaction); @@ -734,9 +739,9 @@ public class LauncherModel extends BroadcastReceiver { * Creates a new unique child id, for a given cell span across all layouts. */ static int getCellLayoutChildId( - long container, int screen, int localCellX, int localCellY, int spanX, int spanY) { + long container, long screen, int localCellX, int localCellY, int spanX, int spanY) { return (((int) container & 0xFF) << 24) - | (screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF); + | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF); } static int getCellCountX() { @@ -768,7 +773,7 @@ public class LauncherModel extends BroadcastReceiver { Runnable r = new Runnable() { public void run() { String transaction = "DbDebug Delete item (" + item.title + ") from db, id: " - + item.id + " (" + item.container + ", " + item.screen + ", " + item.cellX + + + item.id + " (" + item.container + ", " + item.screenId + ", " + item.cellX + ", " + item.cellY + ")"; Launcher.sDumpLogs.add(transaction); Log.d(TAG, transaction); @@ -808,6 +813,48 @@ public class LauncherModel extends BroadcastReceiver { runOnWorkerThread(r); } + /** + * Update the order of the workspace screens in the database. The array list contains + * a list of screen ids in the order that they should appear. + */ + static void updateWorkspaceScreenOrder(Context context, final ArrayList screens) { + final ContentResolver cr = context.getContentResolver(); + final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; + + // Remove any negative screen ids -- these aren't persisted + Iterator iter = screens.iterator(); + while (iter.hasNext()) { + long id = iter.next(); + if (id < 0) { + iter.remove(); + } + } + + Runnable r = new Runnable() { + @Override + public void run() { + final ArrayList screensCopy = new ArrayList(); + + // Clear the table + cr.delete(uri, null, null); + int count = screens.size(); + ContentValues[] values = new ContentValues[count]; + for (int i = 0; i < count; i++) { + ContentValues v = new ContentValues(); + long screenId = screens.get(i); + v.put(LauncherSettings.WorkspaceScreens._ID, screenId); + v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i); + screensCopy.add(screenId); + values[i] = v; + } + cr.bulkInsert(uri, values); + sBgWorkspaceScreens.clear(); + sBgWorkspaceScreens.addAll(screensCopy); + } + }; + runOnWorkerThread(r); + } + /** * Remove the contents of the specified folder from the database */ @@ -1219,7 +1266,6 @@ public class LauncherModel extends BroadcastReceiver { } } - // Update the saved icons if necessary if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons"); synchronized (sBgLock) { @@ -1280,23 +1326,23 @@ public class LauncherModel extends BroadcastReceiver { } // check & update map of what's occupied; used to discard overlapping/invalid items - private boolean checkItemPlacement(ItemInfo occupied[][][], ItemInfo item) { - int containerIndex = item.screen; + private boolean checkItemPlacement(HashMap occupied, ItemInfo item) { + long containerIndex = item.screenId; if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { - // Return early if we detect that an item is under the hotseat button - if (mCallbacks == null || mCallbacks.get().isAllAppsButtonRank(item.screen)) { - return false; - } - - // We use the last index to refer to the hotseat and the screen as the rank, so - // test and update the occupied state accordingly - if (occupied[Launcher.SCREEN_COUNT][item.screen][0] != null) { - Log.e(TAG, "Error loading shortcut into hotseat " + item - + " into position (" + item.screen + ":" + item.cellX + "," + item.cellY - + ") occupied by " + occupied[Launcher.SCREEN_COUNT][item.screen][0]); - return false; + if (occupied.containsKey(LauncherSettings.Favorites.CONTAINER_HOTSEAT)) { + if (occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT) + [(int) item.screenId][0] != null) { + Log.e(TAG, "Error loading shortcut into hotseat " + item + + " into position (" + item.screenId + ":" + item.cellX + "," + + item.cellY + ") occupied by " + + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT) + [(int) item.screenId][0]); + return false; + } } else { - occupied[Launcher.SCREEN_COUNT][item.screen][0] = item; + ItemInfo[][] items = new ItemInfo[mCellCountX + 1][mCellCountY + 1]; + items[(int) item.screenId][0] = item; + occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items); return true; } } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { @@ -1304,22 +1350,28 @@ public class LauncherModel extends BroadcastReceiver { return true; } + if (!occupied.containsKey(item.screenId)) { + ItemInfo[][] items = new ItemInfo[mCellCountX + 1][mCellCountY + 1]; + occupied.put(item.screenId, items); + } + + ItemInfo[][] screens = occupied.get(item.screenId); // Check if any workspace icons overlap with each other for (int x = item.cellX; x < (item.cellX+item.spanX); x++) { for (int y = item.cellY; y < (item.cellY+item.spanY); y++) { - if (occupied[containerIndex][x][y] != null) { + if (screens[x][y] != null) { Log.e(TAG, "Error loading shortcut " + item - + " into cell (" + containerIndex + "-" + item.screen + ":" + + " into cell (" + containerIndex + "-" + item.screenId + ":" + x + "," + y + ") occupied by " - + occupied[containerIndex][x][y]); + + screens[x][y]); return false; } } } for (int x = item.cellX; x < (item.cellX+item.spanX); x++) { for (int y = item.cellY; y < (item.cellY+item.spanY); y++) { - occupied[containerIndex][x][y] = item; + screens[x][y] = item; } } @@ -1348,6 +1400,7 @@ public class LauncherModel extends BroadcastReceiver { sBgFolders.clear(); sBgItemsIdMap.clear(); sBgDbIconCache.clear(); + sBgWorkspaceScreens.clear(); final ArrayList itemsToRemove = new ArrayList(); @@ -1356,8 +1409,7 @@ public class LauncherModel extends BroadcastReceiver { // +1 for the hotseat (it can be larger than the workspace) // Load workspace in reverse order to ensure that latest items are loaded first (and // before any earlier duplicates) - final ItemInfo occupied[][][] = - new ItemInfo[Launcher.SCREEN_COUNT + 1][mCellCountX + 1][mCellCountY + 1]; + final HashMap occupied = new HashMap(); try { final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); @@ -1439,7 +1491,7 @@ public class LauncherModel extends BroadcastReceiver { info.id = c.getLong(idIndex); container = c.getInt(containerIndex); info.container = container; - info.screen = c.getInt(screenIndex); + info.screenId = c.getInt(screenIndex); info.cellX = c.getInt(cellXIndex); info.cellY = c.getInt(cellYIndex); // check & update map of what's occupied @@ -1461,7 +1513,7 @@ public class LauncherModel extends BroadcastReceiver { } if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && loadOldDb) { - info.screen = permuteScreens(info.screen); + info.screenId = permuteScreens(info.screenId); } sBgItemsIdMap.put(info.id, info); @@ -1488,7 +1540,7 @@ public class LauncherModel extends BroadcastReceiver { folderInfo.id = id; container = c.getInt(containerIndex); folderInfo.container = container; - folderInfo.screen = c.getInt(screenIndex); + folderInfo.screenId = c.getInt(screenIndex); folderInfo.cellX = c.getInt(cellXIndex); folderInfo.cellY = c.getInt(cellYIndex); @@ -1504,7 +1556,7 @@ public class LauncherModel extends BroadcastReceiver { } if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && loadOldDb) { - folderInfo.screen = permuteScreens(folderInfo.screen); + folderInfo.screenId = permuteScreens(folderInfo.screenId); } sBgItemsIdMap.put(folderInfo.id, folderInfo); @@ -1530,7 +1582,7 @@ public class LauncherModel extends BroadcastReceiver { appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, provider.provider); appWidgetInfo.id = id; - appWidgetInfo.screen = c.getInt(screenIndex); + appWidgetInfo.screenId = c.getInt(screenIndex); appWidgetInfo.cellX = c.getInt(cellXIndex); appWidgetInfo.cellY = c.getInt(cellYIndex); appWidgetInfo.spanX = c.getInt(spanXIndex); @@ -1548,7 +1600,8 @@ public class LauncherModel extends BroadcastReceiver { } if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && loadOldDb) { - appWidgetInfo.screen = permuteScreens(appWidgetInfo.screen); + appWidgetInfo.screenId = + permuteScreens(appWidgetInfo.screenId); } appWidgetInfo.container = c.getInt(containerIndex); @@ -1587,17 +1640,86 @@ public class LauncherModel extends BroadcastReceiver { } } + if (loadOldDb) { + long maxScreenId = 0; + // If we're importing we use the old screen order. + for (ItemInfo item: sBgItemsIdMap.values()) { + long screenId = item.screenId; + if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && + !sBgWorkspaceScreens.contains(screenId)) { + sBgWorkspaceScreens.add(screenId); + if (screenId > maxScreenId) { + maxScreenId = screenId; + } + } + } + Collections.sort(sBgWorkspaceScreens); + mApp.getLauncherProvider().updateMaxScreenId(maxScreenId); + updateWorkspaceScreenOrder(context, sBgWorkspaceScreens); + } else { + Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI; + final Cursor sc = contentResolver.query(screensUri, null, null, null, null); + TreeMap orderedScreens = new TreeMap(); + + try { + final int idIndex = sc.getColumnIndexOrThrow( + LauncherSettings.WorkspaceScreens._ID); + final int rankIndex = sc.getColumnIndexOrThrow( + LauncherSettings.WorkspaceScreens.SCREEN_RANK); + while (sc.moveToNext()) { + try { + long screenId = sc.getLong(idIndex); + int rank = sc.getInt(rankIndex); + + orderedScreens.put(rank, screenId); + } catch (Exception e) { + Log.w(TAG, "Desktop items loading interrupted:", e); + } + } + } finally { + sc.close(); + } + + Iterator iter = orderedScreens.keySet().iterator(); + while (iter.hasNext()) { + sBgWorkspaceScreens.add(orderedScreens.get(iter.next())); + } + + // Remove any empty screens + ArrayList unusedScreens = new ArrayList(); + unusedScreens.addAll(sBgWorkspaceScreens); + + for (ItemInfo item: sBgItemsIdMap.values()) { + long screenId = item.screenId; + + if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && + unusedScreens.contains(screenId)) { + unusedScreens.remove(screenId); + } + } + + // If there are any empty screens remove them, and update. + if (unusedScreens.size() != 0) { + sBgWorkspaceScreens.removeAll(unusedScreens); + updateWorkspaceScreenOrder(context, sBgWorkspaceScreens); + } + } + if (DEBUG_LOADERS) { Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms"); Log.d(TAG, "workspace layout: "); + Iterator iter = occupied.keySet().iterator(); + int nScreens = occupied.size(); for (int y = 0; y < mCellCountY; y++) { String line = ""; - for (int s = 0; s < Launcher.SCREEN_COUNT; s++) { + + for (int s = 0; s < nScreens; s++) { + long screenId = iter.next(); if (s > 0) { line += " | "; } for (int x = 0; x < mCellCountX; x++) { - line += ((occupied[s][x][y] != null) ? "#" : "."); + line += ((occupied.get(screenId)[x][y] != null) ? "#" : "."); } } Log.d(TAG, "[ " + line + " ]"); @@ -1608,7 +1730,7 @@ public class LauncherModel extends BroadcastReceiver { // We rearrange the screens from the old launcher // 12345 -> 34512 - private int permuteScreens(int screen) { + private long permuteScreens(long screen) { if (screen >= 2) { return screen - 2; } else { @@ -1649,7 +1771,7 @@ public class LauncherModel extends BroadcastReceiver { }); for (ItemInfo info : allWorkspaceItems) { if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { - if (info.screen == currentScreen) { + if (info.screenId == currentScreen) { currentScreenItems.add(info); itemsOnScreen.add(info.id); } else { @@ -1683,7 +1805,7 @@ public class LauncherModel extends BroadcastReceiver { for (LauncherAppWidgetInfo widget : appWidgets) { if (widget == null) continue; if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && - widget.screen == currentScreen) { + widget.screenId == currentScreen) { currentScreenWidgets.add(widget); } else { otherScreenWidgets.add(widget); @@ -1708,7 +1830,7 @@ public class LauncherModel extends BroadcastReceiver { FolderInfo folder = folders.get(id); if (info == null || folder == null) continue; if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP && - info.screen == currentScreen) { + info.screenId == currentScreen) { currentScreenFolders.put(id, folder); } else { otherScreenFolders.put(id, folder); @@ -1727,15 +1849,30 @@ public class LauncherModel extends BroadcastReceiver { int cellCountY = LauncherModel.getCellCountY(); int screenOffset = cellCountX * cellCountY; int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat - long lr = (lhs.container * containerOffset + lhs.screen * screenOffset + + long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset + lhs.cellY * cellCountX + lhs.cellX); - long rr = (rhs.container * containerOffset + rhs.screen * screenOffset + + long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset + rhs.cellY * cellCountX + rhs.cellX); return (int) (lr - rr); } }); } + private void bindWorkspaceScreens(final Callbacks oldCallbacks, + final ArrayList orderedScreens) { + + final Runnable r = new Runnable() { + @Override + public void run() { + Callbacks callbacks = tryGetCallbacks(oldCallbacks); + if (callbacks != null) { + callbacks.bindScreens(orderedScreens); + } + } + }; + runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + } + private void bindWorkspaceItems(final Callbacks oldCallbacks, final ArrayList workspaceItems, final ArrayList appWidgets, @@ -1830,11 +1967,13 @@ public class LauncherModel extends BroadcastReceiver { new ArrayList(); HashMap folders = new HashMap(); HashMap itemsIdMap = new HashMap(); + ArrayList orderedScreenIds = new ArrayList(); synchronized (sBgLock) { workspaceItems.addAll(sBgWorkspaceItems); appWidgets.addAll(sBgAppWidgets); folders.putAll(sBgFolders); itemsIdMap.putAll(sBgItemsIdMap); + orderedScreenIds.addAll(sBgWorkspaceScreens); } ArrayList currentWorkspaceItems = new ArrayList(); @@ -1867,6 +2006,8 @@ public class LauncherModel extends BroadcastReceiver { }; runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); + bindWorkspaceScreens(oldCallbacks, orderedScreenIds); + // Load items on the current page bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, currentFolders, null); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index f971a3743..91e58e2af 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -66,12 +66,13 @@ public class LauncherProvider extends ContentProvider { private static final String DATABASE_NAME = "launcher.db"; - private static final int DATABASE_VERSION = 12; + private static final int DATABASE_VERSION = 13; static final String OLD_AUTHORITY = "com.android.launcher2.settings"; static final String AUTHORITY = "com.android.launcher3.settings"; static final String TABLE_FAVORITES = "favorites"; + static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens"; static final String PARAMETER_NOTIFY = "notify"; static final String DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED = "DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED"; @@ -90,6 +91,7 @@ public class LauncherProvider extends ContentProvider { Uri.parse("content://" + AUTHORITY + "/appWidgetReset"); private DatabaseHelper mOpenHelper; + private static boolean sLoadOldDb; @Override public boolean onCreate() { @@ -202,8 +204,18 @@ public class LauncherProvider extends ContentProvider { } } - public long generateNewId() { - return mOpenHelper.generateNewId(); + public long generateNewItemId() { + return mOpenHelper.generateNewItemId(); + } + + public long generateNewScreenId() { + return mOpenHelper.generateNewScreenId(); + } + + // This is only required one time while loading the workspace during the + // upgrade path, and should never be called from anywhere else. + public void updateMaxScreenId(long maxScreenId) { + mOpenHelper.updateMaxScreenId(maxScreenId); } /** @@ -213,7 +225,9 @@ public class LauncherProvider extends ContentProvider { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE); - boolean loadOldDb = false; + boolean loadOldDb = false || sLoadOldDb; + + sLoadOldDb = false; if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) { SharedPreferences.Editor editor = sp.edit(); @@ -263,7 +277,8 @@ public class LauncherProvider extends ContentProvider { private final Context mContext; private final AppWidgetHost mAppWidgetHost; - private long mMaxId = -1; + private long mMaxItemId = -1; + private long mMaxScreenId = -1; DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -272,8 +287,11 @@ public class LauncherProvider extends ContentProvider { // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from // the DB here - if (mMaxId == -1) { - mMaxId = initializeMaxId(getWritableDatabase()); + if (mMaxItemId == -1) { + mMaxItemId = initializeMaxItemId(getWritableDatabase()); + } + if (mMaxScreenId == -1) { + mMaxScreenId = initializeMaxScreenId(getWritableDatabase()); } } @@ -292,7 +310,8 @@ public class LauncherProvider extends ContentProvider { public void onCreate(SQLiteDatabase db) { if (LOGD) Log.d(TAG, "creating new launcher database"); - mMaxId = 1; + mMaxItemId = 1; + mMaxScreenId = 0; db.execSQL("CREATE TABLE favorites (" + "_id INTEGER PRIMARY KEY," + @@ -314,6 +333,7 @@ public class LauncherProvider extends ContentProvider { "uri TEXT," + "displayMode INTEGER" + ");"); + addWorkspacesTable(db); // Database was just created, so wipe any previous widgets if (mAppWidgetHost != null) { @@ -327,6 +347,13 @@ public class LauncherProvider extends ContentProvider { } } + private void addWorkspacesTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_WORKSPACE_SCREENS + " (" + + LauncherSettings.WorkspaceScreens._ID + " INTEGER," + + LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER" + + ");"); + } + private void setFlagToLoadDefaultWorkspaceLater() { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE); @@ -504,8 +531,8 @@ public class LauncherProvider extends ContentProvider { if (version < 9) { // The max id is not yet set at this point (onUpgrade is triggered in the ctor // before it gets a change to get set, so we need to read it here when we use it) - if (mMaxId == -1) { - mMaxId = initializeMaxId(db); + if (mMaxItemId == -1) { + mMaxItemId = initializeMaxItemId(db); } // Add default hotseat icons @@ -524,9 +551,24 @@ public class LauncherProvider extends ContentProvider { version = 12; } + if (version < 13) { + // With the new shrink-wrapped and re-orderable workspaces, it makes sense + // to persist workspace screens and their relative order. + mMaxScreenId = 0; + + // This will never happen in the wild, but when we switch to using workspace + // screen ids, redo the import from old launcher. + sLoadOldDb = true; + + addWorkspacesTable(db); + version = 13; + } + if (version != DATABASE_VERSION) { Log.w(TAG, "Destroying all old data."); db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS); + onCreate(db); } } @@ -672,15 +714,15 @@ public class LauncherProvider extends ContentProvider { // constructor from the worker thread; however, this doesn't extend until after the // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp // after that point - public long generateNewId() { - if (mMaxId < 0) { - throw new RuntimeException("Error: max id was not initialized"); + public long generateNewItemId() { + if (mMaxItemId < 0) { + throw new RuntimeException("Error: max item id was not initialized"); } - mMaxId += 1; - return mMaxId; + mMaxItemId += 1; + return mMaxItemId; } - private long initializeMaxId(SQLiteDatabase db) { + private long initializeMaxItemId(SQLiteDatabase db) { Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null); // get the result @@ -694,7 +736,44 @@ public class LauncherProvider extends ContentProvider { } if (id == -1) { - throw new RuntimeException("Error: could not query max id"); + throw new RuntimeException("Error: could not query max item id"); + } + + return id; + } + + // Generates a new ID to use for an workspace screen in your database. This method + // should be only called from the main UI thread. As an exception, we do call it when we + // call the constructor from the worker thread; however, this doesn't extend until after the + // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp + // after that point + public long generateNewScreenId() { + if (mMaxScreenId < 0) { + throw new RuntimeException("Error: max screen id was not initialized"); + } + mMaxScreenId += 1; + return mMaxScreenId; + } + + public void updateMaxScreenId(long maxScreenId) { + mMaxScreenId = maxScreenId; + } + + private long initializeMaxScreenId(SQLiteDatabase db) { + Cursor c = db.rawQuery("SELECT MAX(" + LauncherSettings.WorkspaceScreens._ID + ") FROM " + TABLE_WORKSPACE_SCREENS, null); + + // get the result + final int maxIdIndex = 0; + long id = -1; + if (c != null && c.moveToNext()) { + id = c.getLong(maxIdIndex); + } + if (c != null) { + c.close(); + } + + if (id == -1) { + throw new RuntimeException("Error: could not query max screen id"); } return id; @@ -959,7 +1038,7 @@ public class LauncherProvider extends ContentProvider { cn = new ComponentName(packages[0], className); info = packageManager.getActivityInfo(cn, 0); } - id = generateNewId(); + id = generateNewItemId(); intent.setComponent(cn); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); @@ -968,7 +1047,7 @@ public class LauncherProvider extends ContentProvider { values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION); values.put(Favorites.SPANX, 1); values.put(Favorites.SPANY, 1); - values.put(Favorites._ID, generateNewId()); + values.put(Favorites._ID, generateNewItemId()); if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) { return -1; } @@ -983,7 +1062,7 @@ public class LauncherProvider extends ContentProvider { values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER); values.put(Favorites.SPANX, 1); values.put(Favorites.SPANY, 1); - long id = generateNewId(); + long id = generateNewItemId(); values.put(Favorites._ID, id); if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) <= 0) { return -1; @@ -1088,7 +1167,6 @@ public class LauncherProvider extends ContentProvider { return false; } - private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn, int spanX, int spanY, Bundle extras) { boolean allocatedAppWidgets = false; @@ -1101,7 +1179,7 @@ public class LauncherProvider extends ContentProvider { values.put(Favorites.SPANX, spanX); values.put(Favorites.SPANY, spanY); values.put(Favorites.APPWIDGET_ID, appWidgetId); - values.put(Favorites._ID, generateNewId()); + values.put(Favorites._ID, generateNewItemId()); dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values); allocatedAppWidgets = true; @@ -1146,7 +1224,7 @@ public class LauncherProvider extends ContentProvider { return -1; } - long id = generateNewId(); + long id = generateNewItemId(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); values.put(Favorites.INTENT, intent.toUri(0)); values.put(Favorites.TITLE, r.getString(titleResId)); diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index eb395c8bf..a2b9c8143 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -90,6 +90,26 @@ class LauncherSettings { static final String ICON = "icon"; } + /** + * Workspace Screens. + * + * Tracks the order of workspace screens. + */ + static final class WorkspaceScreens implements BaseColumns { + /** + * The content:// style URL for this table + */ + static final Uri CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_WORKSPACE_SCREENS + + "?" + LauncherProvider.PARAMETER_NOTIFY + "=true"); + + /** + * The rank of this screen -- ie. how it is ordered relative to the other screens. + *

Type: INTEGER

+ */ + static final String SCREEN_RANK = "screenRank"; + } + /** * Favorites. */ diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index abf8bbd14..842dc2034 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -491,7 +491,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (!mIsDataReady) { + if (!mIsDataReady || getChildCount() == 0) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } @@ -650,7 +650,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if (!mIsDataReady) { + if (!mIsDataReady || getChildCount() == 0) { return; } diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java index 5249fec02..224b2fca4 100644 --- a/src/com/android/launcher3/ShortcutInfo.java +++ b/src/com/android/launcher3/ShortcutInfo.java @@ -145,7 +145,7 @@ class ShortcutInfo extends ItemInfo { @Override public String toString() { return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id - + " type=" + this.itemType + " container=" + this.container + " screen=" + screen + + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + dropPos + ")"; } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 9a75cc1d5..853e9ee85 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -60,6 +60,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -105,9 +106,15 @@ public class Workspace extends SmoothPagedView private IBinder mWindowToken; private static final float WALLPAPER_SCREENS_SPAN = 2f; - public int mNumPagesToLeft = 0; private int mDefaultPage; + // The screen id used for the empty screen always present to the right. + private final static long EXTRA_EMPTY_SCREEN_ID = -201; + private final static long CUSTOM_CONTENT_SCREEN_ID = -301; + + private HashMap mWorkspaceScreens = new HashMap(); + private ArrayList mScreenOrder = new ArrayList(); + /** * CellInfo for the cell that is currently being dragged */ @@ -254,6 +261,7 @@ public class Workspace extends SmoothPagedView private float[] mNewBackgroundAlphas; private float[] mNewAlphas; private float[] mNewRotationYs; + private int mLastChildCount = -1; private float mTransitionProgress; private final Runnable mBindPages = new Runnable() { @@ -375,6 +383,7 @@ public class Workspace extends SmoothPagedView return size; } } + public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo, int hCell, int vCell, int hSpan, int vSpan) { Rect r = new Rect(); @@ -402,13 +411,6 @@ public class Workspace extends SmoothPagedView UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext()); } - // Just a hack so that if a custom content screen is added to the left, we adjust the - // default screen accordingly so that it stays the same. - void incrementNumScreensToLeft() { - mDefaultPage++; - mNumPagesToLeft++; - } - /** * Initializes various states for this workspace. */ @@ -489,19 +491,131 @@ public class Workspace extends SmoothPagedView return mTouchState != TOUCH_STATE_REST; } - /** - * Adds the specified child in the specified screen. The position and dimension of - * the child are defined by x, y, spanX and spanY. - * - * @param child The child to add in one of the workspace's screens. - * @param screen The screen in which to add the child. - * @param x The X position of the child in the screen's grid. - * @param y The Y position of the child in the screen's grid. - * @param spanX The number of cells spanned horizontally by the child. - * @param spanY The number of cells spanned vertically by the child. - */ - void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY) { - addInScreen(child, container, screen, x, y, spanX, spanY, false); + public long insertNewWorkspaceScreen(long screenId) { + return insertNewWorkspaceScreen(screenId, true); + } + + public long insertNewWorkspaceScreenOnBind(long screenId) { + return insertNewWorkspaceScreen(screenId, false); + } + + // If screen id is -1, this indicates there is no screen assigned, so we generate + // a new screen id. + public long insertNewWorkspaceScreen(long screenId, boolean updateDb) { + CellLayout newScreen = (CellLayout) + mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); + + addView(newScreen, getChildCount()); + mWorkspaceScreens.put(screenId, newScreen); + mScreenOrder.add(screenId); + if (updateDb) { + // On bind we don't need to update the screens in the database. + LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder); + } + return screenId; + } + + public void addCustomContentToLeft(View customContent) { + CellLayout customScreen = (CellLayout) + mLauncher.getLayoutInflater().inflate(R.layout.workspace_custom_content, null); + + int spanX = customScreen.getCountX(); + int spanY = customScreen.getCountY(); + + CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY); + lp.canReorder = false; + + customScreen.addViewToCellLayout(customContent, 0, 0, lp, true); + + addView(customScreen, 0); + + mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen); + mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID); + + // Ensure that the current page and default page are maintained. + mDefaultPage++; + setCurrentPage(getCurrentPage() + 1); + } + + public long commitExtraEmptyScreen() { + CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID); + mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID); + + long newId = LauncherAppState.getInstance().getLauncherProvider().generateNewScreenId(); + mWorkspaceScreens.put(newId, cl); + mScreenOrder.add(newId); + + addExtraEmptyScreen(); + return newId; + } + + public void addExtraEmptyScreen() { + insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID, false); + } + + public CellLayout getScreenWithId(long screenId) { + CellLayout layout = mWorkspaceScreens.get(screenId); + return layout; + } + + public long getIdForScreen(CellLayout layout) { + Iterator iter = mWorkspaceScreens.keySet().iterator(); + while (iter.hasNext()) { + long id = iter.next(); + if (mWorkspaceScreens.get(id) == layout) { + return id; + } + } + return -1; + } + + public int getPageIndexForScreenId(long screenId) { + return indexOfChild(mWorkspaceScreens.get(screenId)); + } + + public long getScreenIdForPageIndex(int index) { + return mScreenOrder.get(index); + } + + public void stripEmptyScreens() { + ArrayList removeScreens = new ArrayList(); + for (Long id: mWorkspaceScreens.keySet()) { + CellLayout cl = mWorkspaceScreens.get(id); + if (id != EXTRA_EMPTY_SCREEN_ID && cl.getShortcutsAndWidgets().getChildCount() == 0) { + removeScreens.add(id); + } + } + + int pageShift = 0; + for (Long id: removeScreens) { + CellLayout cl = mWorkspaceScreens.get(id); + mWorkspaceScreens.remove(id); + mScreenOrder.remove(id); + if (indexOfChild(cl) < mCurrentPage) { + pageShift++; + } + removeView(cl); + } + setCurrentPage(mCurrentPage - pageShift); + } + + // See implementation for parameter definition. + void addInScreen(View child, long container, long screenId, + int x, int y, int spanX, int spanY) { + addInScreen(child, container, screenId, x, y, spanX, spanY, false, false); + } + + // At bind time, we use the rank (screenId) to compute x and y for hotseat items. + // See implementation for parameter definition. + void addInScreenFromBind(View child, long container, long screenId, int x, int y, + int spanX, int spanY) { + addInScreen(child, container, screenId, x, y, spanX, spanY, false, true); + } + + // See implementation for parameter definition. + void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY, + boolean insert) { + addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false); } /** @@ -509,23 +623,30 @@ public class Workspace extends SmoothPagedView * the child are defined by x, y, spanX and spanY. * * @param child The child to add in one of the workspace's screens. - * @param screen The screen in which to add the child. + * @param screenId The screen in which to add the child. * @param x The X position of the child in the screen's grid. * @param y The Y position of the child in the screen's grid. * @param spanX The number of cells spanned horizontally by the child. * @param spanY The number of cells spanned vertically by the child. * @param insert When true, the child is inserted at the beginning of the children list. + * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute + * the x and y position in which to place hotseat items. Otherwise + * we use the x and y position to compute the rank. */ - void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY, - boolean insert) { + void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY, + boolean insert, boolean computeXYFromRank) { if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { - if (screen < 0 || screen >= getChildCount()) { - Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() - + " (was " + screen + "); skipping child"); + if (getScreenWithId(screenId) == null) { + Log.e(TAG, "Skipping child, screenId " + screenId + " not found"); return; } } + // If an item is added to the extra empty screen, we convert it to a real + if (screenId == EXTRA_EMPTY_SCREEN_ID) { + screenId = commitExtraEmptyScreen(); + } + final CellLayout layout; if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { layout = mLauncher.getHotseat().getLayout(); @@ -536,21 +657,18 @@ public class Workspace extends SmoothPagedView ((FolderIcon) child).setTextVisible(false); } - if (screen < 0) { - screen = mLauncher.getHotseat().getOrderInHotseat(x, y); + if (computeXYFromRank) { + x = mLauncher.getHotseat().getCellXFromOrder((int) screenId); + y = mLauncher.getHotseat().getCellYFromOrder((int) screenId); } else { - // Note: We do this to ensure that the hotseat is always laid out in the orientation - // of the hotseat in order regardless of which orientation they were added - x = mLauncher.getHotseat().getCellXFromOrder(screen); - y = mLauncher.getHotseat().getCellYFromOrder(screen); + screenId = mLauncher.getHotseat().getOrderInHotseat(x, y); } } else { // Show folder title if not in the hotseat if (child instanceof FolderIcon) { ((FolderIcon) child).setTextVisible(true); } - - layout = (CellLayout) getChildAt(screen); + layout = getScreenWithId(screenId); child.setOnKeyListener(new IconKeyEventListener()); } @@ -571,7 +689,7 @@ public class Workspace extends SmoothPagedView } // Get the canonical child id to uniquely represent this view in this screen - int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY); + int childId = LauncherModel.getCellLayoutChildId(container, screenId, x, y, spanX, spanY); boolean markCellsAsOccupied = !(child instanceof Folder); if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) { // TODO: This branch occurs when the workspace is adding views @@ -912,7 +1030,8 @@ public class Workspace extends SmoothPagedView private void syncWallpaperOffsetWithScroll() { final boolean enableWallpaperEffects = isHardwareAccelerated(); if (enableWallpaperEffects) { - mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll()); + // TODO: figure out what to do about parallax, for now disable it + //mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll()); } } @@ -968,6 +1087,10 @@ public class Workspace extends SmoothPagedView snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION); } + protected void snapToScreenId(long screenId, Runnable r) { + snapToPage(getPageIndexForScreenId(screenId), r); + } + private void computeWallpaperScrollRatio(int page) { // Here, we determine what the desired scroll would be with and without a layout scale, // and compute a ratio between the two. This allows us to adjust the wallpaper offset @@ -1558,7 +1681,7 @@ public class Workspace extends SmoothPagedView private void initAnimationArrays() { final int childCount = getChildCount(); - if (mOldTranslationXs != null) return; + if (mLastChildCount == childCount) return; mOldTranslationXs = new float[childCount]; mOldTranslationYs = new float[childCount]; mOldScaleXs = new float[childCount]; @@ -1958,16 +2081,15 @@ public class Workspace extends SmoothPagedView showScrollingIndicator(false); } - void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen, + void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId, int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) { View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info); final int[] cellXY = new int[2]; target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); - addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst); + addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst); - int adjustedScreen = screen - mNumPagesToLeft; - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, adjustedScreen, cellXY[0], + LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0], cellXY[1]); } @@ -2122,7 +2244,7 @@ public class Workspace extends SmoothPagedView if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false; mCreateUserFolderOnDrop = false; - final int screen = (targetCell == null) ? mDragInfo.screen : indexOfChild(target); + final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target); boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo); boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo); @@ -2140,7 +2262,7 @@ public class Workspace extends SmoothPagedView target.removeView(v); FolderIcon fi = - mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]); + mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]); destInfo.cellX = -1; destInfo.cellY = -1; sourceInfo.cellX = -1; @@ -2215,8 +2337,8 @@ public class Workspace extends SmoothPagedView long container = hasMovedIntoHotseat ? LauncherSettings.Favorites.CONTAINER_HOTSEAT : LauncherSettings.Favorites.CONTAINER_DESKTOP; - int screen = (mTargetCell[0] < 0) ? - mDragInfo.screen : indexOfChild(dropTargetLayout); + long screenId = (mTargetCell[0] < 0) ? + mDragInfo.screenId : getIdForScreen(dropTargetLayout); int spanX = mDragInfo != null ? mDragInfo.spanX : 1; int spanY = mDragInfo != null ? mDragInfo.spanY : 1; // First we find the cell nearest to point at which the item is @@ -2267,9 +2389,9 @@ public class Workspace extends SmoothPagedView resultSpan[1]); } - if (mCurrentPage != screen && !hasMovedIntoHotseat) { - snapScreen = screen; - snapToPage(screen); + if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) { + snapScreen = getPageIndexForScreenId(screenId); + snapToPage(snapScreen); } if (foundCell) { @@ -2277,7 +2399,7 @@ public class Workspace extends SmoothPagedView if (hasMovedLayouts) { // Reparent the view getParentCellLayoutForView(cell).removeView(cell); - addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1], + addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY); } @@ -2288,7 +2410,7 @@ public class Workspace extends SmoothPagedView lp.cellHSpan = item.spanX; lp.cellVSpan = item.spanY; lp.isLockedToGrid = true; - cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen, + cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screenId, mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && @@ -2319,10 +2441,7 @@ public class Workspace extends SmoothPagedView } } - //TODO: This is a hack on top of a hack, but items aren't being saved - // to the correct screen due to the extra screen. - int adjustedScreen = screen - mNumPagesToLeft; - LauncherModel.moveItemInDatabase(mLauncher, info, container, adjustedScreen, lp.cellX, + LauncherModel.moveItemInDatabase(mLauncher, info, container, screenId, lp.cellX, lp.cellY); } else { // If we can't find a drop location, we return the item to its original position @@ -2369,22 +2488,22 @@ public class Workspace extends SmoothPagedView } } - public void setFinalScrollForPageChange(int screen) { - if (screen >= 0) { + public void setFinalScrollForPageChange(int pageIndex) { + CellLayout cl = (CellLayout) getChildAt(pageIndex); + if (cl != null) { mSavedScrollX = getScrollX(); - CellLayout cl = (CellLayout) getChildAt(screen); mSavedTranslationX = cl.getTranslationX(); mSavedRotationY = cl.getRotationY(); - final int newX = getChildOffset(screen) - getRelativeChildOffset(screen); + final int newX = getChildOffset(pageIndex) - getRelativeChildOffset(pageIndex); setScrollX(newX); cl.setTranslationX(0f); cl.setRotationY(0f); } } - public void resetFinalScrollForPageChange(int screen) { - if (screen >= 0) { - CellLayout cl = (CellLayout) getChildAt(screen); + public void resetFinalScrollForPageChange(int pageIndex) { + if (pageIndex >= 0) { + CellLayout cl = (CellLayout) getChildAt(pageIndex); setScrollX(mSavedScrollX); cl.setTranslationX(mSavedTranslationX); cl.setRotationY(mSavedRotationY); @@ -3047,10 +3166,11 @@ public class Workspace extends SmoothPagedView final long container = mLauncher.isHotseatLayout(cellLayout) ? LauncherSettings.Favorites.CONTAINER_HOTSEAT : LauncherSettings.Favorites.CONTAINER_DESKTOP; - final int screen = indexOfChild(cellLayout); - if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage + final long screenId = getIdForScreen(cellLayout); + if (!mLauncher.isHotseatLayout(cellLayout) + && screenId != getScreenIdForPageIndex(mCurrentPage) && mState != State.SPRING_LOADED) { - snapToPage(screen); + snapToScreenId(screenId, null); } if (info instanceof PendingAddItemInfo) { @@ -3101,11 +3221,11 @@ public class Workspace extends SmoothPagedView span[0] = item.spanX; span[1] = item.spanY; mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo, - container, screen, mTargetCell, span, null); + container, screenId, mTargetCell, span, null); break; case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: mLauncher.processShortcutFromDrop(pendingInfo.componentName, - container, screen, mTargetCell, null); + container, screenId, mTargetCell, null); break; default: throw new IllegalStateException("Unknown item type: " + @@ -3177,14 +3297,13 @@ public class Workspace extends SmoothPagedView } else { cellLayout.findCellForSpan(mTargetCell, 1, 1); } - addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX, + addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY, insertAtFirst); cellLayout.onDropChild(view); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); cellLayout.getShortcutsAndWidgets().measureChild(view); - int adjustedScreen = screen - mNumPagesToLeft; - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, adjustedScreen, + LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, lp.cellX, lp.cellY); if (d.dragView != null) { @@ -3400,7 +3519,7 @@ public class Workspace extends SmoothPagedView if (mLauncher.isHotseatLayout(target)) { cellLayout = mLauncher.getHotseat().getLayout(); } else { - cellLayout = (CellLayout) getChildAt(mDragInfo.screen); + cellLayout = getScreenWithId(mDragInfo.screenId); } cellLayout.onDropChild(mDragInfo.cell); } @@ -3410,6 +3529,8 @@ public class Workspace extends SmoothPagedView mDragOutline = null; mDragInfo = null; + stripEmptyScreens(); + // Hide the scrolling indicator after you pick up an item hideScrollingIndicator(false); } @@ -3417,11 +3538,11 @@ public class Workspace extends SmoothPagedView void updateItemLocationsInDatabase(CellLayout cl) { int count = cl.getShortcutsAndWidgets().getChildCount(); - int screen = indexOfChild(cl); + long screenId = getIdForScreen(cl); int container = Favorites.CONTAINER_DESKTOP; if (mLauncher.isHotseatLayout(cl)) { - screen = -1; + screenId = -1; container = Favorites.CONTAINER_HOTSEAT; } @@ -3431,8 +3552,7 @@ public class Workspace extends SmoothPagedView // Null check required as the AllApps button doesn't have an item info if (info != null && info.requiresDbUpdate) { info.requiresDbUpdate = false; - int adjustedScreen = screen - mNumPagesToLeft; - LauncherModel.modifyItemInDatabase(mLauncher, info, container, adjustedScreen, info.cellX, + LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, info.cellX, info.cellY, info.spanX, info.spanY); } } @@ -3512,11 +3632,11 @@ public class Workspace extends SmoothPagedView void saveWorkspaceScreenToDb(CellLayout cl) { int count = cl.getShortcutsAndWidgets().getChildCount(); - int screen = indexOfChild(cl); + long screenId = getIdForScreen(cl); int container = Favorites.CONTAINER_DESKTOP; if (mLauncher.isHotseatLayout(cl)) { - screen = -1; + screenId = -1; container = Favorites.CONTAINER_HOTSEAT; } @@ -3525,7 +3645,7 @@ public class Workspace extends SmoothPagedView ItemInfo info = (ItemInfo) v.getTag(); // Null check required as the AllApps button doesn't have an item info if (info != null) { - LauncherModel.addItemToDatabase(mLauncher, info, container, screen, info.cellX, + LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, info.cellX, info.cellY, false); } if (v instanceof FolderIcon) { -- cgit v1.2.3