Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5bd67df authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Adding support for result callback when starting uninstall-application activity

Change-Id: Ieaca4fbd0ae0156f24c8863ccbef61d4d6d30ba1
parent d3cc05a3
Loading
Loading
Loading
Loading
+31 −10
Original line number Diff line number Diff line
@@ -16,12 +16,19 @@

package com.android.launcher3;

import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Toast;

import com.android.launcher3.compat.LauncherAppsCompat;

public class InfoDropTarget extends UninstallDropTarget {

    private static final String TAG = "InfoDropTarget";

    public InfoDropTarget(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
@@ -39,10 +46,19 @@ public class InfoDropTarget extends UninstallDropTarget {
        setDrawable(R.drawable.ic_info_launcher);
    }

    @Override
    void completeDrop(DragObject d) {
        DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
                ? (DropTargetResultCallback) d.dragSource : null;
        startDetailsActivityForInfo(d.dragInfo, mLauncher, callback);
    }

    /**
     * @return Whether the activity was started.
     */
    public static boolean startDetailsActivityForInfo(ItemInfo info, Launcher launcher) {
    public static boolean startDetailsActivityForInfo(
            ItemInfo info, Launcher launcher, DropTargetResultCallback callback) {
        boolean result = false;
        ComponentName componentName = null;
        if (info instanceof AppInfo) {
            componentName = ((AppInfo) info).componentName;
@@ -54,23 +70,28 @@ public class InfoDropTarget extends UninstallDropTarget {
            componentName = ((LauncherAppWidgetInfo) info).providerName;
        }
        if (componentName != null) {
            launcher.startApplicationDetailsActivity(componentName, info.user);
            return true;
            try {
                LauncherAppsCompat.getInstance(launcher)
                        .showAppDetailsForProfile(componentName, info.user);
                result = true;
            } catch (SecurityException | ActivityNotFoundException e) {
                Toast.makeText(launcher, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                Log.e(TAG, "Unable to launch settings", e);
            }
        return false;
        }

    @Override
    protected boolean startActivityWithUninstallAffordance(DragObject d) {
        return startDetailsActivityForInfo(d.dragInfo, mLauncher);
        if (callback != null) {
            sendUninstallResult(launcher, result, componentName, info.user, callback);
        }
        return result;
    }

    @Override
    protected boolean supportsDrop(DragSource source, ItemInfo info) {
        return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
        return source.supportsAppInfoDropTarget() && supportsDrop(info);
    }

    public static boolean supportsDrop(Context context, ItemInfo info) {
    public static boolean supportsDrop(ItemInfo info) {
        return info instanceof AppInfo || info instanceof ShortcutInfo
                || info instanceof PendingAddItemInfo || info instanceof LauncherAppWidgetInfo;
    }
+1 −39
Original line number Diff line number Diff line
@@ -57,7 +57,6 @@ import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -108,9 +107,9 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.logging.UserEventLogger;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LongArrayMap;
@@ -2828,43 +2827,6 @@ public class Launcher extends Activity
        }
    }

    void startApplicationDetailsActivity(ComponentName componentName, UserHandleCompat user) {
        try {
            LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
            launcherApps.showAppDetailsForProfile(componentName, user);
        } catch (SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Launcher does not have permission to launch settings");
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch settings");
        }
    }

    // returns true if the activity was started
    boolean startApplicationUninstallActivity(ComponentName componentName, int flags,
            UserHandleCompat user) {
        if ((flags & AppInfo.DOWNLOADED_FLAG) == 0) {
            // System applications cannot be installed. For now, show a toast explaining that.
            // We may give them the option of disabling apps this way.
            int messageId = R.string.uninstall_system_app_text;
            Toast.makeText(this, messageId, Toast.LENGTH_SHORT).show();
            return false;
        } else {
            String packageName = componentName.getPackageName();
            String className = componentName.getClassName();
            Intent intent = new Intent(
                    Intent.ACTION_DELETE, Uri.fromParts("package", packageName, className));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                    Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            if (user != null) {
                user.addToIntent(intent, Intent.EXTRA_USER);
            }
            startActivity(intent);
            return true;
        }
    }

    private boolean startActivity(View v, Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
+65 −37
Original line number Diff line number Diff line
@@ -3,14 +3,16 @@ package com.android.launcher3;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.UserManager;
import android.util.AttributeSet;
import android.util.Pair;
import android.widget.Toast;

import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.Thunk;

public class UninstallDropTarget extends ButtonDropTarget {

@@ -72,63 +74,89 @@ public class UninstallDropTarget extends ButtonDropTarget {
    @Override
    public void onDrop(DragObject d) {
        // Differ item deletion
        if (d.dragSource instanceof UninstallSource) {
            ((UninstallSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
        if (d.dragSource instanceof DropTargetSource) {
            ((DropTargetSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
        }
        super.onDrop(d);
    }

    @Override
    void completeDrop(final DragObject d) {
        final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
        final UserHandleCompat user = d.dragInfo.user;
        if (startActivityWithUninstallAffordance(d)) {

            final Runnable checkIfUninstallWasSuccess = new Runnable() {
                @Override
                public void run() {
                    boolean uninstallSuccessful = false;
                    if (componentInfo != null) {
                        String packageName = componentInfo.first.getPackageName();
                        uninstallSuccessful = !AllAppsList.packageHasActivities(
                                getContext(), packageName, user);
        DropTargetResultCallback callback = d.dragSource instanceof DropTargetResultCallback
                ? (DropTargetResultCallback) d.dragSource : null;
        startUninstallActivity(mLauncher, d.dragInfo, callback);
    }
                    sendUninstallResult(d.dragSource, uninstallSuccessful);

    public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
        return startUninstallActivity(launcher, info, null);
    }
            };
            mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess);

    public static boolean startUninstallActivity(
            final Launcher launcher, ItemInfo info, DropTargetResultCallback callback) {
        Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
        ComponentName cn = componentInfo.first;

        final boolean isUninstallable;
        if ((componentInfo.second & AppInfo.DOWNLOADED_FLAG) == 0) {
            // System applications cannot be installed. For now, show a toast explaining that.
            // We may give them the option of disabling apps this way.
            Toast.makeText(launcher, R.string.uninstall_system_app_text, Toast.LENGTH_SHORT).show();
            isUninstallable = false;
        } else {
            sendUninstallResult(d.dragSource, false);
            Intent intent = new Intent(Intent.ACTION_DELETE,
                    Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            info.user.addToIntent(intent, Intent.EXTRA_USER);
            launcher.startActivity(intent);
            isUninstallable = true;
        }
        if (callback != null) {
            sendUninstallResult(
                    launcher, isUninstallable, componentInfo.first, info.user, callback);
        }

    protected boolean startActivityWithUninstallAffordance(DragObject d) {
        return startUninstallActivity(mLauncher, d.dragInfo);
        return isUninstallable;
    }

    public static boolean startUninstallActivity(Launcher launcher, ItemInfo info) {
        final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
        final UserHandleCompat user = info.user;
        return launcher.startApplicationUninstallActivity(
                componentInfo.first, componentInfo.second, user);
    /**
     * Notifies the {@param callback} whether the uninstall was successful or not.
     *
     * Since there is no direct callback for an uninstall request, we check the package existence
     * when the launch resumes next time. This assumes that the uninstall activity will finish only
     * after the task is completed
     */
    protected static void sendUninstallResult(
            final Launcher launcher, boolean activityStarted,
            final ComponentName cn, final UserHandleCompat user,
            final DropTargetResultCallback callback) {
        if (activityStarted)  {
            final Runnable checkIfUninstallWasSuccess = new Runnable() {
                @Override
                public void run() {
                    String packageName = cn.getPackageName();
                    boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
                            launcher, packageName, user);
                    callback.onDragObjectRemoved(uninstallSuccessful);
                }

    @Thunk void sendUninstallResult(DragSource target, boolean result) {
        if (target instanceof UninstallSource) {
            ((UninstallSource) target).onUninstallActivityReturned(result);
            };
            launcher.addOnResumeCallback(checkIfUninstallWasSuccess);
        } else {
            callback.onDragObjectRemoved(false);
        }
    }

    public interface DropTargetResultCallback {
        /**
     * Interface defining an object that can provide uninstallable drag objects.
         * A drag operation was complete.
         * @param isRemoved true if the drag object should be removed, false otherwise.
         */
    public interface UninstallSource {
        void onDragObjectRemoved(boolean isRemoved);
    }

    /**
         * A pending uninstall operation was complete.
         * @param result true if uninstall was successful, false otherwise.
     * Interface defining an object that can provide uninstallable drag objects.
     */
        void onUninstallActivityReturned(boolean result);
    public interface DropTargetSource extends DropTargetResultCallback {

        /**
         * Indicates that an uninstall request are made and the actual result may come
+3 −3
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ import android.widget.TextView;

import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.Launcher.LauncherOverlay;
import com.android.launcher3.UninstallDropTarget.UninstallSource;
import com.android.launcher3.UninstallDropTarget.DropTargetSource;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
@@ -92,7 +92,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class Workspace extends PagedView
        implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
        DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
        Insettable, UninstallSource, AccessibilityDragSource, Stats.LaunchSourceProvider {
        Insettable, DropTargetSource, AccessibilityDragSource, Stats.LaunchSourceProvider {
    private static final String TAG = "Launcher.Workspace";

    private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
@@ -3664,7 +3664,7 @@ public class Workspace extends PagedView

    /// maybe move this into a smaller part
    @Override
    public void onUninstallActivityReturned(boolean success) {
    public void onDragObjectRemoved(boolean success) {
        mDeferDropAfterUninstall = false;
        mUninstallSuccessful = success;
        if (mDeferredAction != null) {
+2 −2
Original line number Diff line number Diff line
@@ -102,7 +102,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
        if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
            info.addAction(mActions.get(UNINSTALL));
        }
        if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
        if (InfoDropTarget.supportsDrop(item)) {
            info.addAction(mActions.get(INFO));
        }

@@ -137,7 +137,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
            DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host);
            return true;
        } else if (action == INFO) {
            InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
            InfoDropTarget.startDetailsActivityForInfo(item, mLauncher, null);
            return true;
        } else if (action == UNINSTALL) {
            return UninstallDropTarget.startUninstallActivity(mLauncher, item);
Loading