blob: a7839ec29034bb1e3b4fa3de1d841cccd7d3d776 [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;
Sunny Goyal7c74e4a2016-12-15 15:53:17 -080011import android.os.UserHandle;
Sunny Goyalfa401a12015-04-10 13:45:42 -070012import android.os.UserManager;
13import android.util.AttributeSet;
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 -070018
19public class UninstallDropTarget extends ButtonDropTarget {
20
21 public UninstallDropTarget(Context context, AttributeSet attrs) {
22 this(context, attrs, 0);
23 }
24
25 public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) {
26 super(context, attrs, defStyle);
27 }
28
29 @Override
30 protected void onFinishInflate() {
31 super.onFinishInflate();
32 // Get the hover color
Sunny Goyal3a2698b2015-04-28 21:36:46 -070033 mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
Sunny Goyalfa401a12015-04-10 13:45:42 -070034
Sunny Goyal40b626b2015-06-04 22:40:14 -070035 setDrawable(R.drawable.ic_uninstall_launcher);
Sunny Goyalfa401a12015-04-10 13:45:42 -070036 }
37
38 @Override
Sunny Goyalaa8ef112015-06-12 20:04:41 -070039 protected boolean supportsDrop(DragSource source, ItemInfo info) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070040 return supportsDrop(getContext(), info);
41 }
42
Sunny Goyal70660032015-05-14 00:07:08 -070043 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
Sunny Goyal1a70cef2015-04-22 11:29:51 -070044 public static boolean supportsDrop(Context context, Object info) {
Sunny Goyal9fc953b2015-08-17 12:24:25 -070045 if (Utilities.ATLEAST_JB_MR2) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070046 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
Sunny Goyalfa401a12015-04-10 13:45:42 -070047 Bundle restrictions = userManager.getUserRestrictions();
48 if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
49 || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
50 return false;
51 }
52 }
53
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070054 return getUninstallTarget(context, info) != null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070055 }
56
57 /**
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070058 * @return the component name that should be uninstalled or null.
Sunny Goyalfa401a12015-04-10 13:45:42 -070059 */
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070060 private static ComponentName getUninstallTarget(Context context, Object item) {
61 Intent intent = null;
Sunny Goyal7c74e4a2016-12-15 15:53:17 -080062 UserHandle user = null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070063 if (item instanceof AppInfo) {
64 AppInfo info = (AppInfo) item;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070065 intent = info.intent;
66 user = info.user;
Sunny Goyalfa401a12015-04-10 13:45:42 -070067 } else if (item instanceof ShortcutInfo) {
68 ShortcutInfo info = (ShortcutInfo) item;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070069 if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
70 // Do not use restore/target intent here as we cannot uninstall an app which is
71 // being installed/restored.
72 intent = info.intent;
73 user = info.user;
74 }
75 }
76 if (intent != null) {
77 LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
78 .resolveActivity(intent, user);
79 if (info != null
80 && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
81 return info.getComponentName();
Sunny Goyalfa401a12015-04-10 13:45:42 -070082 }
83 }
84 return null;
85 }
86
87 @Override
88 public void onDrop(DragObject d) {
89 // Differ item deletion
Sunny Goyald5bd67d2016-03-11 01:10:19 -080090 if (d.dragSource instanceof DropTargetSource) {
91 ((DropTargetSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
Sunny Goyalfa401a12015-04-10 13:45:42 -070092 }
93 super.onDrop(d);
94 }
95
96 @Override
Sunny Goyal0f76b562016-12-13 19:37:10 -080097 public void completeDrop(final DragObject d) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080098 DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
99 ? (DropTargetResultCallback) d.dragSource : null;
100 startUninstallActivity(mLauncher, d.dragInfo, callback);
Tony Wickham734dfbe2015-09-16 16:22:36 -0700101 }
102
Sunny Goyalaa8ef112015-06-12 20:04:41 -0700103 public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800104 return startUninstallActivity(launcher, info, null);
Sunny Goyal1a70cef2015-04-22 11:29:51 -0700105 }
106
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800107 public static boolean startUninstallActivity(
108 final Launcher launcher, ItemInfo info, DropTargetResultCallback callback) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700109 final ComponentName cn = getUninstallTarget(launcher, info);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800110
111 final boolean isUninstallable;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700112 if (cn == null) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800113 // System applications cannot be installed. For now, show a toast explaining that.
114 // We may give them the option of disabling apps this way.
115 Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
116 isUninstallable = false;
117 } else {
118 Intent intent = new Intent(Intent.ACTION_DELETE,
119 Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
120 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
121 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800122 intent.putExtra(Intent.EXTRA_USER, info.user);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800123 launcher.startActivity(intent);
124 isUninstallable = true;
Sunny Goyalfa401a12015-04-10 13:45:42 -0700125 }
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800126 if (callback != null) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700127 sendUninstallResult(launcher, isUninstallable, cn, info.user, callback);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800128 }
129 return isUninstallable;
130 }
131
132 /**
133 * Notifies the {@param callback} whether the uninstall was successful or not.
134 *
135 * Since there is no direct callback for an uninstall request, we check the package existence
136 * when the launch resumes next time. This assumes that the uninstall activity will finish only
137 * after the task is completed
138 */
139 protected static void sendUninstallResult(
140 final Launcher launcher, boolean activityStarted,
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800141 final ComponentName cn, final UserHandle user,
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800142 final DropTargetResultCallback callback) {
143 if (activityStarted) {
144 final Runnable checkIfUninstallWasSuccess = new Runnable() {
145 @Override
146 public void run() {
147 String packageName = cn.getPackageName();
148 boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
149 launcher, packageName, user);
150 callback.onDragObjectRemoved(uninstallSuccessful);
151 }
152 };
153 launcher.addOnResumeCallback(checkIfUninstallWasSuccess);
154 } else {
155 callback.onDragObjectRemoved(false);
156 }
157 }
158
159 public interface DropTargetResultCallback {
160 /**
161 * A drag operation was complete.
162 * @param isRemoved true if the drag object should be removed, false otherwise.
163 */
164 void onDragObjectRemoved(boolean isRemoved);
Sunny Goyalfa401a12015-04-10 13:45:42 -0700165 }
166
167 /**
168 * Interface defining an object that can provide uninstallable drag objects.
169 */
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800170 public interface DropTargetSource extends DropTargetResultCallback {
Sunny Goyalfa401a12015-04-10 13:45:42 -0700171
172 /**
173 * Indicates that an uninstall request are made and the actual result may come
174 * after some time.
175 */
176 void deferCompleteDropAfterUninstallActivity();
177 }
178}