1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.folder; 18 19 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW; 20 import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION; 21 22 import android.animation.Animator; 23 import android.animation.ObjectAnimator; 24 import android.content.Context; 25 import android.graphics.Canvas; 26 import android.graphics.Point; 27 import android.graphics.Rect; 28 import android.graphics.Region; 29 import android.graphics.drawable.Drawable; 30 import android.os.Parcelable; 31 import android.support.annotation.NonNull; 32 import android.util.AttributeSet; 33 import android.util.Property; 34 import android.view.LayoutInflater; 35 import android.view.MotionEvent; 36 import android.view.View; 37 import android.view.ViewConfiguration; 38 import android.view.ViewGroup; 39 import android.widget.FrameLayout; 40 41 import com.android.launcher3.Alarm; 42 import com.android.launcher3.AppInfo; 43 import com.android.launcher3.BubbleTextView; 44 import com.android.launcher3.CellLayout; 45 import com.android.launcher3.CheckLongPressHelper; 46 import com.android.launcher3.DeviceProfile; 47 import com.android.launcher3.DropTarget.DragObject; 48 import com.android.launcher3.FolderInfo; 49 import com.android.launcher3.FolderInfo.FolderListener; 50 import com.android.launcher3.ItemInfo; 51 import com.android.launcher3.Launcher; 52 import com.android.launcher3.LauncherSettings; 53 import com.android.launcher3.OnAlarmListener; 54 import com.android.launcher3.R; 55 import com.android.launcher3.ShortcutInfo; 56 import com.android.launcher3.SimpleOnStylusPressListener; 57 import com.android.launcher3.StylusEventHelper; 58 import com.android.launcher3.Utilities; 59 import com.android.launcher3.Workspace; 60 import com.android.launcher3.anim.Interpolators; 61 import com.android.launcher3.badge.BadgeRenderer; 62 import com.android.launcher3.badge.FolderBadgeInfo; 63 import com.android.launcher3.dragndrop.BaseItemDragListener; 64 import com.android.launcher3.dragndrop.DragLayer; 65 import com.android.launcher3.dragndrop.DragView; 66 import com.android.launcher3.touch.ItemClickHandler; 67 import com.android.launcher3.util.Thunk; 68 import com.android.launcher3.widget.PendingAddShortcutInfo; 69 70 import java.util.ArrayList; 71 import java.util.List; 72 73 /** 74 * An icon that can appear on in the workspace representing an {@link Folder}. 75 */ 76 public class FolderIcon extends FrameLayout implements FolderListener { 77 @Thunk Launcher mLauncher; 78 @Thunk Folder mFolder; 79 private FolderInfo mInfo; 80 @Thunk static boolean sStaticValuesDirty = true; 81 82 private CheckLongPressHelper mLongPressHelper; 83 private StylusEventHelper mStylusEventHelper; 84 85 static final int DROP_IN_ANIMATION_DURATION = 400; 86 87 // Flag whether the folder should open itself when an item is dragged over is enabled. 88 public static final boolean SPRING_LOADING_ENABLED = true; 89 90 // Delay when drag enters until the folder opens, in miliseconds. 91 private static final int ON_OPEN_DELAY = 800; 92 93 @Thunk BubbleTextView mFolderName; 94 95 PreviewBackground mBackground = new PreviewBackground(); 96 private boolean mBackgroundIsVisible = true; 97 98 FolderIconPreviewVerifier mPreviewVerifier; 99 ClippedFolderIconLayoutRule mPreviewLayoutRule; 100 private PreviewItemManager mPreviewItemManager; 101 private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0); 102 private List<BubbleTextView> mCurrentPreviewItems = new ArrayList<>(); 103 104 boolean mAnimating = false; 105 private Rect mTempBounds = new Rect(); 106 107 private float mSlop; 108 109 private Alarm mOpenAlarm = new Alarm(); 110 111 private FolderBadgeInfo mBadgeInfo = new FolderBadgeInfo(); 112 private BadgeRenderer mBadgeRenderer; 113 private float mBadgeScale; 114 private Point mTempSpaceForBadgeOffset = new Point(); 115 116 private static final Property<FolderIcon, Float> BADGE_SCALE_PROPERTY 117 = new Property<FolderIcon, Float>(Float.TYPE, "badgeScale") { 118 @Override 119 public Float get(FolderIcon folderIcon) { 120 return folderIcon.mBadgeScale; 121 } 122 123 @Override 124 public void set(FolderIcon folderIcon, Float value) { 125 folderIcon.mBadgeScale = value; 126 folderIcon.invalidate(); 127 } 128 }; 129 130 public FolderIcon(Context context, AttributeSet attrs) { 131 super(context, attrs); 132 init(); 133 } 134 135 public FolderIcon(Context context) { 136 super(context); 137 init(); 138 } 139 140 private void init() { 141 mLongPressHelper = new CheckLongPressHelper(this); 142 mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this); 143 mPreviewLayoutRule = new ClippedFolderIconLayoutRule(); 144 mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 145 mPreviewItemManager = new PreviewItemManager(this); 146 } 147 148 public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group, 149 FolderInfo folderInfo) { 150 @SuppressWarnings("all") // suppress dead code warning 151 final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION; 152 if (error) { 153 throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " + 154 "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " + 155 "is dependent on this"); 156 } 157 158 DeviceProfile grid = launcher.getDeviceProfile(); 159 FolderIcon icon = (FolderIcon) LayoutInflater.from(group.getContext()) 160 .inflate(resId, group, false); 161 162 icon.setClipToPadding(false); 163 icon.mFolderName = icon.findViewById(R.id.folder_icon_name); 164 icon.mFolderName.setText(folderInfo.title); 165 icon.mFolderName.setCompoundDrawablePadding(0); 166 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams(); 167 lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx; 168 169 icon.setTag(folderInfo); 170 icon.setOnClickListener(ItemClickHandler.INSTANCE); 171 icon.mInfo = folderInfo; 172 icon.mLauncher = launcher; 173 icon.mBadgeRenderer = launcher.getDeviceProfile().mBadgeRenderer; 174 icon.setContentDescription(launcher.getString(R.string.folder_name_format, folderInfo.title)); 175 Folder folder = Folder.fromXml(launcher); 176 folder.setDragController(launcher.getDragController()); 177 folder.setFolderIcon(icon); 178 folder.bind(folderInfo); 179 icon.setFolder(folder); 180 icon.setAccessibilityDelegate(launcher.getAccessibilityDelegate()); 181 182 folderInfo.addListener(icon); 183 184 icon.setOnFocusChangeListener(launcher.mFocusHandler); 185 return icon; 186 } 187 188 @Override 189 protected Parcelable onSaveInstanceState() { 190 sStaticValuesDirty = true; 191 return super.onSaveInstanceState(); 192 } 193 194 public Folder getFolder() { 195 return mFolder; 196 } 197 198 private void setFolder(Folder folder) { 199 mFolder = folder; 200 mPreviewVerifier = new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv); 201 updatePreviewItems(false); 202 } 203 204 private boolean willAcceptItem(ItemInfo item) { 205 final int itemType = item.itemType; 206 return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || 207 itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT || 208 itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) && 209 item != mInfo && !mFolder.isOpen()); 210 } 211 212 public boolean acceptDrop(ItemInfo dragInfo) { 213 return !mFolder.isDestroyed() && willAcceptItem(dragInfo); 214 } 215 216 public void addItem(ShortcutInfo item) { 217 addItem(item, true); 218 } 219 220 public void addItem(ShortcutInfo item, boolean animate) { 221 mInfo.add(item, animate); 222 } 223 224 public void removeItem(ShortcutInfo item, boolean animate) { 225 mInfo.remove(item, animate); 226 } 227 228 public void onDragEnter(ItemInfo dragInfo) { 229 if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return; 230 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); 231 CellLayout cl = (CellLayout) getParent().getParent(); 232 233 mBackground.animateToAccept(cl, lp.cellX, lp.cellY); 234 mOpenAlarm.setOnAlarmListener(mOnOpenListener); 235 if (SPRING_LOADING_ENABLED && 236 ((dragInfo instanceof AppInfo) 237 || (dragInfo instanceof ShortcutInfo) 238 || (dragInfo instanceof PendingAddShortcutInfo))) { 239 mOpenAlarm.setAlarm(ON_OPEN_DELAY); 240 } 241 } 242 243 OnAlarmListener mOnOpenListener = new OnAlarmListener() { 244 public void onAlarm(Alarm alarm) { 245 mFolder.beginExternalDrag(); 246 mFolder.animateOpen(); 247 } 248 }; 249 250 public Drawable prepareCreateAnimation(final View destView) { 251 return mPreviewItemManager.prepareCreateAnimation(destView); 252 } 253 254 public void performCreateAnimation(final ShortcutInfo destInfo, final View destView, 255 final ShortcutInfo srcInfo, final DragView srcView, Rect dstRect, 256 float scaleRelativeToDragLayer) { 257 prepareCreateAnimation(destView); 258 addItem(destInfo); 259 // This will animate the first item from it's position as an icon into its 260 // position as the first item in the preview 261 mPreviewItemManager.createFirstItemAnimation(false /* reverse */, null) 262 .start(); 263 264 // This will animate the dragView (srcView) into the new folder 265 onDrop(srcInfo, srcView, dstRect, scaleRelativeToDragLayer, 1, 266 false /* itemReturnedOnFailedDrop */); 267 } 268 269 public void performDestroyAnimation(Runnable onCompleteRunnable) { 270 // This will animate the final item in the preview to be full size. 271 mPreviewItemManager.createFirstItemAnimation(true /* reverse */, onCompleteRunnable) 272 .start(); 273 } 274 275 public void onDragExit() { 276 mBackground.animateToRest(); 277 mOpenAlarm.cancelAlarm(); 278 } 279 280 private void onDrop(final ShortcutInfo item, DragView animateView, Rect finalRect, 281 float scaleRelativeToDragLayer, int index, 282 boolean itemReturnedOnFailedDrop) { 283 item.cellX = -1; 284 item.cellY = -1; 285 286 // Typically, the animateView corresponds to the DragView; however, if this is being done 287 // after a configuration activity (ie. for a Shortcut being dragged from AllApps) we 288 // will not have a view to animate 289 if (animateView != null) { 290 DragLayer dragLayer = mLauncher.getDragLayer(); 291 Rect from = new Rect(); 292 dragLayer.getViewRectRelativeToSelf(animateView, from); 293 Rect to = finalRect; 294 if (to == null) { 295 to = new Rect(); 296 Workspace workspace = mLauncher.getWorkspace(); 297 // Set cellLayout and this to it's final state to compute final animation locations 298 workspace.setFinalTransitionTransform(); 299 float scaleX = getScaleX(); 300 float scaleY = getScaleY(); 301 setScaleX(1.0f); 302 setScaleY(1.0f); 303 scaleRelativeToDragLayer = dragLayer.getDescendantRectRelativeToSelf(this, to); 304 // Finished computing final animation locations, restore current state 305 setScaleX(scaleX); 306 setScaleY(scaleY); 307 workspace.resetTransitionTransform(); 308 } 309 310 int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1); 311 boolean itemAdded = false; 312 if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) { 313 List<BubbleTextView> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems); 314 addItem(item, false); 315 mCurrentPreviewItems.clear(); 316 mCurrentPreviewItems.addAll(getPreviewItems()); 317 318 if (!oldPreviewItems.equals(mCurrentPreviewItems)) { 319 for (int i = 0; i < mCurrentPreviewItems.size(); ++i) { 320 if (mCurrentPreviewItems.get(i).getTag().equals(item)) { 321 // If the item dropped is going to be in the preview, we update the 322 // index here to reflect its position in the preview. 323 index = i; 324 } 325 } 326 327 mPreviewItemManager.hidePreviewItem(index, true); 328 mPreviewItemManager.onDrop(oldPreviewItems, mCurrentPreviewItems, item); 329 itemAdded = true; 330 } else { 331 removeItem(item, false); 332 } 333 } 334 335 if (!itemAdded) { 336 addItem(item); 337 } 338 339 int[] center = new int[2]; 340 float scale = getLocalCenterForIndex(index, numItemsInPreview, center); 341 center[0] = (int) Math.round(scaleRelativeToDragLayer * center[0]); 342 center[1] = (int) Math.round(scaleRelativeToDragLayer * center[1]); 343 344 to.offset(center[0] - animateView.getMeasuredWidth() / 2, 345 center[1] - animateView.getMeasuredHeight() / 2); 346 347 float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f; 348 349 float finalScale = scale * scaleRelativeToDragLayer; 350 dragLayer.animateView(animateView, from, to, finalAlpha, 351 1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION, 352 Interpolators.DEACCEL_2, Interpolators.ACCEL_2, 353 null, DragLayer.ANIMATION_END_DISAPPEAR, null); 354 355 mFolder.hideItem(item); 356 357 if (!itemAdded) mPreviewItemManager.hidePreviewItem(index, true); 358 final int finalIndex = index; 359 postDelayed(new Runnable() { 360 public void run() { 361 mPreviewItemManager.hidePreviewItem(finalIndex, false); 362 mFolder.showItem(item); 363 invalidate(); 364 } 365 }, DROP_IN_ANIMATION_DURATION); 366 } else { 367 addItem(item); 368 } 369 } 370 371 public void onDrop(DragObject d, boolean itemReturnedOnFailedDrop) { 372 ShortcutInfo item; 373 if (d.dragInfo instanceof AppInfo) { 374 // Came from all apps -- make a copy 375 item = ((AppInfo) d.dragInfo).makeShortcut(); 376 } else if (d.dragSource instanceof BaseItemDragListener){ 377 // Came from a different window -- make a copy 378 item = new ShortcutInfo((ShortcutInfo) d.dragInfo); 379 } else { 380 item = (ShortcutInfo) d.dragInfo; 381 } 382 mFolder.notifyDrop(); 383 onDrop(item, d.dragView, null, 1.0f, mInfo.contents.size(), 384 itemReturnedOnFailedDrop); 385 } 386 387 public void setBadgeInfo(FolderBadgeInfo badgeInfo) { 388 updateBadgeScale(mBadgeInfo.hasBadge(), badgeInfo.hasBadge()); 389 mBadgeInfo = badgeInfo; 390 } 391 392 public ClippedFolderIconLayoutRule getLayoutRule() { 393 return mPreviewLayoutRule; 394 } 395 396 /** 397 * Sets mBadgeScale to 1 or 0, animating if wasBadged or isBadged is false 398 * (the badge is being added or removed). 399 */ 400 private void updateBadgeScale(boolean wasBadged, boolean isBadged) { 401 float newBadgeScale = isBadged ? 1f : 0f; 402 // Animate when a badge is first added or when it is removed. 403 if ((wasBadged ^ isBadged) && isShown()) { 404 createBadgeScaleAnimator(newBadgeScale).start(); 405 } else { 406 mBadgeScale = newBadgeScale; 407 invalidate(); 408 } 409 } 410 411 public Animator createBadgeScaleAnimator(float... badgeScales) { 412 return ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, badgeScales); 413 } 414 415 public boolean hasBadge() { 416 return mBadgeInfo != null && mBadgeInfo.hasBadge(); 417 } 418 419 private float getLocalCenterForIndex(int index, int curNumItems, int[] center) { 420 mTmpParams = mPreviewItemManager.computePreviewItemDrawingParams( 421 Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index), curNumItems, mTmpParams); 422 423 mTmpParams.transX += mBackground.basePreviewOffsetX; 424 mTmpParams.transY += mBackground.basePreviewOffsetY; 425 426 float intrinsicIconSize = mPreviewItemManager.getIntrinsicIconSize(); 427 float offsetX = mTmpParams.transX + (mTmpParams.scale * intrinsicIconSize) / 2; 428 float offsetY = mTmpParams.transY + (mTmpParams.scale * intrinsicIconSize) / 2; 429 430 center[0] = Math.round(offsetX); 431 center[1] = Math.round(offsetY); 432 return mTmpParams.scale; 433 } 434 435 public void setFolderBackground(PreviewBackground bg) { 436 mBackground = bg; 437 mBackground.setInvalidateDelegate(this); 438 } 439 440 public void setBackgroundVisible(boolean visible) { 441 mBackgroundIsVisible = visible; 442 invalidate(); 443 } 444 445 public PreviewBackground getFolderBackground() { 446 return mBackground; 447 } 448 449 public PreviewItemManager getPreviewItemManager() { 450 return mPreviewItemManager; 451 } 452 453 @Override 454 protected void dispatchDraw(Canvas canvas) { 455 super.dispatchDraw(canvas); 456 457 if (!mBackgroundIsVisible) return; 458 459 mPreviewItemManager.recomputePreviewDrawingParams(); 460 461 if (!mBackground.drawingDelegated()) { 462 mBackground.drawBackground(canvas); 463 } 464 465 if (mFolder == null) return; 466 if (mFolder.getItemCount() == 0 && !mAnimating) return; 467 468 final int saveCount; 469 470 if (canvas.isHardwareAccelerated()) { 471 saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null); 472 } else { 473 saveCount = canvas.save(); 474 canvas.clipPath(mBackground.getClipPath()); 475 } 476 477 mPreviewItemManager.draw(canvas); 478 479 if (canvas.isHardwareAccelerated()) { 480 mBackground.clipCanvasHardware(canvas); 481 } 482 canvas.restoreToCount(saveCount); 483 484 if (!mBackground.drawingDelegated()) { 485 mBackground.drawBackgroundStroke(canvas); 486 } 487 488 drawBadge(canvas); 489 } 490 491 public void drawBadge(Canvas canvas) { 492 if ((mBadgeInfo != null && mBadgeInfo.hasBadge()) || mBadgeScale > 0) { 493 int offsetX = mBackground.getOffsetX(); 494 int offsetY = mBackground.getOffsetY(); 495 int previewSize = (int) (mBackground.previewSize * mBackground.mScale); 496 mTempBounds.set(offsetX, offsetY, offsetX + previewSize, offsetY + previewSize); 497 498 // If we are animating to the accepting state, animate the badge out. 499 float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress()); 500 mTempSpaceForBadgeOffset.set(getWidth() - mTempBounds.right, mTempBounds.top); 501 mBadgeRenderer.draw(canvas, mBackground.getBadgeColor(), mTempBounds, 502 badgeScale, mTempSpaceForBadgeOffset); 503 } 504 } 505 506 public void setTextVisible(boolean visible) { 507 if (visible) { 508 mFolderName.setVisibility(VISIBLE); 509 } else { 510 mFolderName.setVisibility(INVISIBLE); 511 } 512 } 513 514 public boolean getTextVisible() { 515 return mFolderName.getVisibility() == VISIBLE; 516 } 517 518 /** 519 * Returns the list of preview items displayed in the icon. 520 */ 521 public List<BubbleTextView> getPreviewItems() { 522 return getPreviewItemsOnPage(0); 523 } 524 525 /** 526 * Returns the list of "preview items" on {@param page}. 527 */ 528 public List<BubbleTextView> getPreviewItemsOnPage(int page) { 529 mPreviewVerifier.setFolderInfo(mFolder.getInfo()); 530 531 List<BubbleTextView> itemsToDisplay = new ArrayList<>(); 532 List<BubbleTextView> itemsOnPage = mFolder.getItemsOnPage(page); 533 int numItems = itemsOnPage.size(); 534 for (int rank = 0; rank < numItems; ++rank) { 535 if (mPreviewVerifier.isItemInPreview(page, rank)) { 536 itemsToDisplay.add(itemsOnPage.get(rank)); 537 } 538 539 if (itemsToDisplay.size() == MAX_NUM_ITEMS_IN_PREVIEW) { 540 break; 541 } 542 } 543 return itemsToDisplay; 544 } 545 546 @Override 547 protected boolean verifyDrawable(@NonNull Drawable who) { 548 return mPreviewItemManager.verifyDrawable(who) || super.verifyDrawable(who); 549 } 550 551 @Override 552 public void onItemsChanged(boolean animate) { 553 updatePreviewItems(animate); 554 invalidate(); 555 requestLayout(); 556 } 557 558 private void updatePreviewItems(boolean animate) { 559 mPreviewItemManager.updatePreviewItems(animate); 560 mCurrentPreviewItems.clear(); 561 mCurrentPreviewItems.addAll(getPreviewItems()); 562 } 563 564 @Override 565 public void prepareAutoUpdate() { 566 } 567 568 @Override 569 public void onAdd(ShortcutInfo item, int rank) { 570 boolean wasBadged = mBadgeInfo.hasBadge(); 571 mBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(item)); 572 boolean isBadged = mBadgeInfo.hasBadge(); 573 updateBadgeScale(wasBadged, isBadged); 574 invalidate(); 575 requestLayout(); 576 } 577 578 @Override 579 public void onRemove(ShortcutInfo item) { 580 boolean wasBadged = mBadgeInfo.hasBadge(); 581 mBadgeInfo.subtractBadgeInfo(mLauncher.getBadgeInfoForItem(item)); 582 boolean isBadged = mBadgeInfo.hasBadge(); 583 updateBadgeScale(wasBadged, isBadged); 584 invalidate(); 585 requestLayout(); 586 } 587 588 @Override 589 public void onTitleChanged(CharSequence title) { 590 mFolderName.setText(title); 591 setContentDescription(getContext().getString(R.string.folder_name_format, title)); 592 } 593 594 @Override 595 public boolean onTouchEvent(MotionEvent event) { 596 // Call the superclass onTouchEvent first, because sometimes it changes the state to 597 // isPressed() on an ACTION_UP 598 boolean result = super.onTouchEvent(event); 599 600 // Check for a stylus button press, if it occurs cancel any long press checks. 601 if (mStylusEventHelper.onMotionEvent(event)) { 602 mLongPressHelper.cancelLongPress(); 603 return true; 604 } 605 606 switch (event.getAction()) { 607 case MotionEvent.ACTION_DOWN: 608 mLongPressHelper.postCheckForLongPress(); 609 break; 610 case MotionEvent.ACTION_CANCEL: 611 case MotionEvent.ACTION_UP: 612 mLongPressHelper.cancelLongPress(); 613 break; 614 case MotionEvent.ACTION_MOVE: 615 if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) { 616 mLongPressHelper.cancelLongPress(); 617 } 618 break; 619 } 620 return result; 621 } 622 623 @Override 624 public void cancelLongPress() { 625 super.cancelLongPress(); 626 mLongPressHelper.cancelLongPress(); 627 } 628 629 public void removeListeners() { 630 mInfo.removeListener(this); 631 mInfo.removeListener(mFolder); 632 } 633 634 public void clearLeaveBehindIfExists() { 635 ((CellLayout.LayoutParams) getLayoutParams()).canReorder = true; 636 if (mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { 637 CellLayout cl = (CellLayout) getParent().getParent(); 638 cl.clearFolderLeaveBehind(); 639 } 640 } 641 642 public void drawLeaveBehindIfExists() { 643 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); 644 // While the folder is open, the position of the icon cannot change. 645 lp.canReorder = false; 646 if (mInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { 647 CellLayout cl = (CellLayout) getParent().getParent(); 648 cl.setFolderLeaveBehindCell(lp.cellX, lp.cellY); 649 } 650 } 651 652 public void onFolderClose(int currentPage) { 653 mPreviewItemManager.onFolderClose(currentPage); 654 } 655 } 656