• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.AsyncTask;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.view.animation.AnimationUtils;
26 
27 import com.android.launcher3.util.FlingAnimation;
28 import com.android.launcher3.util.Thunk;
29 
30 public class DeleteDropTarget extends ButtonDropTarget {
31 
DeleteDropTarget(Context context, AttributeSet attrs)32     public DeleteDropTarget(Context context, AttributeSet attrs) {
33         this(context, attrs, 0);
34     }
35 
DeleteDropTarget(Context context, AttributeSet attrs, int defStyle)36     public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) {
37         super(context, attrs, defStyle);
38     }
39 
40     @Override
onFinishInflate()41     protected void onFinishInflate() {
42         super.onFinishInflate();
43         // Get the hover color
44         mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
45 
46         setDrawable(R.drawable.ic_remove_launcher);
47     }
48 
supportsDrop(Object info)49     public static boolean supportsDrop(Object info) {
50         return (info instanceof ShortcutInfo)
51                 || (info instanceof LauncherAppWidgetInfo)
52                 || (info instanceof FolderInfo);
53     }
54 
55     @Override
supportsDrop(DragSource source, Object info)56     protected boolean supportsDrop(DragSource source, Object info) {
57         return source.supportsDeleteDropTarget() && supportsDrop(info);
58     }
59 
60     @Override
completeDrop(DragObject d)61     @Thunk void completeDrop(DragObject d) {
62         ItemInfo item = (ItemInfo) d.dragInfo;
63         if ((d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder)) {
64             removeWorkspaceOrFolderItem(mLauncher, item, null);
65         }
66     }
67 
68     /**
69      * Removes the item from the workspace. If the view is not null, it also removes the view.
70      * @return true if the item was removed.
71      */
removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view)72     public static boolean removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) {
73         if (item instanceof ShortcutInfo) {
74             LauncherModel.deleteItemFromDatabase(launcher, item);
75         } else if (item instanceof FolderInfo) {
76             FolderInfo folder = (FolderInfo) item;
77             launcher.removeFolder(folder);
78             LauncherModel.deleteFolderContentsFromDatabase(launcher, folder);
79         } else if (item instanceof LauncherAppWidgetInfo) {
80             final LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) item;
81 
82             // Remove the widget from the workspace
83             launcher.removeAppWidget(widget);
84             LauncherModel.deleteItemFromDatabase(launcher, widget);
85 
86             final LauncherAppWidgetHost appWidgetHost = launcher.getAppWidgetHost();
87 
88             if (appWidgetHost != null && !widget.isCustomWidget()
89                     && widget.isWidgetIdValid()) {
90                 // Deleting an app widget ID is a void call but writes to disk before returning
91                 // to the caller...
92                 new AsyncTask<Void, Void, Void>() {
93                     public Void doInBackground(Void ... args) {
94                         appWidgetHost.deleteAppWidgetId(widget.appWidgetId);
95                         return null;
96                     }
97                 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
98             }
99         } else {
100             return false;
101         }
102 
103         if (view != null) {
104             launcher.getWorkspace().removeWorkspaceItem(view);
105             launcher.getWorkspace().stripEmptyScreens();
106         }
107         return true;
108     }
109 
110     @Override
onFlingToDelete(final DragObject d, PointF vel)111     public void onFlingToDelete(final DragObject d, PointF vel) {
112         // Don't highlight the icon as it's animating
113         d.dragView.setColor(0);
114         d.dragView.updateInitialScaleToCurrentScale();
115 
116         final DragLayer dragLayer = mLauncher.getDragLayer();
117         FlingAnimation fling = new FlingAnimation(d, vel,
118                 getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
119                         mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()),
120                         dragLayer);
121 
122         final int duration = fling.getDuration();
123         final long startTime = AnimationUtils.currentAnimationTimeMillis();
124 
125         // NOTE: Because it takes time for the first frame of animation to actually be
126         // called and we expect the animation to be a continuation of the fling, we have
127         // to account for the time that has elapsed since the fling finished.  And since
128         // we don't have a startDelay, we will always get call to update when we call
129         // start() (which we want to ignore).
130         final TimeInterpolator tInterpolator = new TimeInterpolator() {
131             private int mCount = -1;
132             private float mOffset = 0f;
133 
134             @Override
135             public float getInterpolation(float t) {
136                 if (mCount < 0) {
137                     mCount++;
138                 } else if (mCount == 0) {
139                     mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
140                             startTime) / duration);
141                     mCount++;
142                 }
143                 return Math.min(1f, mOffset + t);
144             }
145         };
146 
147         Runnable onAnimationEndRunnable = new Runnable() {
148             @Override
149             public void run() {
150                 mLauncher.exitSpringLoadedDragMode();
151                 completeDrop(d);
152                 mLauncher.getDragController().onDeferredEndFling(d);
153             }
154         };
155 
156         dragLayer.animateView(d.dragView, fling, duration, tInterpolator, onAnimationEndRunnable,
157                 DragLayer.ANIMATION_END_DISAPPEAR, null);
158     }
159 
160     @Override
getAccessibilityDropConfirmation()161     protected String getAccessibilityDropConfirmation() {
162         return getResources().getString(R.string.item_removed);
163     }
164 }
165