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