private boolean mHoverPointClosesFolder = false;
private Rect mHitRect = new Rect();
- private int mWorkspaceIndex = -1;
- private int mQsbIndex = -1;
public static final int ANIMATION_END_DISAPPEAR = 0;
public static final int ANIMATION_END_FADE_OUT = 1;
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
private final Rect mInsets = new Rect();
+ private int mDragViewIndex;
+
/**
* Used to create a new DragLayer from XML.
*
}
private void updateChildIndices() {
- if (mLauncher != null) {
- mWorkspaceIndex = indexOfChild(mLauncher.getWorkspace());
- mQsbIndex = indexOfChild(mLauncher.getSearchBar());
+ mDragViewIndex = -1;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ if (getChildAt(i) instanceof DragView) {
+ mDragViewIndex = i;
+ }
}
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
- // TODO: We have turned off this custom drawing order because it now effects touch
- // dispatch order. We need to sort that issue out and then decide how to go about this.
- if (true || LauncherAppState.isScreenLandscape(getContext()) ||
- mWorkspaceIndex == -1 || mQsbIndex == -1 ||
- mLauncher.getWorkspace().isDrawingBackgroundGradient()) {
+ if (mDragViewIndex == -1) {
return i;
- }
-
- // This ensures that the workspace is drawn above the hotseat and qsb,
- // except when the workspace is drawing a background gradient, in which
- // case we want the workspace to stay behind these elements.
- if (i == mQsbIndex) {
- return mWorkspaceIndex;
- } else if (i == mWorkspaceIndex) {
- return mQsbIndex;
- } else {
+ } else if (i == mDragViewIndex) {
+ return getChildCount()-1;
+ } else if (i < mDragViewIndex) {
return i;
+ } else {
+ // i > mDragViewIndex
+ return i-1;
}
}
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.support.v4.widget.AutoScrollHelper;
import android.text.InputType;
static final int STATE_ANIMATING = 1;
static final int STATE_OPEN = 2;
+ private static final int CLOSE_FOLDER_DELAY_MS = 150;
+
private int mExpandDuration;
protected CellLayout mContent;
private ScrollView mScrollView;
private int mMaxCountY;
private int mMaxNumItems;
private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
- private Drawable mIconDrawable;
boolean mItemsInvalidated = false;
private ShortcutInfo mCurrentDragInfo;
private View mCurrentDragView;
+ private boolean mIsExternalDrag;
boolean mSuppressOnAdd = false;
private int[] mTargetCell = new int[2];
private int[] mPreviousTargetCell = new int[2];
mLauncher.getWorkspace().onDragStartedWithItem(v);
mLauncher.getWorkspace().beginDragShared(v, this);
- mIconDrawable = ((TextView) v).getCompoundDrawables()[1];
mCurrentDragInfo = item;
mEmptyCell[0] = item.cellX;
return mFolderName;
}
- public Drawable getDragDrawable() {
- return mIconDrawable;
- }
-
/**
* We need to handle touch events to prevent them from falling through to the workspace below.
*/
int count = 0;
for (int i = 0; i < children.size(); i++) {
ShortcutInfo child = (ShortcutInfo) children.get(i);
- if (!createAndAddShortcut(child)) {
+ if (createAndAddShortcut(child) == null) {
overflow.add(child);
} else {
count++;
public void onAnimationEnd(Animator animation) {
mState = STATE_OPEN;
setLayerType(LAYER_TYPE_NONE, null);
- Cling cling = mLauncher.getLauncherClings().showFoldersCling();
- if (cling != null) {
- cling.bringScrimToFront();
- bringToFront();
- cling.bringToFront();
+
+ // Only show cling if we are not in the middle of a drag - this would be quite jarring.
+ if (!mDragController.isDragging()) {
+ Cling cling = mLauncher.getLauncherClings().showFoldersCling();
+ if (cling != null) {
+ cling.bringScrimToFront();
+ bringToFront();
+ cling.bringToFront();
+ }
}
setFocusOnFirstChild();
}
oa.setDuration(mExpandDuration);
setLayerType(LAYER_TYPE_HARDWARE, null);
oa.start();
+
+ // Make sure the folder picks up the last drag move even if the finger doesn't move.
+ if (mDragController.isDragging()) {
+ mDragController.forceTouchMove();
+ }
+ }
+
+ public void beginExternalDrag(ShortcutInfo item) {
+ setupContentForNumItems(getItemCount() + 1);
+ findAndSetEmptyCells(item);
+
+ mCurrentDragInfo = item;
+ mEmptyCell[0] = item.cellX;
+ mEmptyCell[1] = item.cellY;
+ mIsExternalDrag = true;
+
+ mDragInProgress = true;
}
private void sendCustomAccessibilityEvent(int type, String text) {
}
}
- protected boolean createAndAddShortcut(ShortcutInfo item) {
+ protected View createAndAddShortcut(ShortcutInfo item) {
final BubbleTextView textView =
(BubbleTextView) mInflater.inflate(R.layout.application, this, false);
textView.setCompoundDrawables(null,
// This shouldn't happen, log it.
Log.e(TAG, "Folder order not properly persisted during bind");
if (!findAndSetEmptyCells(item)) {
- return false;
+ return null;
}
}
boolean insert = false;
textView.setOnKeyListener(new FolderKeyEventListener());
mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
- return true;
+ return textView;
}
public void onDragEnter(DragObject d) {
mCurrentDragView = null;
mSuppressOnAdd = false;
mRearrangeOnClose = true;
+ mIsExternalDrag = false;
}
public void onDragExit(DragObject d) {
success && (!beingCalledAfterUninstall || mUninstallSuccessful);
if (successfulDrop) {
- if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon) {
+ if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon && target != this) {
replaceFolderWithFinalItem();
}
} else {
}
public void onDrop(DragObject d) {
- ShortcutInfo item;
- if (d.dragInfo instanceof AppInfo) {
- // Came from all apps -- make a copy
- item = ((AppInfo) d.dragInfo).makeShortcut();
- item.spanX = 1;
- item.spanY = 1;
- } else {
- item = (ShortcutInfo) d.dragInfo;
+ Runnable cleanUpRunnable = null;
+
+ // If we are coming from All Apps space, we need to remove the extra empty screen (which is
+ // normally done in Workspace#onDropExternal, as well zoom back in and close the folder.
+ if (d.dragSource != mLauncher.getWorkspace() && !(d.dragSource instanceof Folder)) {
+ cleanUpRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mLauncher.getWorkspace().removeExtraEmptyScreen(false, new Runnable() {
+ @Override
+ public void run() {
+ mLauncher.closeFolder();
+ mLauncher.exitSpringLoadedDragModeDelayed(true,
+ Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT_FOLDER_CLOSE,
+ null);
+ }
+ }, CLOSE_FOLDER_DELAY_MS, false);
+ }
+ };
}
- // Dragged from self onto self, currently this is the only path possible, however
- // we keep this as a distinct code path.
- if (item == mCurrentDragInfo) {
- ShortcutInfo si = (ShortcutInfo) mCurrentDragView.getTag();
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mCurrentDragView.getLayoutParams();
+
+ View currentDragView;
+ ShortcutInfo si = mCurrentDragInfo;
+ if (mIsExternalDrag) {
+ si.cellX = mEmptyCell[0];
+ si.cellY = mEmptyCell[1];
+ currentDragView = createAndAddShortcut(si);
+ } else {
+ currentDragView = mCurrentDragView;
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) currentDragView.getLayoutParams();
si.cellX = lp.cellX = mEmptyCell[0];
si.cellX = lp.cellY = mEmptyCell[1];
- mContent.addViewToCellLayout(mCurrentDragView, -1, (int)item.id, lp, true);
- if (d.dragView.hasDrawn()) {
- mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, mCurrentDragView);
- } else {
- d.deferDragViewCleanupPostAnimation = false;
- mCurrentDragView.setVisibility(VISIBLE);
+ mContent.addViewToCellLayout(currentDragView, -1, (int) si.id, lp, true);
+ }
+
+ if (d.dragView.hasDrawn()) {
+
+ // Temporarily reset the scale such that the animation target gets calculated correctly.
+ float scaleX = getScaleX();
+ float scaleY = getScaleY();
+ setScaleX(1.0f);
+ setScaleY(1.0f);
+ mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, currentDragView,
+ cleanUpRunnable, null);
+ setScaleX(scaleX);
+ setScaleY(scaleY);
+ } else {
+ d.deferDragViewCleanupPostAnimation = false;
+ currentDragView.setVisibility(VISIBLE);
+ }
+ mItemsInvalidated = true;
+ setupContentDimensions(getItemCount());
+
+ // Actually move the item in the database if it was an external drag.
+ if (mIsExternalDrag) {
+ LauncherModel.addOrMoveItemInDatabase(
+ mLauncher, si, mInfo.id, 0, si.cellX, si.cellY);
+
+ // We only need to update the locations if it doesn't get handled in #onDropCompleted.
+ if (d.dragSource != this) {
+ updateItemLocationsInDatabaseBatch();
}
- mItemsInvalidated = true;
- setupContentDimensions(getItemCount());
- mSuppressOnAdd = true;
+ mIsExternalDrag = false;
}
- mInfo.add(item);
+
+ // Temporarily suppress the listener, as we did all the work already here.
+ mSuppressOnAdd = true;
+ mInfo.add(si);
+ mSuppressOnAdd = false;
}
// This is used so the item doesn't immediately appear in the folder when added. In one case
// Flag as to whether or not to draw an outer ring. Currently none is designed.
public static final boolean HAS_OUTER_RING = true;
+ // Flag whether the folder should open itself when an item is dragged over is enabled.
+ public static final boolean SPRING_LOADING_ENABLED = true;
+
// The degree to which the item in the back of the stack is scaled [0...1]
// (0 means it's not scaled at all, 1 means it's scaled to nothing)
private static final float PERSPECTIVE_SCALE_FACTOR = 0.35f;
+ // Delay when drag enters until the folder opens, in miliseconds.
+ private static final int ON_OPEN_DELAY = 800;
+
public static Drawable sSharedFolderLeaveBehind = null;
private ImageView mPreviewBackground;
private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
+ private Alarm mOpenAlarm = new Alarm();
+ private ItemInfo mDragInfo;
+
public FolderIcon(Context context, AttributeSet attrs) {
super(context, attrs);
init();
mFolderRingAnimator.setCellLayout(layout);
mFolderRingAnimator.animateToAcceptState();
layout.showFolderAccept(mFolderRingAnimator);
+ mOpenAlarm.setOnAlarmListener(mOnOpenListener);
+ if (SPRING_LOADING_ENABLED) {
+ mOpenAlarm.setAlarm(ON_OPEN_DELAY);
+ }
+ mDragInfo = (ItemInfo) dragInfo;
}
public void onDragOver(Object dragInfo) {
}
+ OnAlarmListener mOnOpenListener = new OnAlarmListener() {
+ public void onAlarm(Alarm alarm) {
+ ShortcutInfo item;
+ if (mDragInfo instanceof AppInfo) {
+ // Came from all apps -- make a copy.
+ item = ((AppInfo) mDragInfo).makeShortcut();
+ item.spanX = 1;
+ item.spanY = 1;
+ } else {
+ item = (ShortcutInfo) mDragInfo;
+ }
+ mFolder.beginExternalDrag(item);
+ mLauncher.openFolder(FolderIcon.this);
+ }
+ };
+
public void performCreateAnimation(final ShortcutInfo destInfo, final View destView,
final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect,
float scaleRelativeToDragLayer, Runnable postAnimationRunnable) {
public void onDragExit() {
mFolderRingAnimator.animateToNaturalState();
+ mOpenAlarm.cancelAlarm();
}
private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect,