From 3d503fbd9468fb2b9fa645f4f7b91e11229edbfa Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 13 Jul 2011 17:25:49 -0700 Subject: Initial changes to add configurable hotseat. Change-Id: I4c2ed4a1c122c057662fabc70bfef7c5c088460b --- src/com/android/launcher2/CellLayout.java | 1 + src/com/android/launcher2/FocusHelper.java | 12 +- src/com/android/launcher2/Folder.java | 15 +- src/com/android/launcher2/Hotseat.java | 114 +++++ .../android/launcher2/InstallShortcutReceiver.java | 21 +- .../android/launcher2/InstallWidgetReceiver.java | 3 +- src/com/android/launcher2/Launcher.java | 461 ++++++--------------- src/com/android/launcher2/LauncherModel.java | 58 ++- src/com/android/launcher2/LauncherProvider.java | 92 ++-- src/com/android/launcher2/LauncherSettings.java | 1 + src/com/android/launcher2/Workspace.java | 278 +++++++++---- 11 files changed, 568 insertions(+), 488 deletions(-) create mode 100644 src/com/android/launcher2/Hotseat.java (limited to 'src/com/android') diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index ae2250773..bd2a94942 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -1863,6 +1863,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { int spanX; int spanY; int screen; + long container; boolean valid; @Override diff --git a/src/com/android/launcher2/FocusHelper.java b/src/com/android/launcher2/FocusHelper.java index d45c9ac15..2a5f9c433 100644 --- a/src/com/android/launcher2/FocusHelper.java +++ b/src/com/android/launcher2/FocusHelper.java @@ -41,13 +41,13 @@ class ButtonBarKeyEventListener implements View.OnKeyListener { } /** - * A keyboard listener we set on all the dock buttons. + * A keyboard listener we set on all the hotseat buttons. */ -class DockKeyEventListener implements View.OnKeyListener { +class HotseatKeyEventListener implements View.OnKeyListener { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { final Configuration configuration = v.getResources().getConfiguration(); - return FocusHelper.handleDockButtonKeyEvent(v, keyCode, event, configuration.orientation); + return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation); } } @@ -535,9 +535,9 @@ public class FocusHelper { } /** - * Handles key events in the workspace dock (bottom of the screen). + * Handles key events in the workspace hotseat (bottom of the screen). */ - static boolean handleDockButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) { + static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) { final ViewGroup parent = (ViewGroup) v.getParent(); final ViewGroup launcher = (ViewGroup) parent.getParent(); final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace); @@ -547,7 +547,7 @@ public class FocusHelper { final int pageCount = workspace.getChildCount(); // NOTE: currently we don't special case for the phone UI in different - // orientations, even though the dock is on the side in landscape mode. This + // orientations, even though the hotseat is on the side in landscape mode. This // is to ensure that accessibility consistency is maintained across rotations. final int action = e.getAction(); diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index 7641fe7f2..96cd22b56 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -732,8 +732,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList int centeredTop = centerY - height / 2; // We first fetch the currently visible CellLayoutChildren - int page = mLauncher.getWorkspace().getCurrentPage(); - CellLayout currentPage = (CellLayout) mLauncher.getWorkspace().getChildAt(page); + CellLayout currentPage = mLauncher.getWorkspace().getCurrentDropLayout(); CellLayoutChildren boundingLayout = currentPage.getChildrenLayout(); Rect bounds = new Rect(); parent.getDescendantRectRelativeToSelf(boundingLayout, bounds); @@ -851,8 +850,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } // Remove the folder completely - final CellLayout cellLayout = (CellLayout) - mLauncher.getWorkspace().getChildAt(mInfo.screen); + CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen); cellLayout.removeView(mFolderIcon); if (mFolderIcon instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) mFolderIcon); @@ -860,9 +858,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mLauncher.removeFolder(mInfo); if (finalItem != null) { - LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, - LauncherSettings.Favorites.CONTAINER_DESKTOP, mInfo.screen, - mInfo.cellX, mInfo.cellY); + LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container, + mInfo.screen, mInfo.cellX, mInfo.cellY); } LauncherModel.deleteItemFromDatabase(mLauncher, mInfo); @@ -871,8 +868,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList View child = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo) finalItem); - mLauncher.getWorkspace().addInScreen(child, mInfo.screen, mInfo.cellX, mInfo.cellY, - mInfo.spanX, mInfo.spanY); + mLauncher.getWorkspace().addInScreen(child, mInfo.container, mInfo.screen, mInfo.cellX, + mInfo.cellY, mInfo.spanX, mInfo.spanY); } } diff --git a/src/com/android/launcher2/Hotseat.java b/src/com/android/launcher2/Hotseat.java new file mode 100644 index 000000000..deab13177 --- /dev/null +++ b/src/com/android/launcher2/Hotseat.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher2; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; + +import com.android.launcher.R; + +public class Hotseat extends FrameLayout { + static final String TAG = "Hotseat"; + + private Launcher mLauncher; + private CellLayout mContent; + + private int mCellCountX; + private int mCellCountY; + private boolean mIsLandscape; + + public Hotseat(Context context) { + this(context, null); + } + + public Hotseat(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public Hotseat(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.Hotseat, defStyle, 0); + mCellCountX = a.getInt(R.styleable.Hotseat_cellCountX, -1); + mCellCountY = a.getInt(R.styleable.Hotseat_cellCountY, -1); + mIsLandscape = context.getResources().getConfiguration().orientation == + Configuration.ORIENTATION_LANDSCAPE; + } + + public void setup(Launcher launcher) { + mLauncher = launcher; + } + + CellLayout getLayout() { + return mContent; + } + + /* Get the orientation invariant order of the item in the hotseat for persistence. */ + int getOrderInHotseat(int x, int y) { + return mIsLandscape ? (mContent.getCountY() - y - 1) : x; + } + /* Get the orientation specific coordinates given an invariant order in the hotseat. */ + int getCellXFromOrder(int rank) { + return mIsLandscape ? 0 : rank; + } + int getCellYFromOrder(int rank) { + return mIsLandscape ? (mContent.getCountY() - (rank + 1)) : 0; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + if (mCellCountX < 0) mCellCountX = LauncherModel.getCellCountX(); + if (mCellCountY < 0) mCellCountY = LauncherModel.getCellCountY(); + mContent = (CellLayout) findViewById(R.id.layout); + mContent.setGridSize(mCellCountX, mCellCountY); + + resetLayout(); + } + + void resetLayout() { + mContent.removeAllViewsInLayout(); + + // Add the Apps button + Context context = getContext(); + LayoutInflater inflater = LayoutInflater.from(context); + BubbleTextView allAppsButton = (BubbleTextView) + inflater.inflate(R.layout.application, mContent, false); + allAppsButton.setCompoundDrawablesWithIntrinsicBounds(null, + context.getResources().getDrawable(R.drawable.apps_hotseat_button), null, null); + // button.setText(context.getString(R.string.all_apps_button_label)); + allAppsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(android.view.View v) { + mLauncher.showAllApps(true); + } + }); + + // 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 + int x = getCellXFromOrder(0); + int y = getCellYFromOrder(0); + mContent.addViewToCellLayout(allAppsButton, -1, 0, new CellLayout.LayoutParams(x,y,1,1), + true); + } +} diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java index c67e90ecf..9d7054cf4 100644 --- a/src/com/android/launcher2/InstallShortcutReceiver.java +++ b/src/com/android/launcher2/InstallShortcutReceiver.java @@ -65,7 +65,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true); if (duplicate || !LauncherModel.shortcutExists(context, name, intent)) { LauncherApplication app = (LauncherApplication) context.getApplicationContext(); - app.getModel().addShortcut(context, data, screen, mCoordinates[0], + app.getModel().addShortcut(context, data, + LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, mCoordinates[0], mCoordinates[1], true); Toast.makeText(context, context.getString(R.string.shortcut_installed, name), Toast.LENGTH_SHORT).show(); @@ -94,14 +95,16 @@ public class InstallShortcutReceiver extends BroadcastReceiver { int cellX, cellY, spanX, spanY; for (int i = 0; i < items.size(); ++i) { item = items.get(i); - if (item.screen == screen) { - cellX = item.cellX; - cellY = item.cellY; - spanX = item.spanX; - spanY = item.spanY; - for (int x = cellX; x < cellX + spanX && x < xCount; x++) { - for (int y = cellY; y < cellY + spanY && y < yCount; y++) { - occupied[x][y] = true; + if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + if (item.screen == screen) { + cellX = item.cellX; + cellY = item.cellY; + spanX = item.spanX; + spanY = item.spanY; + for (int x = cellX; x < cellX + spanX && x < xCount; x++) { + for (int y = cellY; y < cellY + spanY && y < yCount; y++) { + occupied[x][y] = true; + } } } } diff --git a/src/com/android/launcher2/InstallWidgetReceiver.java b/src/com/android/launcher2/InstallWidgetReceiver.java index b4ce0382f..6b3763ce0 100644 --- a/src/com/android/launcher2/InstallWidgetReceiver.java +++ b/src/com/android/launcher2/InstallWidgetReceiver.java @@ -188,7 +188,8 @@ public class InstallWidgetReceiver { final PendingAddWidgetInfo createInfo = new PendingAddWidgetInfo(widgetInfo, mMimeType, mClipData); - mLauncher.addAppWidgetFromDrop(createInfo, mTargetLayoutScreen, null, mTargetLayoutPos); + mLauncher.addAppWidgetFromDrop(createInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP, + mTargetLayoutScreen, null, mTargetLayoutPos); } } } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 26f41fa53..90bd151eb 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -115,7 +115,6 @@ public final class Launcher extends Activity static final boolean PROFILE_STARTUP = false; static final boolean DEBUG_WIDGETS = false; - static final boolean DEBUG_USER_INTERFACE = false; private static final int MENU_GROUP_ADD = 1; private static final int MENU_GROUP_WALLPAPER = MENU_GROUP_ADD + 1; @@ -149,6 +148,8 @@ public final class Launcher extends Activity // Type: int private static final String RUNTIME_STATE = "launcher.state"; // Type: int + private static final String RUNTIME_STATE_PENDING_ADD_CONTAINER = "launcher.add_container"; + // Type: int private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen"; // Type: int private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cell_x"; @@ -185,16 +186,14 @@ public final class Launcher extends Activity private AppWidgetManager mAppWidgetManager; private LauncherAppWidgetHost mAppWidgetHost; - private int mAddScreen = -1; - private int mAddCellX = -1; - private int mAddCellY = -1; - private int[] mAddDropPosition; + private ItemInfo mPendingAddInfo = new ItemInfo(); private int[] mTmpAddItemCellCoordinates = new int[2]; private FolderInfo mFolderInfo; - private ViewGroup mButtonCluster; + private Hotseat mHotseat; private View mAllAppsButton; + private SearchDropTargetBar mSearchDeleteBar; private AppsCustomizeTabHost mAppsCustomizeTabHost; private AppsCustomizePagedView mAppsCustomizeContent; @@ -259,6 +258,7 @@ public final class Launcher extends Activity private static class PendingAddArguments { int requestCode; Intent intent; + long container; int screen; int cellX; int cellY; @@ -600,20 +600,22 @@ public final class Launcher extends Activity private boolean completeAdd(PendingAddArguments args) { switch (args.requestCode) { case REQUEST_PICK_APPLICATION: - completeAddApplication(args.intent, args.screen, args.cellX, args.cellY); + completeAddApplication(args.intent, args.container, args.screen, args.cellX, + args.cellY); break; case REQUEST_PICK_SHORTCUT: processShortcut(args.intent); break; case REQUEST_CREATE_SHORTCUT: - completeAddShortcut(args.intent, args.screen, args.cellX, args.cellY); + completeAddShortcut(args.intent, args.container, args.screen, args.cellX, + args.cellY); return true; case REQUEST_PICK_APPWIDGET: addAppWidgetFromPick(args.intent); break; case REQUEST_CREATE_APPWIDGET: int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - completeAddAppWidget(appWidgetId, args.screen); + completeAddAppWidget(appWidgetId, args.container, args.screen); return true; case REQUEST_PICK_WALLPAPER: // We just wanted the activity result here so we can clear mWaitingForResult @@ -632,13 +634,15 @@ public final class Launcher extends Activity // For example, the user would PICK_SHORTCUT for "Music playlist", and we // launch over to the Music app to actually CREATE_SHORTCUT. - if (resultCode == RESULT_OK && mAddScreen != -1) { + if (resultCode == RESULT_OK && mPendingAddInfo.container != ItemInfo.NO_ID && + mPendingAddInfo.screen > -1) { final PendingAddArguments args = new PendingAddArguments(); args.requestCode = requestCode; args.intent = data; - args.screen = mAddScreen; - args.cellX = mAddCellX; - args.cellY = mAddCellY; + args.container = mPendingAddInfo.container; + args.screen = mPendingAddInfo.screen; + args.cellX = mPendingAddInfo.cellX; + args.cellY = mPendingAddInfo.cellY; // If the loader is still running, defer the add until it is done. if (isWorkspaceLocked()) { @@ -797,12 +801,15 @@ public final class Launcher extends Activity mWorkspace.setCurrentPage(currentScreen); } - final int addScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1); + final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1); + final int pendingAddScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1); + - if (addScreen > -1) { - mAddScreen = addScreen; - mAddCellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X); - mAddCellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y); + if (pendingAddContainer != ItemInfo.NO_ID && pendingAddScreen > -1) { + mPendingAddInfo.container = pendingAddContainer; + mPendingAddInfo.screen = pendingAddScreen; + mPendingAddInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X); + mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y); mRestoring = true; } @@ -841,6 +848,12 @@ public final class Launcher extends Activity // Setup the drag layer mDragLayer.setup(this, dragController); + // Setup the hotseat + mHotseat = (Hotseat) findViewById(R.id.hotseat); + if (mHotseat != null) { + mHotseat.setup(this); + } + // Setup the workspace mWorkspace.setHapticFeedbackEnabled(false); mWorkspace.setOnLongClickListener(this); @@ -857,47 +870,9 @@ public final class Launcher extends Activity mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content); mAppsCustomizeContent.setup(this, dragController); - // Setup AppsCustomize button - mAllAppsButton = mDragLayer.findViewById(R.id.all_apps_button); - mAllAppsButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - onClickAllAppsButton(v); - } - }); - if (!LauncherApplication.isScreenLarge()) { - // Setup AppsCustomize button on the phone - HandleView handleView = (HandleView) mAllAppsButton; - handleView.setLauncher(this); - handleView.setOnLongClickListener(this); - - // Setup Hotseat - ImageView hotseatLeft = (ImageView) findViewById(R.id.hotseat_left); - hotseatLeft.setContentDescription(mHotseatLabels[0]); - hotseatLeft.setImageDrawable(mHotseatIcons[0]); - ImageView hotseatRight = (ImageView) findViewById(R.id.hotseat_right); - hotseatRight.setContentDescription(mHotseatLabels[1]); - hotseatRight.setImageDrawable(mHotseatIcons[1]); - } - - if (!LauncherApplication.isScreenLarge()) { - // Setup keylistener for button cluster - mButtonCluster = (ViewGroup) findViewById(R.id.all_apps_button_cluster); - View.OnKeyListener listener = null; - if (LauncherApplication.isScreenLarge()) { - // For tablets, AllApps lives in the button bar at the top - listener = new ButtonBarKeyEventListener(); - } else { - // For phones, AppsCustomize lives in the "dock" at the bottom - listener = new DockKeyEventListener(); - } - int buttonCount = mButtonCluster.getChildCount(); - for (int i = 0; i < buttonCount; ++i) { - mButtonCluster.getChildAt(i).setOnKeyListener(listener); - } - } - // Setup the drag controller (the drop targets have to be added in reverse order) + // Setup the drag controller (drop targets have to be added in reverse order in priority) dragController.setDragScoller(mWorkspace); dragController.setScrollView(mDragLayer); dragController.setMoveTarget(mWorkspace); @@ -907,40 +882,7 @@ public final class Launcher extends Activity } } - @SuppressWarnings({"UnusedDeclaration"}) - public void previousScreen(View v) { - if (mState != State.APPS_CUSTOMIZE) { - mWorkspace.scrollLeft(); - } - } - - @SuppressWarnings({"UnusedDeclaration"}) - public void nextScreen(View v) { - if (mState != State.APPS_CUSTOMIZE) { - mWorkspace.scrollRight(); - } - } - - @SuppressWarnings({"UnusedDeclaration"}) - public void launchHotSeat(View v) { - if (mState == State.APPS_CUSTOMIZE) return; - - int index = -1; - if (v.getId() == R.id.hotseat_left) { - index = 0; - } else if (v.getId() == R.id.hotseat_right) { - index = 1; - } - // reload these every tap; you never know when they might change - loadHotseats(); - if (index >= 0 && index < mHotseats.length && mHotseats[index] != null) { - startActivitySafely( - mHotseats[index], - "hotseat" - ); - } - } /** * Creates a view representing a shortcut. @@ -976,9 +918,9 @@ public final 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, int screen, int cellX, int cellY) { + void completeAddApplication(Intent data, long container, int screen, int cellX, int cellY) { final int[] cellXY = mTmpAddItemCellCoordinates; - final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen); + final CellLayout layout = getCellLayout(container, screen); // First we check if we already know the exact location where we want to add this item. if (cellX >= 0 && cellY >= 0) { @@ -995,7 +937,7 @@ public final 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, screen, cellXY[0], cellXY[1], + mWorkspace.addApplicationShortcut(info, layout, container, screen, cellXY[0], cellXY[1], isWorkspaceLocked(), cellX, cellY); } else { Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data); @@ -1008,11 +950,12 @@ public final 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, int screen, int cellX, int cellY) { - final int[] cellXY = mTmpAddItemCellCoordinates; - final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen); + private void completeAddShortcut(Intent data, long container, int screen, int cellX, + int cellY) { + int[] cellXY = mTmpAddItemCellCoordinates; + int[] touchXY = mPendingAddInfo.dropPos; + CellLayout layout = getCellLayout(container, screen); - int[] touchXY = mAddDropPosition; boolean foundCellSpan = false; // First we check if we already know the exact location where we want to add this item. @@ -1022,9 +965,7 @@ public final class Launcher extends Activity foundCellSpan = true; } else if (touchXY != null) { // when dragging and dropping, just find the closest free spot - CellLayout screenLayout = (CellLayout) mWorkspace.getChildAt(screen); - int[] result = screenLayout.findNearestVacantArea( - touchXY[0], touchXY[1], 1, 1, cellXY); + int[] result = layout.findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, cellXY); foundCellSpan = (result != null); } else { foundCellSpan = layout.findCellForSpan(cellXY, 1, 1); @@ -1036,11 +977,12 @@ public final class Launcher extends Activity } final ShortcutInfo info = mModel.addShortcut( - this, data, screen, cellXY[0], cellXY[1], false); + this, data, container, screen, cellXY[0], cellXY[1], false); if (!mRestoring) { final View view = createShortcut(info); - mWorkspace.addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked()); + mWorkspace.addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, + isWorkspaceLocked()); } } @@ -1050,11 +992,11 @@ public final 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, int screen) { + private void completeAddAppWidget(final int appWidgetId, long container, int screen) { AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); // Calculate the grid spans needed to fit this widget - CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen); + CellLayout layout = getCellLayout(container, screen); // We want to account for the extra amount of padding that we are adding to the widget // to ensure that it gets the full amount of space that it has requested @@ -1070,18 +1012,16 @@ public final class Launcher extends Activity // Try finding open space on Launcher screen // We have saved the position to which the widget was dragged-- this really only matters // if we are placing widgets on a "spring-loaded" screen - final int[] cellXY = mTmpAddItemCellCoordinates; - - int[] touchXY = mAddDropPosition; + int[] cellXY = mTmpAddItemCellCoordinates; + int[] touchXY = mPendingAddInfo.dropPos; boolean foundCellSpan = false; - if (mAddCellX >= 0 && mAddCellY >= 0) { - cellXY[0] = mAddCellX; - cellXY[1] = mAddCellY; + if (mPendingAddInfo.cellX >= 0 && mPendingAddInfo.cellY >= 0) { + cellXY[0] = mPendingAddInfo.cellX; + cellXY[1] = mPendingAddInfo.cellY; foundCellSpan = true; } else if (touchXY != null) { // when dragging and dropping, just find the closest free spot - CellLayout screenLayout = (CellLayout) mWorkspace.getChildAt(screen); - int[] result = screenLayout.findNearestVacantArea( + int[] result = layout.findNearestVacantArea( touchXY[0], touchXY[1], spanXY[0], spanXY[1], cellXY); foundCellSpan = (result != null); } else { @@ -1108,8 +1048,7 @@ public final class Launcher extends Activity launcherInfo.spanY = spanXY[1]; LauncherModel.addItemToDatabase(this, launcherInfo, - LauncherSettings.Favorites.CONTAINER_DESKTOP, - screen, cellXY[0], cellXY[1], false); + container, screen, cellXY[0], cellXY[1], false); if (!mRestoring) { // Perform actual inflation because we're live @@ -1118,7 +1057,7 @@ public final class Launcher extends Activity launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo); launcherInfo.hostView.setTag(launcherInfo); - mWorkspace.addInScreen(launcherInfo.hostView, screen, cellXY[0], cellXY[1], + mWorkspace.addInScreen(launcherInfo.hostView, container, screen, cellXY[0], cellXY[1], launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked()); addWidgetToAutoAdvanceIfNeeded(launcherInfo.hostView, appWidgetInfo); @@ -1331,10 +1270,12 @@ public final class Launcher extends Activity // this state is reflected. closeFolder(); - if (mAddScreen > -1 && mWaitingForResult) { - outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, mAddScreen); - outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, mAddCellX); - outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, mAddCellY); + if (mPendingAddInfo.container != ItemInfo.NO_ID && mPendingAddInfo.screen > -1 && + mWaitingForResult) { + outState.putLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, mPendingAddInfo.container); + outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, mPendingAddInfo.screen); + outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, mPendingAddInfo.cellX); + outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, mPendingAddInfo.cellY); } if (mFolderInfo != null && mWaitingForResult) { @@ -1372,7 +1313,7 @@ public final class Launcher extends Activity TextKeyListener.getInstance().release(); - unbindWorkspaceItems(); + unbindWorkspaceAndHotseatItems(); getContentResolver().unregisterContentObserver(mWidgetObserver); unregisterReceiver(mCloseSystemDialogsReceiver); @@ -1507,10 +1448,11 @@ public final class Launcher extends Activity } private void resetAddInfo() { - mAddScreen = -1; - mAddCellX = -1; - mAddCellY = -1; - mAddDropPosition = null; + mPendingAddInfo.container = ItemInfo.NO_ID; + mPendingAddInfo.screen = -1; + mPendingAddInfo.cellX = mPendingAddInfo.cellY = -1; + mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1; + mPendingAddInfo.dropPos = null; } private void manageApps() { @@ -1566,7 +1508,7 @@ public final class Launcher extends Activity startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET); } else { // Otherwise just add it - completeAddAppWidget(appWidgetId, mAddScreen); + completeAddAppWidget(appWidgetId, info.container, info.screen); // Exit spring loaded mode if necessary after adding the widget exitSpringLoadedDragModeDelayed(false); @@ -1581,14 +1523,16 @@ public final class Launcher extends Activity * @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, int screen, int[] cell, int[] loc) { + void processShortcutFromDrop(ComponentName componentName, long container, int screen, + int[] cell, int[] loc) { resetAddInfo(); - mAddScreen = screen; - mAddDropPosition = loc; + mPendingAddInfo.container = container; + mPendingAddInfo.screen = screen; + mPendingAddInfo.dropPos = loc; if (cell != null) { - mAddCellX = cell[0]; - mAddCellY = cell[1]; + mPendingAddInfo.cellX = cell[0]; + mPendingAddInfo.cellY = cell[1]; } Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); @@ -1604,14 +1548,15 @@ public final class Launcher extends Activity * @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, int screen, int[] cell, int[] loc) { + void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, int screen, + int[] cell, int[] loc) { resetAddInfo(); - mAddScreen = screen; - mAddDropPosition = loc; - + mPendingAddInfo.container = info.container = container; + mPendingAddInfo.screen = info.screen = screen; + mPendingAddInfo.dropPos = loc; if (cell != null) { - mAddCellX = cell[0]; - mAddCellY = cell[1]; + mPendingAddInfo.cellX = cell[0]; + mPendingAddInfo.cellY = cell[1]; } int appWidgetId = getAppWidgetHost().allocateAppWidgetId(); @@ -1641,21 +1586,21 @@ public final class Launcher extends Activity startActivityForResult(intent, REQUEST_PICK_WALLPAPER); } - FolderIcon addFolder(final int screen, int cellX, int cellY) { + FolderIcon addFolder(CellLayout layout, long container, final int screen, int cellX, + int cellY) { final FolderInfo folderInfo = new FolderInfo(); folderInfo.title = getText(R.string.folder_name); // Update the model - LauncherModel.addItemToDatabase(Launcher.this, folderInfo, - LauncherSettings.Favorites.CONTAINER_DESKTOP, - screen, cellX, cellY, false); + LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screen, cellX, cellY, + false); sFolders.put(folderInfo.id, folderInfo); // Create the view - FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, - (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), - folderInfo, mIconCache); - mWorkspace.addInScreen(newFolder, screen, cellX, cellY, 1, 1, isWorkspaceLocked()); + FolderIcon newFolder = + FolderIcon.fromXml(R.layout.folder_icon, this, layout, folderInfo, mIconCache); + mWorkspace.addInScreen(newFolder, container, screen, cellX, cellY, 1, 1, + isWorkspaceLocked()); return newFolder; } @@ -1753,8 +1698,7 @@ public final class Launcher extends Activity ViewGroup parent = (ViewGroup) folder.getParent().getParent(); if (parent != null) { - CellLayout cl = (CellLayout) mWorkspace.getChildAt(folder.mInfo.screen); - FolderIcon fi = (FolderIcon) cl.getChildAt(folder.mInfo.cellX, folder.mInfo.cellY); + FolderIcon fi = (FolderIcon) mWorkspace.getViewForTag(folder.mInfo); shrinkAndFadeInFolderIcon(fi); mDragController.removeDropTarget((DropTarget)folder); } @@ -1774,7 +1718,7 @@ public final class Launcher extends Activity * Go through the and disconnect any of the callbacks in the drawables and the views or we * leak the previous Home screen on orientation change. */ - private void unbindWorkspaceItems() { + private void unbindWorkspaceAndHotseatItems() { LauncherModel.unbindWorkspaceItems(); } @@ -1995,16 +1939,6 @@ public final class Launcher extends Activity return false; } - switch (v.getId()) { - case R.id.all_apps_button: - if (mState != State.APPS_CUSTOMIZE) { - mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - showPreviews(v); - } - return true; - } - if (isWorkspaceLocked()) { return false; } @@ -2020,12 +1954,13 @@ public final class Launcher extends Activity return true; } + // The hotseat touch handling does not go through Workspace, and we always allow long press + // on hotseat items. final View itemUnderLongClick = longClickCellInfo.cell; - - if (mWorkspace.allowLongPress() && !mDragController.isDragging()) { + boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress(); + if (allowLongPress && !mDragController.isDragging()) { if (itemUnderLongClick == null) { // User long pressed on empty space - mWorkspace.setAllowLongPress(false); mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); addItems(); @@ -2041,137 +1976,26 @@ public final class Launcher extends Activity return true; } - @SuppressWarnings({"unchecked"}) - private void dismissPreview(final View v) { - final PopupWindow window = (PopupWindow) v.getTag(); - if (window != null) { - window.setOnDismissListener(new PopupWindow.OnDismissListener() { - public void onDismiss() { - ViewGroup group = (ViewGroup) v.getTag(R.id.workspace); - int count = group.getChildCount(); - for (int i = 0; i < count; i++) { - ((ImageView) group.getChildAt(i)).setImageDrawable(null); - } - ArrayList bitmaps = - (ArrayList) v.getTag(R.id.all_apps_button_cluster); - for (Bitmap bitmap : bitmaps) bitmap.recycle(); - - v.setTag(R.id.workspace, null); - v.setTag(R.id.all_apps_button_cluster, null); - window.setOnDismissListener(null); - } - }); - window.dismiss(); - } - v.setTag(null); + boolean isHotseatLayout(View layout) { + return mHotseat != null && layout != null && + (layout instanceof CellLayout) && (layout == mHotseat.getLayout()); } - - private void showPreviews(View anchor) { - showPreviews(anchor, 0, mWorkspace.getChildCount()); + Hotseat getHotseat() { + return mHotseat; } - private void showPreviews(final View anchor, int start, int end) { - final Resources resources = getResources(); - final Workspace workspace = mWorkspace; - - CellLayout cell = ((CellLayout) workspace.getChildAt(start)); - - float max = workspace.getChildCount(); - - final Rect r = new Rect(); - resources.getDrawable(R.drawable.preview_background).getPadding(r); - int extraW = (int) ((r.left + r.right) * max); - int extraH = r.top + r.bottom; - - int aW = cell.getWidth() - extraW; - float w = aW / max; - - int width = cell.getWidth(); - int height = cell.getHeight(); - int x = cell.getPaddingLeft(); - int y = cell.getPaddingTop(); - width -= (x + cell.getPaddingRight()); - height -= (y + cell.getPaddingBottom()); - - float scale = w / width; - - int count = end - start; - - final float sWidth = width * scale; - float sHeight = height * scale; - - LinearLayout preview = new LinearLayout(this); - - PreviewTouchHandler handler = new PreviewTouchHandler(anchor); - ArrayList bitmaps = new ArrayList(count); - - for (int i = start; i < end; i++) { - ImageView image = new ImageView(this); - cell = (CellLayout) workspace.getChildAt(i); - - final Bitmap bitmap = Bitmap.createBitmap((int) sWidth, (int) sHeight, - Bitmap.Config.ARGB_8888); - - final Canvas c = new Canvas(bitmap); - c.scale(scale, scale); - c.translate(-cell.getPaddingLeft(), -cell.getPaddingTop()); - cell.drawChildren(c); - - image.setBackgroundDrawable(resources.getDrawable(R.drawable.preview_background)); - image.setImageBitmap(bitmap); - image.setTag(i); - image.setOnClickListener(handler); - image.setOnFocusChangeListener(handler); - image.setFocusable(true); - if (i == mWorkspace.getCurrentPage()) image.requestFocus(); - - preview.addView(image, - LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - - bitmaps.add(bitmap); - } - - final PopupWindow p = new PopupWindow(this); - p.setContentView(preview); - p.setWidth((int) (sWidth * count + extraW)); - p.setHeight((int) (sHeight + extraH)); - p.setAnimationStyle(R.style.AnimationPreview); - p.setOutsideTouchable(true); - p.setFocusable(true); - p.setBackgroundDrawable(new ColorDrawable(0)); - p.showAsDropDown(anchor, 0, 0); - - p.setOnDismissListener(new PopupWindow.OnDismissListener() { - public void onDismiss() { - dismissPreview(anchor); - } - }); - - anchor.setTag(p); - anchor.setTag(R.id.workspace, preview); - anchor.setTag(R.id.all_apps_button_cluster, bitmaps); - } - - class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener { - private final View mAnchor; - - public PreviewTouchHandler(View anchor) { - mAnchor = anchor; - } - - public void onClick(View v) { - mWorkspace.snapToPage((Integer) v.getTag()); - v.post(this); - } - - public void run() { - dismissPreview(mAnchor); - } - - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - mWorkspace.snapToPage((Integer) v.getTag()); + /** + * Returns the CellLayout of the specified container at the specified screen. + */ + CellLayout getCellLayout(long container, int screen) { + if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + if (mHotseat != null) { + return mHotseat.getLayout(); + } else { + return null; } + } else { + return (CellLayout) mWorkspace.getChildAt(screen); } } @@ -2215,7 +2039,8 @@ public final class Launcher extends Activity private void showAddDialog() { resetAddInfo(); - mAddScreen = mWorkspace.getCurrentPage(); + mPendingAddInfo.container = LauncherSettings.Favorites.CONTAINER_DESKTOP; + mPendingAddInfo.screen = mWorkspace.getCurrentPage(); mWaitingForResult = true; showDialog(DIALOG_CREATE_SHORTCUT); } @@ -2594,29 +2419,29 @@ public final class Launcher extends Activity } /** - * Shows the dock/hotseat area. + * Shows the hotseat area. */ - void showDock(boolean animated) { + void showHotseat(boolean animated) { if (!LauncherApplication.isScreenLarge()) { if (animated) { int duration = mSearchDeleteBar.getTransitionInDuration(); - mButtonCluster.animate().alpha(1f).setDuration(duration); + mHotseat.animate().alpha(1f).setDuration(duration); } else { - mButtonCluster.setAlpha(1f); + mHotseat.setAlpha(1f); } } } /** - * Hides the dock/hotseat area. + * Hides the hotseat area. */ - void hideDock(boolean animated) { + void hideHotseat(boolean animated) { if (!LauncherApplication.isScreenLarge()) { if (animated) { int duration = mSearchDeleteBar.getTransitionOutDuration(); - mButtonCluster.animate().alpha(0f).setDuration(duration); + mHotseat.animate().alpha(0f).setDuration(duration); } else { - mButtonCluster.setAlpha(0f); + mHotseat.setAlpha(0f); } } } @@ -2627,9 +2452,9 @@ public final class Launcher extends Activity cameraZoomOut(State.APPS_CUSTOMIZE, animated, false); mAppsCustomizeTabHost.requestFocus(); - // Hide the search bar and dock + // Hide the search bar and hotseat mSearchDeleteBar.hideSearchBar(animated); - hideDock(animated); + hideHotseat(animated); // Change the state *after* we've called all the transition code mState = State.APPS_CUSTOMIZE; @@ -2686,12 +2511,14 @@ public final class Launcher extends Activity mWorkspace.setVisibility(View.VISIBLE); cameraZoomIn(State.APPS_CUSTOMIZE, animated, false); - // Show the search bar and dock + // Show the search bar and hotseat mSearchDeleteBar.showSearchBar(animated); - showDock(animated); + showHotseat(animated); // Set focus to the AppsCustomize button - findViewById(R.id.all_apps_button).requestFocus(); + if (mAllAppsButton != null) { + mAllAppsButton.requestFocus(); + } } } @@ -3024,21 +2851,12 @@ public final class Launcher extends Activity final CellLayout layoutParent = (CellLayout) workspace.getChildAt(i); layoutParent.removeAllViewsInLayout(); } - - if (DEBUG_USER_INTERFACE) { - android.widget.Button finishButton = new android.widget.Button(this); - finishButton.setText("Finish"); - workspace.addInScreen(finishButton, 1, 0, 0, 1, 1); - - finishButton.setOnClickListener(new android.widget.Button.OnClickListener() { - public void onClick(View v) { - finish(); - } - }); + if (mHotseat != null) { + mHotseat.resetLayout(); } // This wasn't being called before which resulted in a leak of AppWidgetHostViews - unbindWorkspaceItems(); + unbindWorkspaceAndHotseatItems(); } /** @@ -3047,30 +2865,27 @@ public final class Launcher extends Activity * Implementation of the method from LauncherModel.Callbacks. */ public void bindItems(ArrayList shortcuts, int start, int end) { - setLoadOnResume(); final Workspace workspace = mWorkspace; - for (int i=start; i= getChildCount()) { - Log.e(TAG, "The screen must be >= 0 and < " + getChildCount() - + " (was " + screen + "); skipping child"); - return; + void addInScreen(View child, long container, int screen, int x, int y, int spanX, int spanY, + boolean insert) { + 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"); + return; + } + } + + final CellLayout layout; + if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + layout = mLauncher.getHotseat().getLayout(); + + if (screen < 0) { + screen = mLauncher.getHotseat().getOrderInHotseat(x, y); + } 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); + } + } else { + layout = (CellLayout) getChildAt(screen); } - final CellLayout group = (CellLayout) getChildAt(screen); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); if (lp == null) { lp = new CellLayout.LayoutParams(x, y, spanX, spanY); @@ -467,9 +481,9 @@ public class Workspace extends SmoothPagedView } // Get the canonical child id to uniquely represent this view in this screen - int childId = LauncherModel.getCellLayoutChildId(-1, screen, x, y, spanX, spanY); + int childId = LauncherModel.getCellLayoutChildId(container, screen, x, y, spanX, spanY); boolean markCellsAsOccupied = !(child instanceof Folder); - if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) { + if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) { // TODO: This branch occurs when the workspace is adding views // outside of the defined grid // maybe we should be deleting these items from the LauncherModel? @@ -1959,7 +1973,7 @@ public class Workspace extends SmoothPagedView mDragInfo = cellInfo; - CellLayout current = (CellLayout) getChildAt(cellInfo.screen); + CellLayout current = getParentCellLayoutForView(cellInfo.cell); current.onDragChild(child); child.clearFocus(); @@ -2008,17 +2022,15 @@ public class Workspace extends SmoothPagedView b.recycle(); } - void addApplicationShortcut(ShortcutInfo info, int screen, int cellX, int cellY, - boolean insertAtFirst, int intersectX, int intersectY) { - final CellLayout cellLayout = (CellLayout) getChildAt(screen); - View view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo) info); + void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, int screen, + 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]; - cellLayout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); - addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst); - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, - cellXY[0], cellXY[1]); + target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY); + addInScreen(view, container, screen, cellXY[0], cellXY[1], 1, 1, insertAtFirst); + LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, cellXY[0], + cellXY[1]); } /** @@ -2051,7 +2063,6 @@ public class Workspace extends SmoothPagedView mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], spanX, spanY, mDragTargetLayout, mTargetCell); - if (willCreateUserFolder((ItemInfo) d.dragInfo, mDragTargetLayout, mTargetCell, true)) { return true; } @@ -2074,8 +2085,12 @@ public class Workspace extends SmoothPagedView boolean considerTimeout) { View dropOverView = target.getChildAt(targetCell[0], targetCell[1]); - boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == targetCell[0] && - mDragInfo.cellY == targetCell[1]) && mDragInfo.screen == indexOfChild(target); + boolean hasntMoved = false; + if (mDragInfo != null) { + CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell); + hasntMoved = (mDragInfo.cellX == targetCell[0] && + mDragInfo.cellY == targetCell[1]) && (cellParent == target); + } if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) { return false; @@ -2100,7 +2115,7 @@ public class Workspace extends SmoothPagedView return false; } - boolean createUserFolderIfNecessary(View newView, CellLayout target, + boolean createUserFolderIfNecessary(View newView, long container, CellLayout target, int[] targetCell, boolean external, DragView dragView, Runnable postAnimationRunnable) { View v = target.getChildAt(targetCell[0], targetCell[1]); boolean hasntMoved = mDragInfo != null @@ -2118,16 +2133,15 @@ public class Workspace extends SmoothPagedView ShortcutInfo destInfo = (ShortcutInfo) v.getTag(); // if the drag started here, we need to remove it from the workspace if (!external) { - int fromScreen = mDragInfo.screen; - CellLayout sourceLayout = (CellLayout) getChildAt(fromScreen); - sourceLayout.removeView(newView); + getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); } Rect folderLocation = new Rect(); float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation); target.removeView(v); - FolderIcon fi = mLauncher.addFolder(screen, targetCell[0], targetCell[1]); + FolderIcon fi = + mLauncher.addFolder(target, container, screen, targetCell[0], targetCell[1]); destInfo.cellX = -1; destInfo.cellY = -1; sourceInfo.cellX = -1; @@ -2150,9 +2164,7 @@ public class Workspace extends SmoothPagedView // if the drag started here, we need to remove it from the workspace if (!external) { - int fromScreen = mDragInfo.screen; - CellLayout sourceLayout = (CellLayout) getChildAt(fromScreen); - sourceLayout.removeView(newView); + getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); } return true; } @@ -2166,7 +2178,11 @@ public class Workspace extends SmoothPagedView // We want the point to be mapped to the dragTarget. if (mDragTargetLayout != null) { - mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); + if (mLauncher.isHotseatLayout(mDragTargetLayout)) { + mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter); + } else { + mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); + } } // When you are in customization mode and drag to a particular screen, make that the @@ -2186,11 +2202,23 @@ public class Workspace extends SmoothPagedView } else if (mDragInfo != null) { final View cell = mDragInfo.cell; - if (dropTargetLayout != null) { + boolean continueDrop = true; + if (mLauncher.isHotseatLayout(mDragTargetLayout) && d.dragInfo instanceof ItemInfo) { + ItemInfo info = (ItemInfo) d.dragInfo; + if (info.spanX > 1 || info.spanY > 1) { + continueDrop = false; + Toast.makeText(getContext(), R.string.invalid_hotseat_item, + Toast.LENGTH_SHORT).show(); + } + } + + if (continueDrop && dropTargetLayout != null) { // Move internally - final int screen = (mTargetCell[0] < 0) ? + long container = mLauncher.isHotseatLayout(dropTargetLayout) ? + LauncherSettings.Favorites.CONTAINER_HOTSEAT : + LauncherSettings.Favorites.CONTAINER_DESKTOP; + int screen = (mTargetCell[0] < 0) ? mDragInfo.screen : indexOfChild(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 @@ -2199,10 +2227,10 @@ public class Workspace extends SmoothPagedView mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell); // If the item being dropped is a shortcut and the nearest drop // cell also contains a shortcut, then create a folder with the two shortcuts. - boolean dropInscrollArea = mCurrentPage != screen; + boolean dropInscrollArea = mCurrentPage != screen && screen > -1; - if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout, - mTargetCell, false, d.dragView, null)) { + if (!dropInscrollArea && createUserFolderIfNecessary(cell, container, + dropTargetLayout, mTargetCell, false, d.dragView, null)) { return; } @@ -2220,25 +2248,26 @@ public class Workspace extends SmoothPagedView snapToPage(screen); } + if (mTargetCell[0] >= 0 && mTargetCell[1] >= 0) { if (screen != mDragInfo.screen) { // Reparent the view - ((CellLayout) getChildAt(mDragInfo.screen)).removeView(cell); - addInScreen(cell, screen, mTargetCell[0], mTargetCell[1], mDragInfo.spanX, - mDragInfo.spanY); + getParentCellLayoutForView(cell).removeView(cell); + addInScreen(cell, container, screen, mTargetCell[0], mTargetCell[1], + mDragInfo.spanX, mDragInfo.spanY); } - // update the item's position after drop final ItemInfo info = (ItemInfo) cell.getTag(); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); dropTargetLayout.onMove(cell, mTargetCell[0], mTargetCell[1]); lp.cellX = mTargetCell[0]; lp.cellY = mTargetCell[1]; - cell.setId(LauncherModel.getCellLayoutChildId(-1, mDragInfo.screen, + cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screen, mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY)); - if (cell instanceof LauncherAppWidgetHostView) { + if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT && + cell instanceof LauncherAppWidgetHostView) { final CellLayout cellLayout = dropTargetLayout; // We post this call so that the widget has a chance to be placed // in its final location @@ -2264,9 +2293,8 @@ public class Workspace extends SmoothPagedView } } - LauncherModel.moveItemInDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, - lp.cellX, lp.cellY); + LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, lp.cellX, + lp.cellY); } } @@ -2446,7 +2474,8 @@ public class Workspace extends SmoothPagedView final AppWidgetProviderInfo widgetInfo = widgets.get(0).widgetInfo; final PendingAddWidgetInfo createInfo = new PendingAddWidgetInfo(widgetInfo, mimeType, data); - mLauncher.addAppWidgetFromDrop(createInfo, mCurrentPage, null, pos); + mLauncher.addAppWidgetFromDrop(createInfo, + LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentPage, null, pos); } else { // Show the widget picker dialog if there is more than one widget // that can handle this data type @@ -2506,6 +2535,15 @@ public class Workspace extends SmoothPagedView cachedInverseMatrix.mapPoints(xy); } + /* + * Maps a point from the Workspace's coordinate system to another sibling view's. (Workspace + * covers the full screen) + */ + void mapPointFromSelfToSibling(View v, float[] xy) { + xy[0] = xy[0] - v.getLeft(); + xy[1] = xy[1] - v.getTop(); + } + /* * * Convert the 2D coordinate xy from this CellLayout's coordinate space to @@ -2581,7 +2619,7 @@ public class Workspace extends SmoothPagedView float smallestDistSoFar = Float.MAX_VALUE; for (int i = 0; i < screenCount; i++) { - CellLayout cl = (CellLayout)getChildAt(i); + CellLayout cl = (CellLayout) getChildAt(i); final float[] touchXy = mTempTouchCoordinates; touchXy[0] = originX + offsetX; @@ -2657,7 +2695,7 @@ public class Workspace extends SmoothPagedView if (mInScrollArea) return; if (mIsSwitchingState) return; - CellLayout layout; + CellLayout layout = null; ItemInfo item = (ItemInfo) d.dragInfo; // Ensure that we have proper spans for the item that we are dropping @@ -2690,7 +2728,17 @@ public class Workspace extends SmoothPagedView } } } else { - layout = getCurrentDropLayout(); + // Test to see if we are over the hotseat otherwise just use the current page + Rect r = new Rect(); + if (mLauncher.getHotseat() != null) { + mLauncher.getHotseat().getHitRect(r); + if (r.contains(d.x, d.y)) { + layout = mLauncher.getHotseat().getLayout(); + } + } + if (layout == null) { + layout = getCurrentDropLayout(); + } if (layout != mDragTargetLayout) { if (mDragTargetLayout != null) { mDragTargetLayout.setIsDragOverlapping(false); @@ -2710,7 +2758,11 @@ public class Workspace extends SmoothPagedView d.dragView, mDragViewVisualCenter); // We want the point to be mapped to the dragTarget. - mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); + if (mLauncher.isHotseatLayout(mDragTargetLayout)) { + mapPointFromSelfToSibling(mLauncher.getHotseat(), mDragViewVisualCenter); + } else { + mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null); + } ItemInfo info = (ItemInfo) d.dragInfo; mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], @@ -2845,8 +2897,12 @@ public class Workspace extends SmoothPagedView spanY = mDragInfo.spanY; } + final long container = mLauncher.isHotseatLayout(cellLayout) ? + LauncherSettings.Favorites.CONTAINER_HOTSEAT : + LauncherSettings.Favorites.CONTAINER_DESKTOP; final int screen = indexOfChild(cellLayout); - if (screen != mCurrentPage && mState != State.SPRING_LOADED) { + if (!mLauncher.isHotseatLayout(cellLayout) && screen != mCurrentPage + && mState != State.SPRING_LOADED) { snapToPage(screen); } @@ -2863,11 +2919,11 @@ public class Workspace extends SmoothPagedView switch (pendingInfo.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo, - screen, mTargetCell, null); + container, screen, mTargetCell, null); break; case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: mLauncher.processShortcutFromDrop(pendingInfo.componentName, - screen, mTargetCell, null); + container, screen, mTargetCell, null); break; default: throw new IllegalStateException("Unknown item type: " + @@ -2923,8 +2979,8 @@ public class Workspace extends SmoothPagedView mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY, cellLayout, mTargetCell); d.postAnimationRunnable = exitSpringLoadedRunnable; - if (createUserFolderIfNecessary(view, cellLayout, mTargetCell, true, d.dragView, - d.postAnimationRunnable)) { + if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, true, + d.dragView, d.postAnimationRunnable)) { return; } if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, d, true)) { @@ -2939,15 +2995,14 @@ public class Workspace extends SmoothPagedView } else { cellLayout.findCellForSpan(mTargetCell, 1, 1); } - addInScreen(view, indexOfChild(cellLayout), mTargetCell[0], - mTargetCell[1], info.spanX, info.spanY, insertAtFirst); + addInScreen(view, container, screen, mTargetCell[0], mTargetCell[1], info.spanX, + info.spanY, insertAtFirst); cellLayout.onDropChild(view); cellLayout.animateDrop(); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); cellLayout.getChildrenLayout().measureChild(view); - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, screen, + LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screen, lp.cellX, lp.cellY); if (d.dragView != null) { @@ -3016,8 +3071,7 @@ public class Workspace extends SmoothPagedView if (success) { if (target != this) { if (mDragInfo != null) { - final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); - cellLayout.removeView(mDragInfo.cell); + getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell); if (mDragInfo.cell instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) mDragInfo.cell); } @@ -3028,7 +3082,13 @@ public class Workspace extends SmoothPagedView // calling onDropCompleted(). We call it ourselves here, but maybe this should be // moved into DragController.cancelDrag(). doDragExit(null); - ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell); + CellLayout cellLayout; + if (mLauncher.isHotseatLayout(target)) { + cellLayout = mLauncher.getHotseat().getLayout(); + } else { + cellLayout = (CellLayout) getChildAt(mDragInfo.screen); + } + cellLayout.onDropChild(mDragInfo.cell); } mDragOutline = null; mDragInfo = null; @@ -3125,15 +3185,58 @@ public class Workspace extends SmoothPagedView mInScrollArea = false; } - public Folder getFolderForTag(Object tag) { - final int screenCount = getChildCount(); + /** + * Returns a specific CellLayout + */ + CellLayout getParentCellLayoutForView(View v) { + ArrayList layouts = getWorkspaceAndHotseatCellLayouts(); + for (CellLayout layout : layouts) { + if (layout.getChildrenLayout().indexOfChild(v) > -1) { + return layout; + } + } + return null; + } + + /** + * Returns a list of all the CellLayouts in the workspace. + */ + ArrayList getWorkspaceAndHotseatCellLayouts() { + ArrayList layouts = new ArrayList(); + int screenCount = getChildCount(); + for (int screen = 0; screen < screenCount; screen++) { + layouts.add(((CellLayout) getChildAt(screen))); + } + if (mLauncher.getHotseat() != null) { + layouts.add(mLauncher.getHotseat().getLayout()); + } + return layouts; + } + + /** + * We should only use this to search for specific children. Do not use this method to modify + * CellLayoutChildren directly. + */ + ArrayList getWorkspaceAndHotseatCellLayoutChildren() { + ArrayList childrenLayouts = new ArrayList(); + int screenCount = getChildCount(); for (int screen = 0; screen < screenCount; screen++) { - ViewGroup currentScreen = ((CellLayout) getChildAt(screen)).getChildrenLayout(); - int count = currentScreen.getChildCount(); + childrenLayouts.add(((CellLayout) getChildAt(screen)).getChildrenLayout()); + } + if (mLauncher.getHotseat() != null) { + childrenLayouts.add(mLauncher.getHotseat().getLayout().getChildrenLayout()); + } + return childrenLayouts; + } + + public Folder getFolderForTag(Object tag) { + ArrayList childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); + for (CellLayoutChildren layout: childrenLayouts) { + int count = layout.getChildCount(); for (int i = 0; i < count; i++) { - View child = currentScreen.getChildAt(i); + View child = layout.getChildAt(i); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { + if (child instanceof Folder) { Folder f = (Folder) child; if (f.getInfo() == tag && f.getInfo().opened) { return f; @@ -3145,12 +3248,11 @@ public class Workspace extends SmoothPagedView } public View getViewForTag(Object tag) { - int screenCount = getChildCount(); - for (int screen = 0; screen < screenCount; screen++) { - ViewGroup currentScreen = ((CellLayout) getChildAt(screen)).getChildrenLayout(); - int count = currentScreen.getChildCount(); + ArrayList childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); + for (CellLayoutChildren layout: childrenLayouts) { + int count = layout.getChildCount(); for (int i = 0; i < count; i++) { - View child = currentScreen.getChildAt(i); + View child = layout.getChildAt(i); if (child.getTag() == tag) { return child; } @@ -3160,11 +3262,8 @@ public class Workspace extends SmoothPagedView } void clearDropTargets() { - final int screenCount = getChildCount(); - - for (int i = 0; i < screenCount; i++) { - final CellLayout layoutParent = (CellLayout) getChildAt(i); - final ViewGroup layout = layoutParent.getChildrenLayout(); + ArrayList childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); + for (CellLayoutChildren layout: childrenLayouts) { int childCount = layout.getChildCount(); for (int j = 0; j < childCount; j++) { View v = layout.getChildAt(j); @@ -3185,8 +3284,8 @@ public class Workspace extends SmoothPagedView packageNames.add(apps.get(i).componentName.getPackageName()); } - for (int i = 0; i < screenCount; i++) { - final CellLayout layoutParent = (CellLayout) getChildAt(i); + ArrayList cellLayouts = getWorkspaceAndHotseatCellLayouts(); + for (final CellLayout layoutParent: cellLayouts) { final ViewGroup layout = layoutParent.getChildrenLayout(); // Avoid ANRs by treating each screen separately @@ -3273,9 +3372,8 @@ public class Workspace extends SmoothPagedView } void updateShortcuts(ArrayList apps) { - final int screenCount = getChildCount(); - for (int i = 0; i < screenCount; i++) { - final ViewGroup layout = ((CellLayout) getChildAt(i)).getChildrenLayout(); + ArrayList childrenLayouts = getWorkspaceAndHotseatCellLayoutChildren(); + for (CellLayoutChildren layout: childrenLayouts) { int childCount = layout.getChildCount(); for (int j = 0; j < childCount; j++) { final View view = layout.getChildAt(j); @@ -3307,7 +3405,7 @@ public class Workspace extends SmoothPagedView void moveToDefaultScreen(boolean animate) { if (isSmall() || mIsSwitchingState) { - mLauncher.showWorkspace(animate, (CellLayout)getChildAt(mDefaultPage)); + mLauncher.showWorkspace(animate, (CellLayout) getChildAt(mDefaultPage)); } else if (animate) { snapToPage(mDefaultPage); } else { -- cgit v1.2.3