blob: 91539439c2362e685307caa04706139a9d211c57 [file] [log] [blame]
Sunny Goyalfa401a12015-04-10 13:45:42 -07001package com.android.launcher3;
2
Sunny Goyal70660032015-05-14 00:07:08 -07003import android.annotation.TargetApi;
Sunny Goyalfa401a12015-04-10 13:45:42 -07004import android.content.ComponentName;
5import android.content.Context;
Sunny Goyald5bd67d2016-03-11 01:10:19 -08006import android.content.Intent;
7import android.net.Uri;
Sunny Goyalfa401a12015-04-10 13:45:42 -07008import android.os.Build;
9import android.os.Bundle;
10import android.os.UserManager;
11import android.util.AttributeSet;
12import android.util.Pair;
Sunny Goyald5bd67d2016-03-11 01:10:19 -080013import android.widget.Toast;
Sunny Goyalaa8ef112015-06-12 20:04:41 -070014
Sunny Goyalfa401a12015-04-10 13:45:42 -070015import com.android.launcher3.compat.UserHandleCompat;
Sunny Goyalfa401a12015-04-10 13:45:42 -070016
17public class UninstallDropTarget extends ButtonDropTarget {
18
19 public UninstallDropTarget(Context context, AttributeSet attrs) {
20 this(context, attrs, 0);
21 }
22
23 public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) {
24 super(context, attrs, defStyle);
25 }
26
27 @Override
28 protected void onFinishInflate() {
29 super.onFinishInflate();
30 // Get the hover color
Sunny Goyal3a2698b2015-04-28 21:36:46 -070031 mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
Sunny Goyalfa401a12015-04-10 13:45:42 -070032
Sunny Goyal40b626b2015-06-04 22:40:14 -070033 setDrawable(R.drawable.ic_uninstall_launcher);
Sunny Goyalfa401a12015-04-10 13:45:42 -070034 }
35
36 @Override
Sunny Goyalaa8ef112015-06-12 20:04:41 -070037 protected boolean supportsDrop(DragSource source, ItemInfo info) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070038 return supportsDrop(getContext(), info);
39 }
40
Sunny Goyal70660032015-05-14 00:07:08 -070041 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
Sunny Goyal1a70cef2015-04-22 11:29:51 -070042 public static boolean supportsDrop(Context context, Object info) {
Sunny Goyal9fc953b2015-08-17 12:24:25 -070043 if (Utilities.ATLEAST_JB_MR2) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070044 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
Sunny Goyalfa401a12015-04-10 13:45:42 -070045 Bundle restrictions = userManager.getUserRestrictions();
46 if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
47 || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
48 return false;
49 }
50 }
51
52 Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
53 return componentInfo != null && (componentInfo.second & AppInfo.DOWNLOADED_FLAG) != 0;
54 }
55
56 /**
57 * @return the component name and flags if {@param info} is an AppInfo or an app shortcut.
58 */
59 private static Pair<ComponentName, Integer> getAppInfoFlags(Object item) {
60 if (item instanceof AppInfo) {
61 AppInfo info = (AppInfo) item;
62 return Pair.create(info.componentName, info.flags);
63 } else if (item instanceof ShortcutInfo) {
64 ShortcutInfo info = (ShortcutInfo) item;
65 ComponentName component = info.getTargetComponent();
66 if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION
67 && component != null) {
68 return Pair.create(component, info.flags);
69 }
70 }
71 return null;
72 }
73
74 @Override
75 public void onDrop(DragObject d) {
76 // Differ item deletion
Sunny Goyald5bd67d2016-03-11 01:10:19 -080077 if (d.dragSource instanceof DropTargetSource) {
78 ((DropTargetSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
Sunny Goyalfa401a12015-04-10 13:45:42 -070079 }
80 super.onDrop(d);
81 }
82
83 @Override
84 void completeDrop(final DragObject d) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080085 DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
86 ? (DropTargetResultCallback) d.dragSource : null;
87 startUninstallActivity(mLauncher, d.dragInfo, callback);
Tony Wickham734dfbe2015-09-16 16:22:36 -070088 }
89
Sunny Goyalaa8ef112015-06-12 20:04:41 -070090 public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080091 return startUninstallActivity(launcher, info, null);
Sunny Goyal1a70cef2015-04-22 11:29:51 -070092 }
93
Sunny Goyald5bd67d2016-03-11 01:10:19 -080094 public static boolean startUninstallActivity(
95 final Launcher launcher, ItemInfo info, DropTargetResultCallback callback) {
96 Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
97 ComponentName cn = componentInfo.first;
98
99 final boolean isUninstallable;
100 if ((componentInfo.second & AppInfo.DOWNLOADED_FLAG) == 0) {
101 // System applications cannot be installed. For now, show a toast explaining that.
102 // We may give them the option of disabling apps this way.
103 Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
104 isUninstallable = false;
105 } else {
106 Intent intent = new Intent(Intent.ACTION_DELETE,
107 Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
108 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
109 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
110 info.user.addToIntent(intent, Intent.EXTRA_USER);
111 launcher.startActivity(intent);
112 isUninstallable = true;
Sunny Goyalfa401a12015-04-10 13:45:42 -0700113 }
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800114 if (callback != null) {
115 sendUninstallResult(
116 launcher, isUninstallable, componentInfo.first, info.user, callback);
117 }
118 return isUninstallable;
119 }
120
121 /**
122 * Notifies the {@param callback} whether the uninstall was successful or not.
123 *
124 * Since there is no direct callback for an uninstall request, we check the package existence
125 * when the launch resumes next time. This assumes that the uninstall activity will finish only
126 * after the task is completed
127 */
128 protected static void sendUninstallResult(
129 final Launcher launcher, boolean activityStarted,
130 final ComponentName cn, final UserHandleCompat user,
131 final DropTargetResultCallback callback) {
132 if (activityStarted) {
133 final Runnable checkIfUninstallWasSuccess = new Runnable() {
134 @Override
135 public void run() {
136 String packageName = cn.getPackageName();
137 boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
138 launcher, packageName, user);
139 callback.onDragObjectRemoved(uninstallSuccessful);
140 }
141 };
142 launcher.addOnResumeCallback(checkIfUninstallWasSuccess);
143 } else {
144 callback.onDragObjectRemoved(false);
145 }
146 }
147
148 public interface DropTargetResultCallback {
149 /**
150 * A drag operation was complete.
151 * @param isRemoved true if the drag object should be removed, false otherwise.
152 */
153 void onDragObjectRemoved(boolean isRemoved);
Sunny Goyalfa401a12015-04-10 13:45:42 -0700154 }
155
156 /**
157 * Interface defining an object that can provide uninstallable drag objects.
158 */
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800159 public interface DropTargetSource extends DropTargetResultCallback {
Sunny Goyalfa401a12015-04-10 13:45:42 -0700160
161 /**
162 * Indicates that an uninstall request are made and the actual result may come
163 * after some time.
164 */
165 void deferCompleteDropAfterUninstallActivity();
166 }
167}