1 /* 2 * Copyright (C) 2011 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; 18 19 import android.animation.TimeInterpolator; 20 import android.content.Context; 21 import android.graphics.PointF; 22 import android.text.TextUtils; 23 import android.util.AttributeSet; 24 import android.view.View; 25 import android.view.animation.AnimationUtils; 26 27 import com.android.launcher3.dragndrop.DragLayer; 28 import com.android.launcher3.dragndrop.DragOptions; 29 import com.android.launcher3.folder.Folder; 30 import com.android.launcher3.util.FlingAnimation; 31 import com.android.launcher3.util.Thunk; 32 33 public class DeleteDropTarget extends ButtonDropTarget { 34 DeleteDropTarget(Context context, AttributeSet attrs)35 public DeleteDropTarget(Context context, AttributeSet attrs) { 36 this(context, attrs, 0); 37 } 38 DeleteDropTarget(Context context, AttributeSet attrs, int defStyle)39 public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) { 40 super(context, attrs, defStyle); 41 } 42 43 @Override onFinishInflate()44 protected void onFinishInflate() { 45 super.onFinishInflate(); 46 // Get the hover color 47 mHoverColor = getResources().getColor(R.color.delete_target_hover_tint); 48 49 setDrawable(R.drawable.ic_remove_launcher); 50 } 51 52 @Override onDragStart(DropTarget.DragObject dragObject, DragOptions options)53 public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { 54 super.onDragStart(dragObject, options); 55 setTextBasedOnDragSource(dragObject.dragSource); 56 } 57 58 /** @return true for items that should have a "Remove" action in accessibility. */ supportsAccessibleDrop(ItemInfo info)59 public static boolean supportsAccessibleDrop(ItemInfo info) { 60 return (info instanceof ShortcutInfo) 61 || (info instanceof LauncherAppWidgetInfo) 62 || (info instanceof FolderInfo); 63 } 64 65 @Override supportsDrop(DragSource source, ItemInfo info)66 protected boolean supportsDrop(DragSource source, ItemInfo info) { 67 return true; 68 } 69 70 /** 71 * Set the drop target's text to either "Remove" or "Cancel" depending on the drag source. 72 */ setTextBasedOnDragSource(DragSource dragSource)73 public void setTextBasedOnDragSource(DragSource dragSource) { 74 if (!TextUtils.isEmpty(getText())) { 75 setText(dragSource.supportsDeleteDropTarget() ? R.string.remove_drop_target_label 76 : android.R.string.cancel); 77 } 78 } 79 80 @Override completeDrop(DragObject d)81 @Thunk void completeDrop(DragObject d) { 82 ItemInfo item = d.dragInfo; 83 if ((d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder)) { 84 removeWorkspaceOrFolderItem(mLauncher, item, null); 85 } 86 } 87 88 /** 89 * Removes the item from the workspace. If the view is not null, it also removes the view. 90 */ removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view)91 public static void removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) { 92 // Remove the item from launcher and the db, we can ignore the containerInfo in this call 93 // because we already remove the drag view from the folder (if the drag originated from 94 // a folder) in Folder.beginDrag() 95 launcher.removeItem(view, item, true /* deleteFromDb */); 96 launcher.getWorkspace().stripEmptyScreens(); 97 launcher.getDragLayer().announceForAccessibility(launcher.getString(R.string.item_removed)); 98 } 99 100 @Override onFlingToDelete(final DragObject d, PointF vel)101 public void onFlingToDelete(final DragObject d, PointF vel) { 102 // Don't highlight the icon as it's animating 103 d.dragView.setColor(0); 104 105 final DragLayer dragLayer = mLauncher.getDragLayer(); 106 FlingAnimation fling = new FlingAnimation(d, vel, 107 getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), 108 mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()), 109 dragLayer); 110 111 final int duration = fling.getDuration(); 112 final long startTime = AnimationUtils.currentAnimationTimeMillis(); 113 114 // NOTE: Because it takes time for the first frame of animation to actually be 115 // called and we expect the animation to be a continuation of the fling, we have 116 // to account for the time that has elapsed since the fling finished. And since 117 // we don't have a startDelay, we will always get call to update when we call 118 // start() (which we want to ignore). 119 final TimeInterpolator tInterpolator = new TimeInterpolator() { 120 private int mCount = -1; 121 private float mOffset = 0f; 122 123 @Override 124 public float getInterpolation(float t) { 125 if (mCount < 0) { 126 mCount++; 127 } else if (mCount == 0) { 128 mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() - 129 startTime) / duration); 130 mCount++; 131 } 132 return Math.min(1f, mOffset + t); 133 } 134 }; 135 136 Runnable onAnimationEndRunnable = new Runnable() { 137 @Override 138 public void run() { 139 mLauncher.exitSpringLoadedDragMode(); 140 completeDrop(d); 141 mLauncher.getDragController().onDeferredEndFling(d); 142 } 143 }; 144 145 dragLayer.animateView(d.dragView, fling, duration, tInterpolator, onAnimationEndRunnable, 146 DragLayer.ANIMATION_END_DISAPPEAR, null); 147 } 148 } 149