From fa401a10e7e9341daf6f3c5949bf9331902c26d0 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 10 Apr 2015 13:45:42 -0700 Subject: Updating drop button targets > Splitting DeleteDropTarget into delete and uninstall > Showing UninstallDropTarget for app shortcuts on workspace > Showing InfoDropTarget only when developer options is enabled Change-Id: I4396571d2199d1581bb9c733aef88ab9b0ebd79d --- res/layout/search_drop_target_bar.xml | 13 + src/com/android/launcher3/AppsContainerView.java | 3 +- src/com/android/launcher3/ButtonDropTarget.java | 132 ++++++++-- src/com/android/launcher3/DeleteDropTarget.java | 278 +-------------------- src/com/android/launcher3/DragController.java | 9 +- src/com/android/launcher3/DropTarget.java | 4 +- src/com/android/launcher3/Folder.java | 5 +- src/com/android/launcher3/InfoDropTarget.java | 85 +------ .../launcher3/LauncherAccessibilityDelegate.java | 3 +- src/com/android/launcher3/LauncherModel.java | 10 +- src/com/android/launcher3/SearchDropTargetBar.java | 17 +- src/com/android/launcher3/UninstallDropTarget.java | 122 +++++++++ src/com/android/launcher3/Workspace.java | 5 +- 13 files changed, 312 insertions(+), 374 deletions(-) create mode 100644 src/com/android/launcher3/UninstallDropTarget.java diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml index 0d7167e5b..9b0da1d4e 100644 --- a/res/layout/search_drop_target_bar.xml +++ b/res/layout/search_drop_target_bar.xml @@ -41,6 +41,19 @@ android:text="@string/delete_target_label" /> + + + + + + + diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java index 52bc6b6ef..5f1594f28 100644 --- a/src/com/android/launcher3/AppsContainerView.java +++ b/src/com/android/launcher3/AppsContainerView.java @@ -34,6 +34,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; + import com.android.launcher3.util.Thunk; import java.util.List; @@ -286,7 +287,7 @@ public class AppsContainerView extends FrameLayout implements DragSource, Insett @Override public boolean supportsDeleteDropTarget() { - return true; + return false; } @Override diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index 019f86c21..5b399087a 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -17,19 +17,29 @@ package com.android.launcher3; import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.graphics.drawable.TransitionDrawable; import android.util.AttributeSet; import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; import android.widget.TextView; +import com.android.launcher3.R; +import com.android.launcher3.util.Thunk; /** * Implements a DropTarget. */ -public class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener { +public abstract class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener { + + private static int DRAG_VIEW_DROP_DURATION = 285; protected final int mTransitionDuration; @@ -44,6 +54,9 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro /** The paint applied to the drag view on hover */ protected int mHoverColor = 0; + protected ColorStateList mOriginalTextColor; + protected TransitionDrawable mDrawable; + public ButtonDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -56,12 +69,37 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro mBottomDragPadding = r.getDimensionPixelSize(R.dimen.drop_target_drag_padding); } - void setLauncher(Launcher launcher) { - mLauncher = launcher; + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mOriginalTextColor = getTextColors(); + + // Remove the text in the Phone UI in landscape + int orientation = getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + if (!LauncherAppState.getInstance().isScreenLarge()) { + setText(""); + } + } } - public boolean acceptDrop(DragObject d) { - return false; + protected void setDrawable(int resId) { + // Get the hover color + mDrawable = (TransitionDrawable) getCurrentDrawable(); + + if (mDrawable == null) { + // TODO: investigate why this is ever happening. Presently only on one known device. + mDrawable = (TransitionDrawable) getResources().getDrawable(resId); + setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null); + } + + if (null != mDrawable) { + mDrawable.setCrossFadeEnabled(true); + } + } + + public void setLauncher(Launcher launcher) { + mLauncher = launcher; } public void setSearchDropTargetBar(SearchDropTargetBar searchDropTargetBar) { @@ -78,37 +116,94 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro return null; } - public void onDrop(DragObject d) { + @Override + public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { } + + @Override + public final void onDragEnter(DragObject d) { + d.dragView.setColor(mHoverColor); + mDrawable.startTransition(mTransitionDuration); + setTextColor(mHoverColor); } - public void onFlingToDelete(DragObject d, int x, int y, PointF vec) { + @Override + public void onDragOver(DragObject d) { // Do nothing } - public void onDragEnter(DragObject d) { - d.dragView.setColor(mHoverColor); + protected void resetHoverColor() { + mDrawable.resetTransition(); + setTextColor(mOriginalTextColor); } - public void onDragOver(DragObject d) { - // Do nothing + @Override + public final void onDragExit(DragObject d) { + if (!d.dragComplete) { + d.dragView.setColor(0); + resetHoverColor(); + } else { + // Restore the hover color + d.dragView.setColor(mHoverColor); + } } - public void onDragExit(DragObject d) { - d.dragView.setColor(0); + @Override + public final void onDragStart(DragSource source, Object info, int dragAction) { + mActive = supportsDrop(source, info); + mDrawable.resetTransition(); + setTextColor(mOriginalTextColor); + ((ViewGroup) getParent()).setVisibility(mActive ? View.VISIBLE : View.GONE); } - public void onDragStart(DragSource source, Object info, int dragAction) { - // Do nothing + @Override + public final boolean acceptDrop(DragObject dragObject) { + return supportsDrop(dragObject.dragSource, dragObject.dragInfo); } + protected abstract boolean supportsDrop(DragSource source, Object info); + + @Override public boolean isDropEnabled() { return mActive; } + @Override public void onDragEnd() { - // Do nothing + mActive = false; } + /** + * On drop animate the dropView to the icon. + */ + @Override + public void onDrop(final DragObject d) { + final DragLayer dragLayer = mLauncher.getDragLayer(); + final Rect from = new Rect(); + dragLayer.getViewRectRelativeToSelf(d.dragView, from); + + int width = mDrawable.getIntrinsicWidth(); + int height = mDrawable.getIntrinsicHeight(); + final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), + width, height); + final float scale = (float) to.width() / from.width(); + mSearchDropTargetBar.deferOnDragEnd(); + + Runnable onAnimationEndRunnable = new Runnable() { + @Override + public void run() { + completeDrop(d); + mSearchDropTargetBar.onDragEnd(); + mLauncher.exitSpringLoadedDragModeDelayed(true, 0, null); + } + }; + dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f, + DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2), + new LinearInterpolator(), onAnimationEndRunnable, + DragLayer.ANIMATION_END_DISAPPEAR, null); + } + + @Thunk abstract void completeDrop(DragObject d); + @Override public void getHitRectRelativeToDragLayer(android.graphics.Rect outRect) { super.getHitRect(outRect); @@ -120,10 +215,10 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro } private boolean isRtl() { - return (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); + return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); } - Rect getIconRect(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight) { + protected Rect getIconRect(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight) { DragLayer dragLayer = mLauncher.getDragLayer(); // Find the rect to animate to (the view is center aligned) @@ -157,6 +252,7 @@ public class ButtonDropTarget extends TextView implements DropTarget, DragContro return to; } + @Override public void getLocationInDragLayer(int[] loc) { mLauncher.getDragLayer().getLocationInDragLayer(this, loc); } diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 62aa285ab..aa3e66c09 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -19,33 +19,22 @@ package com.android.launcher3; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.annotation.TargetApi; -import android.content.ComponentName; import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.TransitionDrawable; import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.os.UserManager; import android.util.AttributeSet; import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; -import android.view.animation.LinearInterpolator; -import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.R; import com.android.launcher3.util.Thunk; import com.android.launcher3.widget.WidgetsContainerView; public class DeleteDropTarget extends ButtonDropTarget { - private static int DELETE_ANIMATION_DURATION = 285; + private static int FLING_DELETE_ANIMATION_DURATION = 350; private static float FLING_TO_DELETE_FRICTION = 0.035f; private static int MODE_FLING_DELETE_TO_TRASH = 0; @@ -53,13 +42,6 @@ public class DeleteDropTarget extends ButtonDropTarget { private final int mFlingDeleteMode = MODE_FLING_DELETE_ALONG_VECTOR; - private ColorStateList mOriginalTextColor; - private TransitionDrawable mUninstallDrawable; - private TransitionDrawable mRemoveDrawable; - private TransitionDrawable mCurrentDrawable; - - @Thunk boolean mWaitingForUninstall = false; - public DeleteDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -71,258 +53,27 @@ public class DeleteDropTarget extends ButtonDropTarget { @Override protected void onFinishInflate() { super.onFinishInflate(); - - // Get the drawable - mOriginalTextColor = getTextColors(); - // Get the hover color - Resources r = getResources(); - mHoverColor = r.getColor(R.color.delete_target_hover_tint); - mUninstallDrawable = (TransitionDrawable) - r.getDrawable(R.drawable.uninstall_target_selector); - mRemoveDrawable = (TransitionDrawable) r.getDrawable(R.drawable.remove_target_selector); - - mRemoveDrawable.setCrossFadeEnabled(true); - mUninstallDrawable.setCrossFadeEnabled(true); - - // The current drawable is set to either the remove drawable or the uninstall drawable - // and is initially set to the remove drawable, as set in the layout xml. - mCurrentDrawable = (TransitionDrawable) getCurrentDrawable(); - - // Remove the text in the Phone UI in landscape - int orientation = getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - if (!LauncherAppState.getInstance().isScreenLarge()) { - setText(""); - } - } - } - - private boolean isAllAppsApplication(DragSource source, Object info) { - return source.supportsAppInfoDropTarget() && (info instanceof AppInfo); - } - - private boolean isWidget(DragSource source, Object info) { - if (source instanceof WidgetsContainerView) { - if (info instanceof PendingAddItemInfo) { - PendingAddItemInfo addInfo = (PendingAddItemInfo) info; - switch (addInfo.itemType) { - case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: - case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: - case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: - return true; - } - } - } - return false; - } - private boolean isDragSourceWorkspaceOrFolder(DragObject d) { - return (d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder); - } - - private void setHoverColor() { - if (mCurrentDrawable != null) { - mCurrentDrawable.startTransition(mTransitionDuration); - } - setTextColor(mHoverColor); - } - private void resetHoverColor() { - if (mCurrentDrawable != null) { - mCurrentDrawable.resetTransition(); - } - setTextColor(mOriginalTextColor); - } + mHoverColor = getResources().getColor(R.color.delete_target_hover_tint); - @Override - public boolean acceptDrop(DragObject d) { - return willAcceptDrop(d.dragInfo); + setDrawable(R.drawable.remove_target_selector); } - public static boolean willAcceptDrop(Object info) { - if (info instanceof ItemInfo) { - ItemInfo item = (ItemInfo) info; - if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET || - item.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET || - item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { - return true; - } - - if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { - return true; - } - - if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && - item instanceof AppInfo) { - AppInfo appInfo = (AppInfo) info; - return (appInfo.flags & AppInfo.DOWNLOADED_FLAG) != 0; - } - - if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && - item instanceof ShortcutInfo) { - return true; - } - } - return false; + public static boolean willAcceptDrop(DragSource source, Object info) { + return (info instanceof ItemInfo) && source.supportsDeleteDropTarget(); } - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) @Override - public void onDragStart(DragSource source, Object info, int dragAction) { - boolean isVisible = true; - boolean useUninstallLabel = isAllAppsApplication(source, info); - boolean useDeleteLabel = !useUninstallLabel && source.supportsDeleteDropTarget(); - - // If we are dragging an application from AppsCustomize, only show the control if we can - // delete the app (it was downloaded), and rename the string to "uninstall" in such a case. - // Hide the delete target if it is a widget from AppsCustomize. - if (!willAcceptDrop(info) || isWidget(source, info)) { - isVisible = false; - } - if (useUninstallLabel) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - UserManager userManager = (UserManager) - getContext().getSystemService(Context.USER_SERVICE); - Bundle restrictions = userManager.getUserRestrictions(); - if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) - || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) { - isVisible = false; - } - } - } - - if (useUninstallLabel) { - setCompoundDrawablesRelativeWithIntrinsicBounds(mUninstallDrawable, null, null, null); - } else if (useDeleteLabel) { - setCompoundDrawablesRelativeWithIntrinsicBounds(mRemoveDrawable, null, null, null); - } else { - isVisible = false; - } - mCurrentDrawable = (TransitionDrawable) getCurrentDrawable(); - - mActive = isVisible; - resetHoverColor(); - ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE); - if (isVisible && getText().length() > 0) { - setText(useUninstallLabel ? R.string.delete_target_uninstall_label - : R.string.delete_target_label); - } + protected boolean supportsDrop(DragSource source, Object info) { + return willAcceptDrop(source, info); } @Override - public void onDragEnd() { - super.onDragEnd(); - mActive = false; - } - - public void onDragEnter(DragObject d) { - super.onDragEnter(d); - - setHoverColor(); - } - - public void onDragExit(DragObject d) { - super.onDragExit(d); - - if (!d.dragComplete) { - resetHoverColor(); - } else { - // Restore the hover color if we are deleting - d.dragView.setColor(mHoverColor); - } - } - - private void animateToTrashAndCompleteDrop(final DragObject d) { - final DragLayer dragLayer = mLauncher.getDragLayer(); - final Rect from = new Rect(); - dragLayer.getViewRectRelativeToSelf(d.dragView, from); - - int width = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicWidth(); - int height = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicHeight(); - final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), - width, height); - final float scale = (float) to.width() / from.width(); - - mSearchDropTargetBar.deferOnDragEnd(); - deferCompleteDropIfUninstalling(d); - - Runnable onAnimationEndRunnable = new Runnable() { - @Override - public void run() { - completeDrop(d); - mSearchDropTargetBar.onDragEnd(); - mLauncher.exitSpringLoadedDragModeDelayed(true, 0, null); - } - }; - dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f, - DELETE_ANIMATION_DURATION, new DecelerateInterpolator(2), - new LinearInterpolator(), onAnimationEndRunnable, - DragLayer.ANIMATION_END_DISAPPEAR, null); - } - - private void deferCompleteDropIfUninstalling(DragObject d) { - mWaitingForUninstall = false; - if (isUninstallFromWorkspace(d)) { - if (d.dragSource instanceof Folder) { - ((Folder) d.dragSource).deferCompleteDropAfterUninstallActivity(); - } else if (d.dragSource instanceof Workspace) { - ((Workspace) d.dragSource).deferCompleteDropAfterUninstallActivity(); - } - mWaitingForUninstall = true; - } - } - - private boolean isUninstallFromWorkspace(DragObject d) { - return false; - } - @Thunk void completeDrop(DragObject d) { ItemInfo item = (ItemInfo) d.dragInfo; - boolean wasWaitingForUninstall = mWaitingForUninstall; - mWaitingForUninstall = false; - if (isAllAppsApplication(d.dragSource, item)) { - uninstallApp(mLauncher, (AppInfo) item); - } else if (isUninstallFromWorkspace(d)) { - ShortcutInfo shortcut = (ShortcutInfo) item; - if (shortcut.intent != null && shortcut.intent.getComponent() != null) { - final ComponentName componentName = shortcut.intent.getComponent(); - final DragSource dragSource = d.dragSource; - final UserHandleCompat user = shortcut.user; - mWaitingForUninstall = mLauncher.startApplicationUninstallActivity( - componentName, shortcut.flags, user); - if (mWaitingForUninstall) { - final Runnable checkIfUninstallWasSuccess = new Runnable() { - @Override - public void run() { - mWaitingForUninstall = false; - String packageName = componentName.getPackageName(); - boolean uninstallSuccessful = !AllAppsList.packageHasActivities( - getContext(), packageName, user); - if (dragSource instanceof Folder) { - ((Folder) dragSource). - onUninstallActivityReturned(uninstallSuccessful); - } else if (dragSource instanceof Workspace) { - ((Workspace) dragSource). - onUninstallActivityReturned(uninstallSuccessful); - } - } - }; - mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess); - } - } - } else if (isDragSourceWorkspaceOrFolder(d)) { + if ((d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder)) { removeWorkspaceOrFolderItem(mLauncher, item, null); } - if (wasWaitingForUninstall && !mWaitingForUninstall) { - if (d.dragSource instanceof Folder) { - ((Folder) d.dragSource).onUninstallActivityReturned(false); - } else if (d.dragSource instanceof Workspace) { - ((Workspace) d.dragSource).onUninstallActivityReturned(false); - } - } - } - - public static void uninstallApp(Launcher launcher, AppInfo info) { - launcher.startApplicationUninstallActivity(info.componentName, info.flags, info.user); } /** @@ -354,7 +105,7 @@ public class DeleteDropTarget extends ButtonDropTarget { appWidgetHost.deleteAppWidgetId(widget.appWidgetId); return null; } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } else { return false; @@ -367,18 +118,14 @@ public class DeleteDropTarget extends ButtonDropTarget { return true; } - public void onDrop(DragObject d) { - animateToTrashAndCompleteDrop(d); - } - /** * Creates an animation from the current drag view to the delete trash icon. */ private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer, DragObject d, PointF vel, ViewConfiguration config) { - int width = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicWidth(); - int height = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicHeight(); + int width = mDrawable.getIntrinsicWidth(); + int height = mDrawable.getIntrinsicHeight(); final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), width, height); final Rect from = new Rect(); @@ -541,7 +288,6 @@ public class DeleteDropTarget extends ButtonDropTarget { updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime, duration, config); } - deferCompleteDropIfUninstalling(d); Runnable onAnimationEndRunnable = new Runnable() { @Override diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java index 347374738..b24608cb1 100644 --- a/src/com/android/launcher3/DragController.java +++ b/src/com/android/launcher3/DragController.java @@ -125,7 +125,7 @@ public class DragController { /** * Interface to receive notifications when a drag starts or stops */ - interface DragListener { + public interface DragListener { /** * A drag has begun * @@ -400,7 +400,7 @@ public class DragController { } } - void onDeferredEndFling(DropTarget.DragObject d) { + public void onDeferredEndFling(DropTarget.DragObject d) { d.dragSource.onFlingToDeleteCompleted(); } @@ -462,7 +462,8 @@ public class DragController { mLastTouchUpTime = System.currentTimeMillis(); if (mDragging) { PointF vec = isFlingingToDelete(mDragObject.dragSource); - if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragInfo)) { + if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource, + mDragObject.dragInfo)) { vec = null; } if (vec != null) { @@ -616,7 +617,7 @@ public class DragController { if (mDragging) { PointF vec = isFlingingToDelete(mDragObject.dragSource); - if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragInfo)) { + if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource, mDragObject.dragInfo)) { vec = null; } if (vec != null) { diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java index 94ae82b82..c5cca3b28 100644 --- a/src/com/android/launcher3/DropTarget.java +++ b/src/com/android/launcher3/DropTarget.java @@ -139,7 +139,7 @@ public interface DropTarget { /** * Handle an object being dropped on the DropTarget - * + * * @param source DragSource where the drag started * @param x X coordinate of the drop location * @param y Y coordinate of the drop location @@ -169,7 +169,7 @@ public interface DropTarget { /** * Check if a drop action can occur at, or near, the requested location. * This will be called just before onDrop. - * + * * @param source DragSource where the drag started * @param x X coordinate of the drop location * @param y Y coordinate of the drop location diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 116332438..c35ce944f 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -51,6 +51,7 @@ import android.widget.TextView; import com.android.launcher3.DragController.DragListener; import com.android.launcher3.FolderInfo.FolderListener; +import com.android.launcher3.UninstallDropTarget.UninstallSource; import com.android.launcher3.Workspace.ItemOperator; import com.android.launcher3.util.Thunk; @@ -62,7 +63,7 @@ import java.util.Collections; */ public class Folder extends LinearLayout implements DragSource, View.OnClickListener, View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener, - View.OnFocusChangeListener, DragListener { + View.OnFocusChangeListener, DragListener, UninstallSource { private static final String TAG = "Launcher.Folder"; /** @@ -772,10 +773,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList updateItemLocationsInDatabaseBatch(); } + @Override public void deferCompleteDropAfterUninstallActivity() { mDeferDropAfterUninstall = true; } + @Override public void onUninstallActivityReturned(boolean success) { mDeferDropAfterUninstall = false; mUninstallSuccessful = success; diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java index 3c36361aa..e48640c93 100644 --- a/src/com/android/launcher3/InfoDropTarget.java +++ b/src/com/android/launcher3/InfoDropTarget.java @@ -18,21 +18,14 @@ package com.android.launcher3; import android.content.ComponentName; import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.drawable.TransitionDrawable; +import android.provider.Settings; import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; +import com.android.launcher3.R; import com.android.launcher3.compat.UserHandleCompat; public class InfoDropTarget extends ButtonDropTarget { - private ColorStateList mOriginalTextColor; - private TransitionDrawable mDrawable; - public InfoDropTarget(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -44,43 +37,10 @@ public class InfoDropTarget extends ButtonDropTarget { @Override protected void onFinishInflate() { super.onFinishInflate(); - - mOriginalTextColor = getTextColors(); - // Get the hover color - Resources r = getResources(); - mHoverColor = r.getColor(R.color.info_target_hover_tint); - mDrawable = (TransitionDrawable) getCurrentDrawable(); - - if (mDrawable == null) { - // TODO: investigate why this is ever happening. Presently only on one known device. - mDrawable = (TransitionDrawable) r.getDrawable(R.drawable.info_target_selector); - setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null); - } - - if (null != mDrawable) { - mDrawable.setCrossFadeEnabled(true); - } - - // Remove the text in the Phone UI in landscape - int orientation = getResources().getConfiguration().orientation; - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - if (!LauncherAppState.getInstance().isScreenLarge()) { - setText(""); - } - } - } - - @Override - public boolean acceptDrop(DragObject d) { - // acceptDrop is called just before onDrop. We do the work here, rather than - // in onDrop, because it allows us to reject the drop (by returning false) - // so that the object being dragged isn't removed from the drag source. + mHoverColor = getResources().getColor(R.color.info_target_hover_tint); - startDetailsActivityForInfo(d.dragInfo, mLauncher); - // There is no post-drop animation, so clean up the DragView now - d.deferDragViewCleanupPostAnimation = false; - return false; + setDrawable(R.drawable.info_target_selector); } public static void startDetailsActivityForInfo(Object info, Launcher launcher) { @@ -105,39 +65,14 @@ public class InfoDropTarget extends ButtonDropTarget { } @Override - public void onDragStart(DragSource source, Object info, int dragAction) { - boolean isVisible = true; - - // Hide this button unless we are dragging something from AllApps - if (!source.supportsAppInfoDropTarget()) { - isVisible = false; - } - - mActive = isVisible; - mDrawable.resetTransition(); - setTextColor(mOriginalTextColor); - ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE); + protected boolean supportsDrop(DragSource source, Object info) { + return source.supportsAppInfoDropTarget() && + Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1; } @Override - public void onDragEnd() { - super.onDragEnd(); - mActive = false; - } - - public void onDragEnter(DragObject d) { - super.onDragEnter(d); - - mDrawable.startTransition(mTransitionDuration); - setTextColor(mHoverColor); - } - - public void onDragExit(DragObject d) { - super.onDragExit(d); - - if (!d.dragComplete) { - mDrawable.resetTransition(); - setTextColor(mOriginalTextColor); - } + void completeDrop(DragObject d) { + startDetailsActivityForInfo(d.dragInfo, mLauncher); } } diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java index cfc1bd96c..8ba02ea5f 100644 --- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java @@ -105,7 +105,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate { InfoDropTarget.startDetailsActivityForInfo(item, mLauncher); return true; } else if (action == UNINSTALL) { - DeleteDropTarget.uninstallApp(mLauncher, (AppInfo) item); + AppInfo info = (AppInfo) item; + mLauncher.startApplicationUninstallActivity(info.componentName, info.flags, info.user); return true; } else if (action == MOVE) { beginAccessibleDrag(host, item); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 37f1ea86e..f7df6bc1a 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -1079,7 +1079,7 @@ public class LauncherModel extends BroadcastReceiver * @param context * @param item */ - static void deleteItemFromDatabase(Context context, final ItemInfo item) { + public static void deleteItemFromDatabase(Context context, final ItemInfo item) { ArrayList items = new ArrayList(); items.add(item); deleteItemsFromDatabase(context, items); @@ -1185,7 +1185,7 @@ public class LauncherModel extends BroadcastReceiver /** * Remove the contents of the specified folder from the database */ - static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) { + public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) { final ContentResolver cr = context.getContentResolver(); Runnable r = new Runnable() { @@ -3106,6 +3106,9 @@ public class LauncherModel extends BroadcastReceiver si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON & ~ShortcutInfo.FLAG_AUTOINTALL_ICON & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; + if (appInfo != null) { + si.flags = appInfo.flags; + } infoUpdated = true; si.updateIcon(mIconCache); @@ -3414,6 +3417,9 @@ public class LauncherModel extends BroadcastReceiver info.user = user; info.contentDescription = mUserManager.getBadgedLabelForUser( info.title.toString(), info.user); + if (lai != null) { + info.flags = AppInfo.initFlags(lai); + } return info; } diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index cc17820ff..a8dcd0f06 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -44,11 +44,14 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D private boolean mIsSearchBarHidden; private View mQSBSearchBar; private View mDropTargetBar; - private ButtonDropTarget mInfoDropTarget; - private ButtonDropTarget mDeleteDropTarget; private int mBarHeight; private boolean mDeferOnDragEnd = false; + // Drop targets + private ButtonDropTarget mInfoDropTarget; + private ButtonDropTarget mDeleteDropTarget; + private ButtonDropTarget mUninstallDropTarget; + private boolean mEnableDropDownDropTargets; public SearchDropTargetBar(Context context, AttributeSet attrs) { @@ -61,13 +64,19 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D public void setup(Launcher launcher, DragController dragController) { dragController.addDragListener(this); + dragController.setFlingToDeleteDropTarget(mDeleteDropTarget); + dragController.addDragListener(mInfoDropTarget); dragController.addDragListener(mDeleteDropTarget); + dragController.addDragListener(mUninstallDropTarget); + dragController.addDropTarget(mInfoDropTarget); dragController.addDropTarget(mDeleteDropTarget); - dragController.setFlingToDeleteDropTarget(mDeleteDropTarget); + dragController.addDropTarget(mUninstallDropTarget); + mInfoDropTarget.setLauncher(launcher); mDeleteDropTarget.setLauncher(launcher); + mUninstallDropTarget.setLauncher(launcher); } public void setQsbSearchBar(View qsb) { @@ -116,9 +125,11 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D mDropTargetBar = findViewById(R.id.drag_target_bar); mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text); mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text); + mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.uninstall_target_text); mInfoDropTarget.setSearchDropTargetBar(this); mDeleteDropTarget.setSearchDropTargetBar(this); + mUninstallDropTarget.setSearchDropTargetBar(this); mEnableDropDownDropTargets = getResources().getBoolean(R.bool.config_useDropTargetDownTransition); diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java new file mode 100644 index 000000000..4a7fffeb2 --- /dev/null +++ b/src/com/android/launcher3/UninstallDropTarget.java @@ -0,0 +1,122 @@ +package com.android.launcher3; + +import android.content.ComponentName; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.UserManager; +import android.util.AttributeSet; +import android.util.Pair; + +import com.android.launcher3.R; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.util.Thunk; + +public class UninstallDropTarget extends ButtonDropTarget { + + public UninstallDropTarget(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + // Get the hover color + mHoverColor = getResources().getColor(R.color.delete_target_hover_tint); + + setDrawable(R.drawable.uninstall_target_selector); + } + + @Override + protected boolean supportsDrop(DragSource source, Object info) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + UserManager userManager = (UserManager) + getContext().getSystemService(Context.USER_SERVICE); + Bundle restrictions = userManager.getUserRestrictions(); + if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) + || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) { + return false; + } + } + + Pair componentInfo = getAppInfoFlags(info); + return componentInfo != null && (componentInfo.second & AppInfo.DOWNLOADED_FLAG) != 0; + } + + /** + * @return the component name and flags if {@param info} is an AppInfo or an app shortcut. + */ + private static Pair getAppInfoFlags(Object item) { + if (item instanceof AppInfo) { + AppInfo info = (AppInfo) item; + return Pair.create(info.componentName, info.flags); + } else if (item instanceof ShortcutInfo) { + ShortcutInfo info = (ShortcutInfo) item; + ComponentName component = info.getTargetComponent(); + if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION + && component != null) { + return Pair.create(component, info.flags); + } + } + return null; + } + + @Override + public void onDrop(DragObject d) { + // Differ item deletion + if (d.dragSource instanceof UninstallSource) { + ((UninstallSource) d.dragSource).deferCompleteDropAfterUninstallActivity(); + } + super.onDrop(d); + } + + @Override + void completeDrop(final DragObject d) { + final Pair componentInfo = getAppInfoFlags(d.dragInfo); + final UserHandleCompat user = ((ItemInfo) d.dragInfo).user; + if (mLauncher.startApplicationUninstallActivity( + componentInfo.first, componentInfo.second, user)) { + + final Runnable checkIfUninstallWasSuccess = new Runnable() { + @Override + public void run() { + String packageName = componentInfo.first.getPackageName(); + boolean uninstallSuccessful = !AllAppsList.packageHasActivities( + getContext(), packageName, user); + sendUninstallResult(d.dragSource, uninstallSuccessful); + } + }; + mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess); + } else { + sendUninstallResult(d.dragSource, false); + } + } + + @Thunk void sendUninstallResult(DragSource target, boolean result) { + if (target instanceof UninstallSource) { + ((UninstallSource) target).onUninstallActivityReturned(result); + } + } + + /** + * Interface defining an object that can provide uninstallable drag objects. + */ + public static interface UninstallSource { + + /** + * A pending uninstall operation was complete. + * @param result true if uninstall was successful, false otherwise. + */ + void onUninstallActivityReturned(boolean result); + + /** + * Indicates that an uninstall request are made and the actual result may come + * after some time. + */ + void deferCompleteDropAfterUninstallActivity(); + } +} diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 043ecb075..568fbb301 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -66,6 +66,7 @@ import com.android.launcher3.FolderIcon.FolderRingAnimator; import com.android.launcher3.Launcher.CustomContentCallbacks; import com.android.launcher3.Launcher.LauncherOverlay; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.UninstallDropTarget.UninstallSource; import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; @@ -88,7 +89,7 @@ import java.util.concurrent.atomic.AtomicInteger; public class Workspace extends SmoothPagedView implements DropTarget, DragSource, DragScroller, View.OnTouchListener, DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener, - Insettable { + Insettable, UninstallSource { private static final String TAG = "Launcher.Workspace"; private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0; @@ -4269,11 +4270,13 @@ public class Workspace extends SmoothPagedView } } + @Override public void deferCompleteDropAfterUninstallActivity() { mDeferDropAfterUninstall = true; } /// maybe move this into a smaller part + @Override public void onUninstallActivityReturned(boolean success) { mDeferDropAfterUninstall = false; mUninstallSuccessful = success; -- cgit v1.2.3