Home | History | Annotate | Download | only in launcher3
      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 
     32     public DeleteDropTarget(Context context, AttributeSet attrs) {
     33         this(context, attrs, 0);
     34     }
     35 
     36     public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) {
     37         super(context, attrs, defStyle);
     38     }
     39 
     40     @Override
     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 
     49     public static boolean supportsDrop(Object info) {
     50         return (info instanceof ShortcutInfo)
     51                 || (info instanceof LauncherAppWidgetInfo)
     52                 || (info instanceof FolderInfo);
     53     }
     54 
     55     @Override
     56     protected boolean supportsDrop(DragSource source, Object info) {
     57         return source.supportsDeleteDropTarget() && supportsDrop(info);
     58     }
     59 
     60     @Override
     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      */
     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
    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
    161     protected String getAccessibilityDropConfirmation() {
    162         return getResources().getString(R.string.item_removed);
    163     }
    164 }
    165