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