Removing some unnecessary interfaces and merging them to ActivityContext

Bug: 259733681
Test: Everything compiles
Change-Id: If6b530f6e589a851cf8554f5de0849843bd66dd4
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 9bdc822..61707df 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -30,14 +30,13 @@
 
 import androidx.annotation.IntDef;
 
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.ViewCache;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.ScrimView;
 
 import java.io.PrintWriter;
@@ -48,8 +47,7 @@
 /**
  * Launcher BaseActivity
  */
-public abstract class BaseActivity extends Activity implements AppLauncher,
-        DeviceProfileListenable {
+public abstract class BaseActivity extends Activity implements ActivityContext {
 
     private static final String TAG = "BaseActivity";
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 828066a..ce78fce 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -55,7 +55,6 @@
 import com.android.launcher3.util.WindowBounds;
 
 import java.io.PrintWriter;
-import java.util.List;
 import java.util.Locale;
 
 @SuppressLint("NewApi")
@@ -1631,35 +1630,6 @@
         void onDeviceProfileChanged(DeviceProfile dp);
     }
 
-    /** Allows registering listeners for {@link DeviceProfile} changes. */
-    public interface DeviceProfileListenable {
-
-        /** The current device profile. */
-        DeviceProfile getDeviceProfile();
-
-        /** Registered {@link OnDeviceProfileChangeListener} instances. */
-        List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners();
-
-        /** Notifies listeners of a {@link DeviceProfile} change. */
-        default void dispatchDeviceProfileChanged() {
-            DeviceProfile deviceProfile = getDeviceProfile();
-            List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners();
-            for (int i = listeners.size() - 1; i >= 0; i--) {
-                listeners.get(i).onDeviceProfileChanged(deviceProfile);
-            }
-        }
-
-        /** Register listener for {@link DeviceProfile} changes. */
-        default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
-            getOnDeviceProfileChangeListeners().add(listener);
-        }
-
-        /** Unregister listener for {@link DeviceProfile} changes. */
-        default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
-            getOnDeviceProfileChangeListeners().remove(listener);
-        }
-    }
-
     /**
      * Handler that deals with ItemInfo of the views for the DeviceProfile
      */
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 31a7d18..5dddc6f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.uioverrides.states.AllAppsState;
 import com.android.launcher3.uioverrides.states.OverviewState;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.Arrays;
 
@@ -261,7 +262,7 @@
      *
      * 0 means completely zoomed in, without blurs. 1 is zoomed out, with blurs.
      */
-    public final  <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    public final  <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepth(DEVICE_PROFILE_CONTEXT context) {
         return getDepth(context,
                 BaseDraggingActivity.fromContext(context).getDeviceProfile().isMultiWindowMode);
@@ -272,7 +273,7 @@
      *
      * @see #getDepth(Context).
      */
-    public final <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    public final <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepth(DEVICE_PROFILE_CONTEXT context, boolean isMultiWindowMode) {
         if (isMultiWindowMode) {
             return 0;
@@ -280,7 +281,7 @@
         return getDepthUnchecked(context);
     }
 
-    protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable>
+    protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
             float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
         return 0f;
     }
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 5c55b53..5296df1 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -27,13 +27,12 @@
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 
@@ -42,8 +41,8 @@
  *
  * @param <T> Type of context inflating all apps.
  */
-public class ActivityAllAppsContainerView<T extends Context & AppLauncher
-        & DeviceProfileListenable> extends BaseAllAppsContainerView<T> {
+public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
+        extends BaseAllAppsContainerView<T> {
 
     private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300;
 
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index f308a25..65b4661 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -48,7 +48,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
@@ -81,8 +80,8 @@
  *
  * @param <T> Type of context inflating all apps.
  */
-public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext
-        & DeviceProfileListenable> extends SpringRelativeLayout implements DragSource, Insettable,
+public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext>
+        extends SpringRelativeLayout implements DragSource, Insettable,
         OnDeviceProfileChangeListener, OnActivePageChangedListener,
         ScrimView.ScrimDrawingController {
 
diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
index 4fb732d..20edf8a 100644
--- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
+++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java
@@ -26,17 +26,17 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.views.AppLauncher;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Provides views for local search results.
  */
-public class DefaultSearchAdapterProvider extends SearchAdapterProvider<AppLauncher> {
+public class DefaultSearchAdapterProvider extends SearchAdapterProvider<ActivityContext> {
 
     private final RecyclerView.ItemDecoration mDecoration;
     private View mHighlightedView;
 
-    public DefaultSearchAdapterProvider(AppLauncher launcher) {
+    public DefaultSearchAdapterProvider(ActivityContext launcher) {
         super(launcher);
         mDecoration = new RecyclerView.ItemDecoration() {
             @Override
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 772913d..e7b0446 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -63,6 +63,7 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.InvariantDeviceProfile;
@@ -174,6 +175,7 @@
         }
     }
 
+    private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>();
     private final Handler mUiHandler;
     private final Context mContext;
     private final InvariantDeviceProfile mIdp;
@@ -331,6 +333,11 @@
     }
 
     @Override
+    public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() {
+        return mDpChangeListeners;
+    }
+
+    @Override
     public Hotseat getHotseat() {
         return mHotseat;
     }
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
index 32378b8..2390425 100644
--- a/src/com/android/launcher3/statemanager/BaseState.java
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -18,7 +18,7 @@
 import android.content.Context;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.DeviceProfileListenable;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Interface representing a state of a StatefulActivity
@@ -37,7 +37,7 @@
     /**
      * @return How long the animation to this state should take (or from this state to NORMAL).
      */
-    <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable>
+    <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
     int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState);
 
     /**
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index dd5b22e..28085e1 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -17,23 +17,41 @@
 
 import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
+import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
+import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.Toast;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
@@ -41,20 +59,30 @@
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.OnboardingPrefs;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.ViewCache;
 
+import java.util.List;
+
 /**
  * An interface to be used along with a context for various activities in Launcher. This allows a
  * generic class to depend on Context subclass instead of an Activity.
  */
 public interface ActivityContext {
 
+    String TAG = "ActivityContext";
+
     default boolean finishAutoCancelActionMode() {
         return false;
     }
@@ -117,6 +145,28 @@
 
     DeviceProfile getDeviceProfile();
 
+    /** Registered {@link OnDeviceProfileChangeListener} instances. */
+    List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners();
+
+    /** Notifies listeners of a {@link DeviceProfile} change. */
+    default void dispatchDeviceProfileChanged() {
+        DeviceProfile deviceProfile = getDeviceProfile();
+        List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners();
+        for (int i = listeners.size() - 1; i >= 0; i--) {
+            listeners.get(i).onDeviceProfileChanged(deviceProfile);
+        }
+    }
+
+    /** Register listener for {@link DeviceProfile} changes. */
+    default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+        getOnDeviceProfileChangeListeners().add(listener);
+    }
+
+    /** Unregister listener for {@link DeviceProfile} changes. */
+    default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+        getOnDeviceProfileChangeListeners().remove(listener);
+    }
+
     default ViewCache getViewCache() {
         return new ViewCache();
     }
@@ -162,32 +212,6 @@
         return false;
     }
 
-    /**
-     * Returns the ActivityContext associated with the given Context, or throws an exception if
-     * the Context is not associated with any ActivityContext.
-     */
-    static <T extends Context & ActivityContext> T lookupContext(Context context) {
-        T activityContext = lookupContextNoThrow(context);
-        if (activityContext == null) {
-            throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
-        }
-        return activityContext;
-    }
-
-    /**
-     * Returns the ActivityContext associated with the given Context, or null if
-     * the Context is not associated with any ActivityContext.
-     */
-    static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
-        if (context instanceof ActivityContext) {
-            return (T) context;
-        } else if (context instanceof ContextWrapper) {
-            return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
-        } else {
-            return null;
-        }
-    }
-
     default View.OnClickListener getItemOnClickListener() {
         return v -> {
             // No op.
@@ -256,4 +280,187 @@
             });
         }
     }
+
+    /**
+     * Safely starts an activity.
+     *
+     * @param v View starting the activity.
+     * @param intent Base intent being launched.
+     * @param item Item associated with the view.
+     * @return {@code true} if the activity starts successfully.
+     */
+    default boolean startActivitySafely(
+            View v, Intent intent, @Nullable ItemInfo item) {
+
+        Context context = (Context) this;
+        if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
+            Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
+            return false;
+        }
+
+        Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null;
+        UserHandle user = item == null ? null : item.user;
+
+        // Prepare intent
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (v != null) {
+            intent.setSourceBounds(Utilities.getViewBounds(v));
+        }
+        try {
+            boolean isShortcut = (item instanceof WorkspaceItemInfo)
+                    && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+                    || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+                    && !((WorkspaceItemInfo) item).isPromise();
+            if (isShortcut) {
+                // Shortcuts need some special checks due to legacy reasons.
+                startShortcutIntentSafely(intent, optsBundle, item);
+            } else if (user == null || user.equals(Process.myUserHandle())) {
+                // Could be launching some bookkeeping activity
+                context.startActivity(intent, optsBundle);
+            } else {
+                context.getSystemService(LauncherApps.class).startMainActivity(
+                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
+            }
+            if (item != null) {
+                InstanceId instanceId = new InstanceIdSequence().newInstanceId();
+                logAppLaunch(getStatsLogManager(), item, instanceId);
+            }
+            return true;
+        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
+            Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
+        }
+        return false;
+    }
+
+    /** Returns {@code true} if an app launch is blocked due to safe mode. */
+    default boolean isAppBlockedForSafeMode() {
+        return false;
+    }
+
+    /**
+     * Creates and logs a new app launch event.
+     */
+    default void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
+            InstanceId instanceId) {
+        statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId)
+                .log(LAUNCHER_APP_LAUNCH_TAP);
+    }
+
+    /**
+     * Returns launch options for an Activity.
+     *
+     * @param v View initiating a launch.
+     * @param item Item associated with the view.
+     */
+    default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
+        int left = 0, top = 0;
+        int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
+        if (v instanceof BubbleTextView) {
+            // Launch from center of icon, not entire view
+            Drawable icon = ((BubbleTextView) v).getIcon();
+            if (icon != null) {
+                Rect bounds = icon.getBounds();
+                left = (width - bounds.width()) / 2;
+                top = v.getPaddingTop();
+                width = bounds.width();
+                height = bounds.height();
+            }
+        }
+        ActivityOptions options =
+                ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
+
+        options.setLaunchDisplayId(
+                (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
+                        : Display.DEFAULT_DISPLAY);
+        RunnableList callback = new RunnableList();
+        return new ActivityOptionsWrapper(options, callback);
+    }
+
+    /**
+     * Safely launches an intent for a shortcut.
+     *
+     * @param intent Intent to start.
+     * @param optsBundle Optional launch arguments.
+     * @param info Shortcut information.
+     */
+    default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
+        try {
+            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
+            try {
+                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
+                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
+                // is enabled by default on NYC.
+                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
+                        .penaltyLog().build());
+
+                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                    String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
+                    String packageName = intent.getPackage();
+                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+                } else {
+                    // Could be launching some bookkeeping activity
+                    ((Context) this).startActivity(intent, optsBundle);
+                }
+            } finally {
+                StrictMode.setVmPolicy(oldPolicy);
+            }
+        } catch (SecurityException e) {
+            if (!onErrorStartingShortcut(intent, info)) {
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * A wrapper around the platform method with Launcher specific checks.
+     */
+    default void startShortcut(String packageName, String id, Rect sourceBounds,
+            Bundle startActivityOptions, UserHandle user) {
+        if (GO_DISABLE_WIDGETS) {
+            return;
+        }
+        try {
+            ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id,
+                    sourceBounds, startActivityOptions, user);
+        } catch (SecurityException | IllegalStateException e) {
+            Log.e(TAG, "Failed to start shortcut", e);
+        }
+    }
+
+    /**
+     * Invoked when a shortcut fails to launch.
+     * @param intent Shortcut intent that failed to start.
+     * @param info Shortcut information.
+     * @return {@code true} if the error is handled by this callback.
+     */
+    default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
+        return false;
+    }
+
+    /**
+     * Returns the ActivityContext associated with the given Context, or throws an exception if
+     * the Context is not associated with any ActivityContext.
+     */
+    static <T extends Context & ActivityContext> T lookupContext(Context context) {
+        T activityContext = lookupContextNoThrow(context);
+        if (activityContext == null) {
+            throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
+        }
+        return activityContext;
+    }
+
+    /**
+     * Returns the ActivityContext associated with the given Context, or null if
+     * the Context is not associated with any ActivityContext.
+     */
+    static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
+        if (context instanceof ActivityContext) {
+            return (T) context;
+        } else if (context instanceof ContextWrapper) {
+            return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/views/AppLauncher.java b/src/com/android/launcher3/views/AppLauncher.java
deleted file mode 100644
index 19e66ab..0000000
--- a/src/com/android/launcher3/views/AppLauncher.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
-import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
-
-import android.app.ActivityOptions;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.StrictMode;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.Display;
-import android.view.View;
-import android.widget.Toast;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.logging.InstanceId;
-import com.android.launcher3.logging.InstanceIdSequence;
-import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.util.ActivityOptionsWrapper;
-import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.util.RunnableList;
-
-/** An {@link ActivityContext} that can also launch app activities and shortcuts safely. */
-public interface AppLauncher extends ActivityContext {
-
-    String TAG = "AppLauncher";
-
-    /**
-     * Safely starts an activity.
-     *
-     * @param v View starting the activity.
-     * @param intent Base intent being launched.
-     * @param item Item associated with the view.
-     * @return {@code true} if the activity starts successfully.
-     */
-    default boolean startActivitySafely(
-            View v, Intent intent, @Nullable ItemInfo item) {
-
-        Context context = (Context) this;
-        if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
-            Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
-            return false;
-        }
-
-        Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null;
-        UserHandle user = item == null ? null : item.user;
-
-        // Prepare intent
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        if (v != null) {
-            intent.setSourceBounds(Utilities.getViewBounds(v));
-        }
-        try {
-            boolean isShortcut = (item instanceof WorkspaceItemInfo)
-                    && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                    || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
-                    && !((WorkspaceItemInfo) item).isPromise();
-            if (isShortcut) {
-                // Shortcuts need some special checks due to legacy reasons.
-                startShortcutIntentSafely(intent, optsBundle, item);
-            } else if (user == null || user.equals(Process.myUserHandle())) {
-                // Could be launching some bookkeeping activity
-                context.startActivity(intent, optsBundle);
-            } else {
-                context.getSystemService(LauncherApps.class).startMainActivity(
-                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
-            }
-            if (item != null) {
-                InstanceId instanceId = new InstanceIdSequence().newInstanceId();
-                logAppLaunch(getStatsLogManager(), item, instanceId);
-            }
-            return true;
-        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
-            Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
-        }
-        return false;
-    }
-
-    /** Returns {@code true} if an app launch is blocked due to safe mode. */
-    default boolean isAppBlockedForSafeMode() {
-        return false;
-    }
-
-    /**
-     * Creates and logs a new app launch event.
-     */
-    default void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
-            InstanceId instanceId) {
-        statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId)
-                .log(LAUNCHER_APP_LAUNCH_TAP);
-    }
-
-    /**
-     * Returns launch options for an Activity.
-     *
-     * @param v View initiating a launch.
-     * @param item Item associated with the view.
-     */
-    default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
-        int left = 0, top = 0;
-        int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
-        if (v instanceof BubbleTextView) {
-            // Launch from center of icon, not entire view
-            Drawable icon = ((BubbleTextView) v).getIcon();
-            if (icon != null) {
-                Rect bounds = icon.getBounds();
-                left = (width - bounds.width()) / 2;
-                top = v.getPaddingTop();
-                width = bounds.width();
-                height = bounds.height();
-            }
-        }
-        ActivityOptions options =
-                ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
-
-        options.setLaunchDisplayId(
-                (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
-                        : Display.DEFAULT_DISPLAY);
-        RunnableList callback = new RunnableList();
-        return new ActivityOptionsWrapper(options, callback);
-    }
-
-    /**
-     * Safely launches an intent for a shortcut.
-     *
-     * @param intent Intent to start.
-     * @param optsBundle Optional launch arguments.
-     * @param info Shortcut information.
-     */
-    default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
-        try {
-            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
-            try {
-                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
-                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
-                // is enabled by default on NYC.
-                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
-                        .penaltyLog().build());
-
-                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                    String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
-                    String packageName = intent.getPackage();
-                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
-                } else {
-                    // Could be launching some bookkeeping activity
-                    ((Context) this).startActivity(intent, optsBundle);
-                }
-            } finally {
-                StrictMode.setVmPolicy(oldPolicy);
-            }
-        } catch (SecurityException e) {
-            if (!onErrorStartingShortcut(intent, info)) {
-                throw e;
-            }
-        }
-    }
-
-    /**
-     * A wrapper around the platform method with Launcher specific checks.
-     */
-    default void startShortcut(String packageName, String id, Rect sourceBounds,
-            Bundle startActivityOptions, UserHandle user) {
-        if (GO_DISABLE_WIDGETS) {
-            return;
-        }
-        try {
-            ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id,
-                    sourceBounds, startActivityOptions, user);
-        } catch (SecurityException | IllegalStateException e) {
-            Log.e(TAG, "Failed to start shortcut", e);
-        }
-    }
-
-    /**
-     * Invoked when a shortcut fails to launch.
-     * @param intent Shortcut intent that failed to start.
-     * @param info Shortcut information.
-     * @return {@code true} if the error is handled by this callback.
-     */
-    default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
-        return false;
-    }
-}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 622516f..5b57e22 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -139,12 +139,12 @@
         mTargetRect.roundOut(outPos);
     }
 
-    public static OptionsPopupView show(AppLauncher launcher, RectF targetRect,
+    public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
             List<OptionItem> items, boolean shouldAddArrow) {
         return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);
     }
 
-    public static OptionsPopupView show(AppLauncher launcher, RectF targetRect,
+    public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
             List<OptionItem> items, boolean shouldAddArrow, int width) {
         OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
                 .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);