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.launcher2; 18 19 import android.content.Context; 20 import android.content.res.ColorStateList; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.graphics.PorterDuff; 24 import android.graphics.PorterDuffColorFilter; 25 import android.graphics.Rect; 26 import android.graphics.drawable.TransitionDrawable; 27 import android.util.AttributeSet; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.view.animation.DecelerateInterpolator; 31 32 import com.android.launcher.R; 33 34 public class DeleteDropTarget extends ButtonDropTarget { 35 36 private static int DELETE_ANIMATION_DURATION = 250; 37 private ColorStateList mOriginalTextColor; 38 private TransitionDrawable mDrawable; 39 private int mHoverColor = 0xFFFF0000; 40 41 public DeleteDropTarget(Context context, AttributeSet attrs) { 42 this(context, attrs, 0); 43 } 44 45 public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) { 46 super(context, attrs, defStyle); 47 } 48 49 @Override 50 protected void onFinishInflate() { 51 super.onFinishInflate(); 52 53 // Get the drawable 54 mOriginalTextColor = getTextColors(); 55 56 // Get the hover color 57 Resources r = getResources(); 58 mHoverColor = r.getColor(R.color.delete_target_hover_tint); 59 mHoverPaint.setColorFilter(new PorterDuffColorFilter( 60 mHoverColor, PorterDuff.Mode.SRC_ATOP)); 61 mDrawable = (TransitionDrawable) getCompoundDrawables()[0]; 62 mDrawable.setCrossFadeEnabled(true); 63 64 // Remove the text in the Phone UI in landscape 65 int orientation = getResources().getConfiguration().orientation; 66 if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 67 if (!LauncherApplication.isScreenLarge()) { 68 setText(""); 69 } 70 } 71 } 72 73 private boolean isAllAppsApplication(DragSource source, Object info) { 74 return (source instanceof AppsCustomizePagedView) && (info instanceof ApplicationInfo); 75 } 76 private boolean isAllAppsWidget(DragSource source, Object info) { 77 return (source instanceof AppsCustomizePagedView) && (info instanceof PendingAddWidgetInfo); 78 } 79 private boolean isDragSourceWorkspaceOrFolder(DragObject d) { 80 return (d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder); 81 } 82 private boolean isWorkspaceOrFolderApplication(DragObject d) { 83 return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo); 84 } 85 private boolean isWorkspaceOrFolderWidget(DragObject d) { 86 return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof LauncherAppWidgetInfo); 87 } 88 private boolean isWorkspaceFolder(DragObject d) { 89 return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof FolderInfo); 90 } 91 92 @Override 93 public boolean acceptDrop(DragObject d) { 94 // We can remove everything including App shortcuts, folders, widgets, etc. 95 return true; 96 } 97 98 @Override 99 public void onDragStart(DragSource source, Object info, int dragAction) { 100 boolean isVisible = true; 101 boolean isUninstall = false; 102 103 // If we are dragging a widget from AppsCustomize, hide the delete target 104 if (isAllAppsWidget(source, info)) { 105 isVisible = false; 106 } 107 108 // If we are dragging an application from AppsCustomize, only show the control if we can 109 // delete the app (it was downloaded), and rename the string to "uninstall" in such a case 110 if (isAllAppsApplication(source, info)) { 111 ApplicationInfo appInfo = (ApplicationInfo) info; 112 if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) { 113 isUninstall = true; 114 } else { 115 isVisible = false; 116 } 117 } 118 119 mActive = isVisible; 120 mDrawable.resetTransition(); 121 setTextColor(mOriginalTextColor); 122 ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE); 123 if (getText().length() > 0) { 124 setText(isUninstall ? R.string.delete_target_uninstall_label 125 : R.string.delete_target_label); 126 } 127 } 128 129 @Override 130 public void onDragEnd() { 131 super.onDragEnd(); 132 mActive = false; 133 } 134 135 public void onDragEnter(DragObject d) { 136 super.onDragEnter(d); 137 138 mDrawable.startTransition(mTransitionDuration); 139 setTextColor(mHoverColor); 140 } 141 142 public void onDragExit(DragObject d) { 143 super.onDragExit(d); 144 145 if (!d.dragComplete) { 146 mDrawable.resetTransition(); 147 setTextColor(mOriginalTextColor); 148 } 149 } 150 151 private void animateToTrashAndCompleteDrop(final DragObject d) { 152 DragLayer dragLayer = mLauncher.getDragLayer(); 153 Rect from = new Rect(); 154 Rect to = new Rect(); 155 dragLayer.getViewRectRelativeToSelf(d.dragView, from); 156 dragLayer.getViewRectRelativeToSelf(this, to); 157 158 int width = mDrawable.getIntrinsicWidth(); 159 int height = mDrawable.getIntrinsicHeight(); 160 to.set(to.left + getPaddingLeft(), to.top + getPaddingTop(), 161 to.left + getPaddingLeft() + width, to.bottom); 162 163 // Center the destination rect about the trash icon 164 int xOffset = (int) -(d.dragView.getMeasuredWidth() - width) / 2; 165 int yOffset = (int) -(d.dragView.getMeasuredHeight() - height) / 2; 166 to.offset(xOffset, yOffset); 167 168 mSearchDropTargetBar.deferOnDragEnd(); 169 Runnable onAnimationEndRunnable = new Runnable() { 170 @Override 171 public void run() { 172 mSearchDropTargetBar.onDragEnd(); 173 mLauncher.exitSpringLoadedDragMode(); 174 completeDrop(d); 175 } 176 }; 177 dragLayer.animateView(d.dragView, from, to, 0.1f, 0.1f, 178 DELETE_ANIMATION_DURATION, new DecelerateInterpolator(2), 179 new DecelerateInterpolator(1.5f), onAnimationEndRunnable, false); 180 } 181 182 private void completeDrop(DragObject d) { 183 ItemInfo item = (ItemInfo) d.dragInfo; 184 185 if (isAllAppsApplication(d.dragSource, item)) { 186 // Uninstall the application if it is being dragged from AppsCustomize 187 mLauncher.startApplicationUninstallActivity((ApplicationInfo) item); 188 } else if (isWorkspaceOrFolderApplication(d)) { 189 LauncherModel.deleteItemFromDatabase(mLauncher, item); 190 } else if (isWorkspaceFolder(d)) { 191 // Remove the folder from the workspace and delete the contents from launcher model 192 FolderInfo folderInfo = (FolderInfo) item; 193 mLauncher.removeFolder(folderInfo); 194 LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo); 195 } else if (isWorkspaceOrFolderWidget(d)) { 196 // Remove the widget from the workspace 197 mLauncher.removeAppWidget((LauncherAppWidgetInfo) item); 198 LauncherModel.deleteItemFromDatabase(mLauncher, item); 199 200 final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item; 201 final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost(); 202 if (appWidgetHost != null) { 203 // Deleting an app widget ID is a void call but writes to disk before returning 204 // to the caller... 205 new Thread("deleteAppWidgetId") { 206 public void run() { 207 appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId); 208 } 209 }.start(); 210 } 211 } 212 } 213 214 public void onDrop(DragObject d) { 215 animateToTrashAndCompleteDrop(d); 216 } 217 } 218