diff --git a/lineage/res/res/anim/last_app_in.xml b/lineage/res/res/anim/last_app_in.xml
new file mode 100644
index 00000000..2a9285f5
--- /dev/null
+++ b/lineage/res/res/anim/last_app_in.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/lineage/res/res/anim/last_app_out.xml b/lineage/res/res/anim/last_app_out.xml
new file mode 100644
index 00000000..7c66c60f
--- /dev/null
+++ b/lineage/res/res/anim/last_app_out.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/lineage/res/res/values/symbols.xml b/lineage/res/res/values/symbols.xml
index a98ed572..ece15dfb 100644
--- a/lineage/res/res/values/symbols.xml
+++ b/lineage/res/res/values/symbols.xml
@@ -143,4 +143,8 @@
+
+
+
+
diff --git a/sdk/src/java/org/lineageos/internal/util/ActionUtils.java b/sdk/src/java/org/lineageos/internal/util/ActionUtils.java
new file mode 100644
index 00000000..c00cc175
--- /dev/null
+++ b/sdk/src/java/org/lineageos/internal/util/ActionUtils.java
@@ -0,0 +1,149 @@
+package org.lineageos.internal.util;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.widget.Toast;
+
+import org.lineageos.platform.internal.R;
+
+import java.util.List;
+
+public class ActionUtils {
+ private static final boolean DEBUG = false;
+ private static final String TAG = ActionUtils.class.getSimpleName();
+ private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+ /**
+ * Kills the top most / most recent user application, but leaves out the launcher.
+ * This is function governed by {@link Settings.Secure.KILL_APP_LONGPRESS_BACK}.
+ *
+ * @param context the current context, used to retrieve the package manager.
+ * @param userId the ID of the currently active user
+ * @return {@code true} when a user application was found and closed.
+ */
+ public static boolean killForegroundApp(Context context, int userId) {
+ try {
+ return killForegroundAppInternal(context, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not kill foreground app");
+ }
+ return false;
+ }
+
+ private static boolean killForegroundAppInternal(Context context, int userId)
+ throws RemoteException {
+ try {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ String defaultHomePackage = "com.android.launcher";
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0);
+
+ if (res.activityInfo != null && !res.activityInfo.packageName.equals("android")) {
+ defaultHomePackage = res.activityInfo.packageName;
+ }
+
+ IActivityManager am = ActivityManagerNative.getDefault();
+ List apps = am.getRunningAppProcesses();
+ for (ActivityManager.RunningAppProcessInfo appInfo : apps) {
+ int uid = appInfo.uid;
+ // Make sure it's a foreground user application (not system,
+ // root, phone, etc.)
+ if (uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID
+ && appInfo.importance ==
+ ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ if (appInfo.pkgList != null && (appInfo.pkgList.length > 0)) {
+ for (String pkg : appInfo.pkgList) {
+ if (!pkg.equals(SYSTEMUI_PACKAGE)
+ && !pkg.equals(defaultHomePackage)) {
+ am.forceStopPackage(pkg, UserHandle.USER_CURRENT);
+ return true;
+ }
+ }
+ } else {
+ Process.killProcess(appInfo.pid);
+ return true;
+ }
+ }
+ }
+ } catch (RemoteException remoteException) {
+ // Do nothing; just let it go.
+ }
+ return false;
+ }
+
+ /**
+ * Attempt to bring up the last activity in the stack before the current active one.
+ *
+ * @param context
+ * @return whether an activity was found to switch to
+ */
+ public static boolean switchToLastApp(Context context, int userId) {
+ try {
+ return switchToLastAppInternal(context, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not switch to last app");
+ }
+ return false;
+ }
+
+ private static boolean switchToLastAppInternal(Context context, int userId)
+ throws RemoteException {
+ ActivityManager.RecentTaskInfo lastTask = getLastTask(context, userId);
+
+ if (lastTask == null || lastTask.id < 0) {
+ return false;
+ }
+
+ final String packageName = lastTask.baseIntent.getComponent().getPackageName();
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final ActivityOptions opts = ActivityOptions.makeCustomAnimation(context,
+ org.lineageos.platform.internal.R.anim.last_app_in,
+ org.lineageos.platform.internal.R.anim.last_app_out);
+
+ if (DEBUG) Log.d(TAG, "switching to " + packageName);
+ am.moveTaskToFront(lastTask.id, ActivityManager.MOVE_TASK_NO_USER_ACTION, opts.toBundle());
+
+ return true;
+ }
+
+ private static ActivityManager.RecentTaskInfo getLastTask(Context context, int userId)
+ throws RemoteException {
+ final String defaultHomePackage = resolveCurrentLauncherPackage(context, userId);
+ final ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ final List tasks = am.getRecentTasksForUser(5,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE, userId);
+
+ for (int i = 1; i < tasks.size(); i++) {
+ ActivityManager.RecentTaskInfo task = tasks.get(i);
+ if (task.origActivity != null) {
+ task.baseIntent.setComponent(task.origActivity);
+ }
+ String packageName = task.baseIntent.getComponent().getPackageName();
+ if (!packageName.equals(defaultHomePackage)
+ && !packageName.equals(SYSTEMUI_PACKAGE)) {
+ return tasks.get(i);
+ }
+ }
+
+ return null;
+ }
+
+ private static String resolveCurrentLauncherPackage(Context context, int userId) {
+ final Intent launcherIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME);
+ final PackageManager pm = context.getPackageManager();
+ final ResolveInfo launcherInfo = pm.resolveActivityAsUser(launcherIntent, 0, userId);
+ return launcherInfo.activityInfo.packageName;
+ }
+}