blob: 00c613a88f16e6646a3ffc830cc2f7e916b3a98e [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;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -07007import android.content.pm.ApplicationInfo;
Sunny Goyald5bd67d2016-03-11 01:10:19 -08008import android.net.Uri;
Sunny Goyalfa401a12015-04-10 13:45:42 -07009import android.os.Build;
10import android.os.Bundle;
11import android.os.UserManager;
12import android.util.AttributeSet;
13import android.util.Pair;
Sunny Goyald5bd67d2016-03-11 01:10:19 -080014import android.widget.Toast;
Sunny Goyalaa8ef112015-06-12 20:04:41 -070015
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070016import com.android.launcher3.compat.LauncherActivityInfoCompat;
17import com.android.launcher3.compat.LauncherAppsCompat;
Sunny Goyalfa401a12015-04-10 13:45:42 -070018import com.android.launcher3.compat.UserHandleCompat;
Sunny Goyalfa401a12015-04-10 13:45:42 -070019
20public class UninstallDropTarget extends ButtonDropTarget {
21
22 public UninstallDropTarget(Context context, AttributeSet attrs) {
23 this(context, attrs, 0);
24 }
25
26 public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) {
27 super(context, attrs, defStyle);
28 }
29
30 @Override
31 protected void onFinishInflate() {
32 super.onFinishInflate();
33 // Get the hover color
Sunny Goyal3a2698b2015-04-28 21:36:46 -070034 mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
Sunny Goyalfa401a12015-04-10 13:45:42 -070035
Sunny Goyal40b626b2015-06-04 22:40:14 -070036 setDrawable(R.drawable.ic_uninstall_launcher);
Sunny Goyalfa401a12015-04-10 13:45:42 -070037 }
38
39 @Override
Sunny Goyalaa8ef112015-06-12 20:04:41 -070040 protected boolean supportsDrop(DragSource source, ItemInfo info) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070041 return supportsDrop(getContext(), info);
42 }
43
Sunny Goyal70660032015-05-14 00:07:08 -070044 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
Sunny Goyal1a70cef2015-04-22 11:29:51 -070045 public static boolean supportsDrop(Context context, Object info) {
Sunny Goyal9fc953b2015-08-17 12:24:25 -070046 if (Utilities.ATLEAST_JB_MR2) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070047 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
Sunny Goyalfa401a12015-04-10 13:45:42 -070048 Bundle restrictions = userManager.getUserRestrictions();
49 if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
50 || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
51 return false;
52 }
53 }
54
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070055 return getUninstallTarget(context, info) != null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070056 }
57
58 /**
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070059 * @return the component name that should be uninstalled or null.
Sunny Goyalfa401a12015-04-10 13:45:42 -070060 */
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070061 private static ComponentName getUninstallTarget(Context context, Object item) {
62 Intent intent = null;
63 UserHandleCompat user = null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070064 if (item instanceof AppInfo) {
65 AppInfo info = (AppInfo) item;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070066 intent = info.intent;
67 user = info.user;
Sunny Goyalfa401a12015-04-10 13:45:42 -070068 } else if (item instanceof ShortcutInfo) {
69 ShortcutInfo info = (ShortcutInfo) item;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070070 if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
71 // Do not use restore/target intent here as we cannot uninstall an app which is
72 // being installed/restored.
73 intent = info.intent;
74 user = info.user;
75 }
76 }
77 if (intent != null) {
78 LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
79 .resolveActivity(intent, user);
80 if (info != null
81 && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
82 return info.getComponentName();
Sunny Goyalfa401a12015-04-10 13:45:42 -070083 }
84 }
85 return null;
86 }
87
88 @Override
89 public void onDrop(DragObject d) {
90 // Differ item deletion
Sunny Goyald5bd67d2016-03-11 01:10:19 -080091 if (d.dragSource instanceof DropTargetSource) {
92 ((DropTargetSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
Sunny Goyalfa401a12015-04-10 13:45:42 -070093 }
94 super.onDrop(d);
95 }
96
97 @Override
Sunny Goyal0f76b562016-12-13 19:37:10 -080098 public void completeDrop(final DragObject d) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080099 DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
100 ? (DropTargetResultCallback) d.dragSource : null;
101 startUninstallActivity(mLauncher, d.dragInfo, callback);
Tony Wickham734dfbe2015-09-16 16:22:36 -0700102 }
103
Sunny Goyalaa8ef112015-06-12 20:04:41 -0700104 public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800105 return startUninstallActivity(launcher, info, null);
Sunny Goyal1a70cef2015-04-22 11:29:51 -0700106 }
107
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800108 public static boolean startUninstallActivity(
109 final Launcher launcher, ItemInfo info, DropTargetResultCallback callback) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700110 final ComponentName cn = getUninstallTarget(launcher, info);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800111
112 final boolean isUninstallable;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700113 if (cn == null) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800114 // System applications cannot be installed. For now, show a toast explaining that.
115 // We may give them the option of disabling apps this way.
116 Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
117 isUninstallable = false;
118 } else {
119 Intent intent = new Intent(Intent.ACTION_DELETE,
120 Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
121 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
122 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
123 info.user.addToIntent(intent, Intent.EXTRA_USER);
124 launcher.startActivity(intent);
125 isUninstallable = true;
Sunny Goyalfa401a12015-04-10 13:45:42 -0700126 }
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800127 if (callback != null) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700128 sendUninstallResult(launcher, isUninstallable, cn, info.user, callback);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800129 }
130 return isUninstallable;
131 }
132
133 /**
134 * Notifies the {@param callback} whether the uninstall was successful or not.
135 *
136 * Since there is no direct callback for an uninstall request, we check the package existence
137 * when the launch resumes next time. This assumes that the uninstall activity will finish only
138 * after the task is completed
139 */
140 protected static void sendUninstallResult(
141 final Launcher launcher, boolean activityStarted,
142 final ComponentName cn, final UserHandleCompat user,
143 final DropTargetResultCallback callback) {
144 if (activityStarted) {
145 final Runnable checkIfUninstallWasSuccess = new Runnable() {
146 @Override
147 public void run() {
148 String packageName = cn.getPackageName();
149 boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
150 launcher, packageName, user);
151 callback.onDragObjectRemoved(uninstallSuccessful);
152 }
153 };
154 launcher.addOnResumeCallback(checkIfUninstallWasSuccess);
155 } else {
156 callback.onDragObjectRemoved(false);
157 }
158 }
159
160 public interface DropTargetResultCallback {
161 /**
162 * A drag operation was complete.
163 * @param isRemoved true if the drag object should be removed, false otherwise.
164 */
165 void onDragObjectRemoved(boolean isRemoved);
Sunny Goyalfa401a12015-04-10 13:45:42 -0700166 }
167
168 /**
169 * Interface defining an object that can provide uninstallable drag objects.
170 */
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800171 public interface DropTargetSource extends DropTargetResultCallback {
Sunny Goyalfa401a12015-04-10 13:45:42 -0700172
173 /**
174 * Indicates that an uninstall request are made and the actual result may come
175 * after some time.
176 */
177 void deferCompleteDropAfterUninstallActivity();
178 }
179}