blob: e15cf9f50aed3c8d2a7b64c9bf0520c786c20fa2 [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 Goyal3e9be432017-01-05 15:22:41 -08007import android.content.pm.LauncherActivityInfo;
Sunny Goyalf2db2532017-03-01 17:27:16 -08008import android.content.pm.PackageManager;
Sunny Goyald5bd67d2016-03-11 01:10:19 -08009import android.net.Uri;
Sunny Goyalfa401a12015-04-10 13:45:42 -070010import 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.LauncherAppsCompat;
Sunny Goyalfa401a12015-04-10 13:45:42 -070017
18public class UninstallDropTarget extends ButtonDropTarget {
19
20 public UninstallDropTarget(Context context, AttributeSet attrs) {
21 this(context, attrs, 0);
22 }
23
24 public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) {
25 super(context, attrs, defStyle);
26 }
27
28 @Override
29 protected void onFinishInflate() {
30 super.onFinishInflate();
Sunny Goyalda1dfa32017-04-26 22:34:49 -070031 setupUi();
32 }
33
34 protected void setupUi() {
Sunny Goyalfa401a12015-04-10 13:45:42 -070035 // Get the hover color
Sunny Goyal3a2698b2015-04-28 21:36:46 -070036 mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
Sunny Goyalda1dfa32017-04-26 22:34:49 -070037 setDrawable(R.drawable.ic_uninstall_shadow);
Sunny Goyalfa401a12015-04-10 13:45:42 -070038 }
39
40 @Override
Sunny Goyalaa8ef112015-06-12 20:04:41 -070041 protected boolean supportsDrop(DragSource source, ItemInfo info) {
Sunny Goyal1a70cef2015-04-22 11:29:51 -070042 return supportsDrop(getContext(), info);
43 }
44
Sunny Goyal1fe0c2c2017-08-15 12:54:42 -070045 public static boolean supportsDrop(Context context, ItemInfo info) {
Sunny Goyala52ecb02016-12-16 15:04:51 -080046 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
47 Bundle restrictions = userManager.getUserRestrictions();
48 if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
49 || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
50 return false;
Sunny Goyalfa401a12015-04-10 13:45:42 -070051 }
52
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070053 return getUninstallTarget(context, info) != null;
Sunny Goyalfa401a12015-04-10 13:45:42 -070054 }
55
56 /**
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070057 * @return the component name that should be uninstalled or null.
Sunny Goyalfa401a12015-04-10 13:45:42 -070058 */
Sunny Goyal1fe0c2c2017-08-15 12:54:42 -070059 private static ComponentName getUninstallTarget(Context context, ItemInfo item) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070060 Intent intent = null;
Sunny Goyal7c74e4a2016-12-15 15:53:17 -080061 UserHandle user = null;
Sunny Goyal1fe0c2c2017-08-15 12:54:42 -070062 if (item != null &&
63 item.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
64 intent = item.getIntent();
65 user = item.user;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070066 }
67 if (intent != null) {
Sunny Goyal3e9be432017-01-05 15:22:41 -080068 LauncherActivityInfo info = LauncherAppsCompat.getInstance(context)
Sunny Goyal8e0e1d72016-10-10 10:41:41 -070069 .resolveActivity(intent, user);
70 if (info != null
71 && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
72 return info.getComponentName();
Sunny Goyalfa401a12015-04-10 13:45:42 -070073 }
74 }
75 return null;
76 }
77
78 @Override
79 public void onDrop(DragObject d) {
80 // Differ item deletion
Sunny Goyald5bd67d2016-03-11 01:10:19 -080081 if (d.dragSource instanceof DropTargetSource) {
82 ((DropTargetSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
Sunny Goyalfa401a12015-04-10 13:45:42 -070083 }
84 super.onDrop(d);
85 }
86
87 @Override
Sunny Goyal0f76b562016-12-13 19:37:10 -080088 public void completeDrop(final DragObject d) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080089 DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
90 ? (DropTargetResultCallback) d.dragSource : null;
91 startUninstallActivity(mLauncher, d.dragInfo, callback);
Tony Wickham734dfbe2015-09-16 16:22:36 -070092 }
93
Sunny Goyalaa8ef112015-06-12 20:04:41 -070094 public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -080095 return startUninstallActivity(launcher, info, null);
Sunny Goyal1a70cef2015-04-22 11:29:51 -070096 }
97
Sunny Goyald5bd67d2016-03-11 01:10:19 -080098 public static boolean startUninstallActivity(
99 final Launcher launcher, ItemInfo info, DropTargetResultCallback callback) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700100 final ComponentName cn = getUninstallTarget(launcher, info);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800101
102 final boolean isUninstallable;
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700103 if (cn == null) {
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800104 // System applications cannot be installed. For now, show a toast explaining that.
105 // We may give them the option of disabling apps this way.
106 Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
107 isUninstallable = false;
108 } else {
109 Intent intent = new Intent(Intent.ACTION_DELETE,
110 Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
111 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
112 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800113 intent.putExtra(Intent.EXTRA_USER, info.user);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800114 launcher.startActivity(intent);
115 isUninstallable = true;
Sunny Goyalfa401a12015-04-10 13:45:42 -0700116 }
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800117 if (callback != null) {
Sunny Goyal8e0e1d72016-10-10 10:41:41 -0700118 sendUninstallResult(launcher, isUninstallable, cn, info.user, callback);
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800119 }
120 return isUninstallable;
121 }
122
123 /**
124 * Notifies the {@param callback} whether the uninstall was successful or not.
125 *
126 * Since there is no direct callback for an uninstall request, we check the package existence
127 * when the launch resumes next time. This assumes that the uninstall activity will finish only
128 * after the task is completed
129 */
130 protected static void sendUninstallResult(
131 final Launcher launcher, boolean activityStarted,
Sunny Goyal7c74e4a2016-12-15 15:53:17 -0800132 final ComponentName cn, final UserHandle user,
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800133 final DropTargetResultCallback callback) {
134 if (activityStarted) {
135 final Runnable checkIfUninstallWasSuccess = new Runnable() {
136 @Override
137 public void run() {
Sunny Goyalf2db2532017-03-01 17:27:16 -0800138 // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well.
139 boolean uninstallSuccessful = LauncherAppsCompat.getInstance(launcher)
140 .getApplicationInfo(cn.getPackageName(),
141 PackageManager.MATCH_UNINSTALLED_PACKAGES, user) == null;
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800142 callback.onDragObjectRemoved(uninstallSuccessful);
143 }
144 };
145 launcher.addOnResumeCallback(checkIfUninstallWasSuccess);
146 } else {
147 callback.onDragObjectRemoved(false);
148 }
149 }
150
151 public interface DropTargetResultCallback {
152 /**
153 * A drag operation was complete.
154 * @param isRemoved true if the drag object should be removed, false otherwise.
155 */
156 void onDragObjectRemoved(boolean isRemoved);
Sunny Goyalfa401a12015-04-10 13:45:42 -0700157 }
158
159 /**
160 * Interface defining an object that can provide uninstallable drag objects.
161 */
Sunny Goyald5bd67d2016-03-11 01:10:19 -0800162 public interface DropTargetSource extends DropTargetResultCallback {
Sunny Goyalfa401a12015-04-10 13:45:42 -0700163
164 /**
165 * Indicates that an uninstall request are made and the actual result may come
166 * after some time.
167 */
168 void deferCompleteDropAfterUninstallActivity();
169 }
170}