1 package com.android.launcher3; 2 3 import android.annotation.TargetApi; 4 import android.content.ComponentName; 5 import android.content.Context; 6 import android.os.Build; 7 import android.os.Bundle; 8 import android.os.UserManager; 9 import android.util.AttributeSet; 10 import android.util.Pair; 11 import com.android.launcher3.R; 12 import com.android.launcher3.compat.UserHandleCompat; 13 import com.android.launcher3.util.Thunk; 14 15 public class UninstallDropTarget extends ButtonDropTarget { 16 UninstallDropTarget(Context context, AttributeSet attrs)17 public UninstallDropTarget(Context context, AttributeSet attrs) { 18 this(context, attrs, 0); 19 } 20 UninstallDropTarget(Context context, AttributeSet attrs, int defStyle)21 public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) { 22 super(context, attrs, defStyle); 23 } 24 25 @Override onFinishInflate()26 protected void onFinishInflate() { 27 super.onFinishInflate(); 28 // Get the hover color 29 mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint); 30 31 setDrawable(R.drawable.ic_uninstall_launcher); 32 } 33 34 @Override supportsDrop(DragSource source, Object info)35 protected boolean supportsDrop(DragSource source, Object info) { 36 return supportsDrop(getContext(), info); 37 } 38 39 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) supportsDrop(Context context, Object info)40 public static boolean supportsDrop(Context context, Object info) { 41 if (Utilities.ATLEAST_JB_MR2) { 42 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 43 Bundle restrictions = userManager.getUserRestrictions(); 44 if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) 45 || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) { 46 return false; 47 } 48 } 49 50 Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info); 51 return componentInfo != null && (componentInfo.second & AppInfo.DOWNLOADED_FLAG) != 0; 52 } 53 54 /** 55 * @return the component name and flags if {@param info} is an AppInfo or an app shortcut. 56 */ getAppInfoFlags(Object item)57 private static Pair<ComponentName, Integer> getAppInfoFlags(Object item) { 58 if (item instanceof AppInfo) { 59 AppInfo info = (AppInfo) item; 60 return Pair.create(info.componentName, info.flags); 61 } else if (item instanceof ShortcutInfo) { 62 ShortcutInfo info = (ShortcutInfo) item; 63 ComponentName component = info.getTargetComponent(); 64 if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION 65 && component != null) { 66 return Pair.create(component, info.flags); 67 } 68 } 69 return null; 70 } 71 72 @Override onDrop(DragObject d)73 public void onDrop(DragObject d) { 74 // Differ item deletion 75 if (d.dragSource instanceof UninstallSource) { 76 ((UninstallSource) d.dragSource).deferCompleteDropAfterUninstallActivity(); 77 } 78 super.onDrop(d); 79 } 80 81 @Override completeDrop(final DragObject d)82 void completeDrop(final DragObject d) { 83 final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo); 84 final UserHandleCompat user = ((ItemInfo) d.dragInfo).user; 85 if (startUninstallActivity(mLauncher, d.dragInfo)) { 86 87 final Runnable checkIfUninstallWasSuccess = new Runnable() { 88 @Override 89 public void run() { 90 String packageName = componentInfo.first.getPackageName(); 91 boolean uninstallSuccessful = !AllAppsList.packageHasActivities( 92 getContext(), packageName, user); 93 sendUninstallResult(d.dragSource, uninstallSuccessful); 94 } 95 }; 96 mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess); 97 } else { 98 sendUninstallResult(d.dragSource, false); 99 } 100 } 101 startUninstallActivity(Launcher launcher, Object info)102 public static boolean startUninstallActivity(Launcher launcher, Object info) { 103 final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info); 104 final UserHandleCompat user = ((ItemInfo) info).user; 105 return launcher.startApplicationUninstallActivity( 106 componentInfo.first, componentInfo.second, user); 107 } 108 sendUninstallResult(DragSource target, boolean result)109 @Thunk void sendUninstallResult(DragSource target, boolean result) { 110 if (target instanceof UninstallSource) { 111 ((UninstallSource) target).onUninstallActivityReturned(result); 112 } 113 } 114 115 /** 116 * Interface defining an object that can provide uninstallable drag objects. 117 */ 118 public static interface UninstallSource { 119 120 /** 121 * A pending uninstall operation was complete. 122 * @param result true if uninstall was successful, false otherwise. 123 */ onUninstallActivityReturned(boolean result)124 void onUninstallActivityReturned(boolean result); 125 126 /** 127 * Indicates that an uninstall request are made and the actual result may come 128 * after some time. 129 */ deferCompleteDropAfterUninstallActivity()130 void deferCompleteDropAfterUninstallActivity(); 131 } 132 } 133