blob: 73a9f6417f78db9aef0f2c0d204dc5b7c3c2b7c4 [file] [log] [blame]
Sunny Goyalfa401a12015-04-10 13:45:42 -07001package com.android.launcher3;
2
3import android.content.ComponentName;
4import android.content.Context;
Sunny Goyald5bd67d2016-03-11 01:10:19 -08005import android.content.Intent;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -07006import android.content.pm.ApplicationInfo;
Sunny Goyald5bd67d2016-03-11 01:10:19 -08007import android.net.Uri;
Sunny Goyalfa401a12015-04-10 13:45:42 -07008import android.os.Bundle;
Sunny Goyal7c74e4a2016-12-15 15:53:17 -08009import android.os.UserHandle;
Sunny Goyalfa401a12015-04-10 13:45:42 -070010import android.os.UserManager;
11import android.util.AttributeSet;
Sunny Goyald5bd67d2016-03-11 01:10:19 -080012import android.widget.Toast;
Sunny Goyalaa8ef112015-06-12 20:04:41 -070013
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070014import com.android.launcher3.compat.LauncherActivityInfoCompat;
15import com.android.launcher3.compat.LauncherAppsCompat;
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
41 public static boolean supportsDrop(Context context, Object info) {
Sunny Goyala52ecb02016-12-16 15:04:51 -080042 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;
Sunny Goyalfa401a12015-04-10 13:45:42 -070047 }
48
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070049 return getUninstallTarget(context, info) != null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070050 }
51
52 /**
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070053 * @return the component name that should be uninstalled or null.
Sunny Goyalfa401a12015-04-10 13:45:42 -070054 */
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070055 private static ComponentName getUninstallTarget(Context context, Object item) {
56 Intent intent = null;
Sunny Goyal7c74e4a2016-12-15 15:53:17 -080057 UserHandle user = null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070058 if (item instanceof AppInfo) {
59 AppInfo info = (AppInfo) item;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070060 intent = info.intent;
61 user = info.user;
Sunny Goyalfa401a12015-04-10 13:45:42 -070062 } else if (item instanceof ShortcutInfo) {
63 ShortcutInfo info = (ShortcutInfo) item;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070064 if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
65 // Do not use restore/target intent here as we cannot uninstall an app which is
66 // being installed/restored.
67 intent = info.intent;
68 user = info.user;
69 }
70 }
71 if (intent != null) {
72 LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
73 .resolveActivity(intent, user);
74 if (info != null
75 && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
76 return info.getComponentName();
Sunny Goyalfa401a12015-04-10 13:45:42 -070077 }
78 }
79 return null;
80 }
81
82 @Override
83 public void onDrop(DragObject d) {
84 // Differ item deletion
Sunny Goyald5bd67d2016-03-11 01:10:19 -080085 if (d.dragSource instanceof DropTargetSource) {
86 ((DropTargetSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
Sunny Goyalfa401a12015-04-10 13:45:42 -070087 }
88 super.onDrop(d);
89 }
90
91 @Override
Sunny Goyal0f76b562016-12-13 19:37:10 -080092 public void completeDrop(final DragObject d) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080093 DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
94 ? (DropTargetResultCallback) d.dragSource : null;
95 startUninstallActivity(mLauncher, d.dragInfo, callback);
Tony Wickham734dfbe2015-09-16 16:22:36 -070096 }
97
Sunny Goyalaa8ef112015-06-12 20:04:41 -070098 public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080099 return startUninstallActivity(launcher, info, null);
Sunny Goyal1a70cef2015-04-22 11:29:51 -0700100 }
101
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800102 public static boolean startUninstallActivity(
103 final Launcher launcher, ItemInfo info, DropTargetResultCallback callback) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700104 final ComponentName cn = getUninstallTarget(launcher, info);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800105
106 final boolean isUninstallable;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700107 if (cn == null) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800108 // System applications cannot be installed. For now, show a toast explaining that.
109 // We may give them the option of disabling apps this way.
110 Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
111 isUninstallable = false;
112 } else {
113 Intent intent = new Intent(Intent.ACTION_DELETE,
114 Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
115 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
116 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800117 intent.putExtra(Intent.EXTRA_USER, info.user);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800118 launcher.startActivity(intent);
119 isUninstallable = true;
Sunny Goyalfa401a12015-04-10 13:45:42 -0700120 }
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800121 if (callback != null) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700122 sendUninstallResult(launcher, isUninstallable, cn, info.user, callback);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800123 }
124 return isUninstallable;
125 }
126
127 /**
128 * Notifies the {@param callback} whether the uninstall was successful or not.
129 *
130 * Since there is no direct callback for an uninstall request, we check the package existence
131 * when the launch resumes next time. This assumes that the uninstall activity will finish only
132 * after the task is completed
133 */
134 protected static void sendUninstallResult(
135 final Launcher launcher, boolean activityStarted,
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800136 final ComponentName cn, final UserHandle user,
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800137 final DropTargetResultCallback callback) {
138 if (activityStarted) {
139 final Runnable checkIfUninstallWasSuccess = new Runnable() {
140 @Override
141 public void run() {
142 String packageName = cn.getPackageName();
143 boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
144 launcher, packageName, user);
145 callback.onDragObjectRemoved(uninstallSuccessful);
146 }
147 };
148 launcher.addOnResumeCallback(checkIfUninstallWasSuccess);
149 } else {
150 callback.onDragObjectRemoved(false);
151 }
152 }
153
154 public interface DropTargetResultCallback {
155 /**
156 * A drag operation was complete.
157 * @param isRemoved true if the drag object should be removed, false otherwise.
158 */
159 void onDragObjectRemoved(boolean isRemoved);
Sunny Goyalfa401a12015-04-10 13:45:42 -0700160 }
161
162 /**
163 * Interface defining an object that can provide uninstallable drag objects.
164 */
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800165 public interface DropTargetSource extends DropTargetResultCallback {
Sunny Goyalfa401a12015-04-10 13:45:42 -0700166
167 /**
168 * Indicates that an uninstall request are made and the actual result may come
169 * after some time.
170 */
171 void deferCompleteDropAfterUninstallActivity();
172 }
173}