mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-04 09:56:49 +00:00
Merge "Use already-running app instances when splitting" into tm-qpr-dev
This commit is contained in:
@@ -30,6 +30,8 @@ import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
@@ -41,6 +43,9 @@ import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
|
||||
import com.android.quickstep.util.SplitSelectStateController;
|
||||
import com.android.quickstep.views.FloatingTaskView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface QuickstepSystemShortcut {
|
||||
|
||||
@@ -93,14 +98,22 @@ public interface QuickstepSystemShortcut {
|
||||
}
|
||||
|
||||
StatsLogManager.EventEnum splitEvent = getLogEventForPosition(mPosition.stagePosition);
|
||||
SplitSelectSource source = new SplitSelectSource(mOriginalView,
|
||||
new BitmapDrawable(bitmap), intent, mPosition, mItemInfo, splitEvent);
|
||||
if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
|
||||
startSplitToHome(source);
|
||||
} else {
|
||||
RecentsView recentsView = mTarget.getOverviewPanel();
|
||||
recentsView.initiateSplitSelect(source);
|
||||
}
|
||||
RecentsView recentsView = mTarget.getOverviewPanel();
|
||||
// Check if there is already an instance of this app running, if so, initiate the split
|
||||
// using that.
|
||||
recentsView.findLastActiveTaskAndDoSplitOperation(
|
||||
intent.getComponent(),
|
||||
(Consumer<Task>) foundTask -> {
|
||||
SplitSelectSource source = new SplitSelectSource(mOriginalView,
|
||||
new BitmapDrawable(bitmap), intent, mPosition, mItemInfo,
|
||||
splitEvent, foundTask);
|
||||
if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
|
||||
startSplitToHome(source);
|
||||
} else {
|
||||
recentsView.initiateSplitSelect(source);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void startSplitToHome(SplitSelectSource source) {
|
||||
@@ -108,7 +121,7 @@ public interface QuickstepSystemShortcut {
|
||||
|
||||
SplitSelectStateController controller = mTarget.getSplitSelectStateController();
|
||||
controller.setInitialTaskSelect(source.intent, source.position.stagePosition,
|
||||
source.itemInfo, source.splitEvent);
|
||||
source.itemInfo, source.splitEvent, source.alreadyRunningTask);
|
||||
|
||||
RecentsView recentsView = mTarget.getOverviewPanel();
|
||||
recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
|
||||
@@ -142,16 +155,19 @@ public interface QuickstepSystemShortcut {
|
||||
public final SplitPositionOption position;
|
||||
public final ItemInfo itemInfo;
|
||||
public final StatsLogManager.EventEnum splitEvent;
|
||||
@Nullable
|
||||
public final Task alreadyRunningTask;
|
||||
|
||||
public SplitSelectSource(View view, Drawable drawable, Intent intent,
|
||||
SplitPositionOption position, ItemInfo itemInfo,
|
||||
StatsLogManager.EventEnum splitEvent) {
|
||||
StatsLogManager.EventEnum splitEvent, @Nullable Task foundTask) {
|
||||
this.view = view;
|
||||
this.drawable = drawable;
|
||||
this.intent = intent;
|
||||
this.position = position;
|
||||
this.itemInfo = itemInfo;
|
||||
this.splitEvent = splitEvent;
|
||||
this.alreadyRunningTask = foundTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,10 @@ import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Base class for providing different taskbar UI
|
||||
@@ -160,23 +162,30 @@ public class TaskbarUIController {
|
||||
*/
|
||||
public void triggerSecondAppForSplit(ItemInfoWithIcon info, Intent intent, View startingView) {
|
||||
RecentsView recents = getRecentsView();
|
||||
TaskView foundTaskView = recents.getTaskViewByComponentName(info.getTargetComponent());
|
||||
if (foundTaskView != null) {
|
||||
recents.confirmSplitSelect(
|
||||
foundTaskView,
|
||||
foundTaskView.getTask(),
|
||||
foundTaskView.getIconView().getDrawable(),
|
||||
foundTaskView.getThumbnail(),
|
||||
foundTaskView.getThumbnail().getThumbnail(),
|
||||
/* intent */ null);
|
||||
} else {
|
||||
recents.confirmSplitSelect(
|
||||
/* containerTaskView */ null,
|
||||
/* task */ null,
|
||||
new BitmapDrawable(info.bitmap.icon),
|
||||
startingView,
|
||||
/* thumbnail */ null,
|
||||
intent);
|
||||
}
|
||||
recents.findLastActiveTaskAndDoSplitOperation(
|
||||
info.getTargetComponent(),
|
||||
(Consumer<Task>) foundTask -> {
|
||||
if (foundTask != null) {
|
||||
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
|
||||
// There is already a running app of this type, use that as second app.
|
||||
recents.confirmSplitSelect(
|
||||
foundTaskView,
|
||||
foundTaskView.getTask(),
|
||||
foundTaskView.getIconView().getDrawable(),
|
||||
foundTaskView.getThumbnail(),
|
||||
foundTaskView.getThumbnail().getThumbnail(),
|
||||
null /* intent */);
|
||||
} else {
|
||||
// No running app of that type, create a new instance as second app.
|
||||
recents.confirmSplitSelect(
|
||||
null /* containerTaskView */,
|
||||
null /* task */,
|
||||
new BitmapDrawable(info.bitmap.icon),
|
||||
startingView,
|
||||
null /* thumbnail */,
|
||||
intent);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,8 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the list of recent tasks.
|
||||
* Fetches the list of recent tasks. Tasks are ordered by recency, with the latest active tasks
|
||||
* at the end of the list.
|
||||
*
|
||||
* @param callback The callback to receive the task plan once its complete or null. This is
|
||||
* always called on the UI thread.
|
||||
|
||||
@@ -37,7 +37,6 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
@@ -124,10 +123,15 @@ public class SplitSelectStateController {
|
||||
* To be called after first task selected from home or all apps.
|
||||
*/
|
||||
public void setInitialTaskSelect(Intent intent, @StagePosition int stagePosition,
|
||||
@NonNull ItemInfo itemInfo, StatsLogManager.EventEnum splitEvent) {
|
||||
mInitialTaskIntent = intent;
|
||||
mUser = itemInfo.user;
|
||||
mItemInfo = itemInfo;
|
||||
@NonNull ItemInfo itemInfo, StatsLogManager.EventEnum splitEvent,
|
||||
@Nullable Task alreadyRunningTask) {
|
||||
if (alreadyRunningTask != null) {
|
||||
mInitialTaskId = alreadyRunningTask.key.id;
|
||||
} else {
|
||||
mInitialTaskIntent = intent;
|
||||
mUser = itemInfo.user;
|
||||
}
|
||||
|
||||
setInitialData(stagePosition, splitEvent, itemInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -1221,18 +1221,50 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link TaskView} that has ComponentName matching {@code componentName} or null if
|
||||
* no match.
|
||||
* Pulls the list of active Tasks from RecentModel, and finds the most recently active Task
|
||||
* matching a given ComponentName. Then uses that Task (which could be null) with the given
|
||||
* callback.
|
||||
*
|
||||
* Used in various splitscreen operations when we need to check if there is a currently running
|
||||
* Task of a certain type and use the most recent one.
|
||||
*/
|
||||
@Nullable
|
||||
public TaskView getTaskViewByComponentName(ComponentName componentName) {
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView taskView = requireTaskViewAt(i);
|
||||
if (taskView.getTask().key.sourceComponent.equals(componentName)) {
|
||||
return taskView;
|
||||
public void findLastActiveTaskAndDoSplitOperation(ComponentName componentName,
|
||||
Consumer<Task> callback) {
|
||||
mModel.getTasks(taskGroups -> {
|
||||
Task lastActiveTask = null;
|
||||
// Loop through tasks in reverse, since they are ordered with most-recent tasks last.
|
||||
for (int i = taskGroups.size() - 1; i >= 0; i--) {
|
||||
GroupTask groupTask = taskGroups.get(i);
|
||||
Task task1 = groupTask.task1;
|
||||
if (isInstanceOfComponent(task1, componentName)) {
|
||||
lastActiveTask = task1;
|
||||
break;
|
||||
}
|
||||
Task task2 = groupTask.task2;
|
||||
if (isInstanceOfComponent(task2, componentName)) {
|
||||
lastActiveTask = task2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
callback.accept(lastActiveTask);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given Task is the most recently-active Task of type componentName. Used for
|
||||
* selecting already-running Tasks for splitscreen.
|
||||
*/
|
||||
public boolean isInstanceOfComponent(@Nullable Task task, ComponentName componentName) {
|
||||
if (task == null) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
// Exclude the task that is already staged
|
||||
if (mSplitHiddenTaskView != null && mSplitHiddenTaskView.getTask().equals(task)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return task.key.baseIntent.getComponent().equals(componentName);
|
||||
}
|
||||
|
||||
public void setOverviewStateEnabled(boolean enabled) {
|
||||
@@ -1509,13 +1541,41 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
int previousCurrentPage = mCurrentPage;
|
||||
removeAllViews();
|
||||
|
||||
// Add views as children based on whether it's grouped or single task
|
||||
// If we are entering Overview as a result of initiating a split from somewhere else
|
||||
// (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail.
|
||||
Task stagedTaskToBeRemovedFromGrid =
|
||||
mSplitSelectSource != null ? mSplitSelectSource.alreadyRunningTask : null;
|
||||
|
||||
// Add views as children based on whether it's grouped or single task. Looping through
|
||||
// taskGroups backwards populates the thumbnail grid from least recent to most recent.
|
||||
for (int i = taskGroups.size() - 1; i >= 0; i--) {
|
||||
GroupTask groupTask = taskGroups.get(i);
|
||||
TaskView taskView = getTaskViewFromPool(groupTask.taskViewType);
|
||||
boolean isRemovalNeeded = stagedTaskToBeRemovedFromGrid != null
|
||||
&& groupTask.containsTask(stagedTaskToBeRemovedFromGrid.key.id);
|
||||
|
||||
TaskView taskView;
|
||||
if (isRemovalNeeded && groupTask.hasMultipleTasks()) {
|
||||
// If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE
|
||||
// to be a temporary container for the remaining task.
|
||||
taskView = getTaskViewFromPool(TaskView.Type.SINGLE);
|
||||
} else {
|
||||
taskView = getTaskViewFromPool(groupTask.taskViewType);
|
||||
}
|
||||
|
||||
addView(taskView);
|
||||
|
||||
if (taskView instanceof GroupedTaskView) {
|
||||
if (isRemovalNeeded && groupTask.hasMultipleTasks()) {
|
||||
if (groupTask.task1.equals(stagedTaskToBeRemovedFromGrid)) {
|
||||
taskView.bind(groupTask.task2, mOrientationState);
|
||||
} else {
|
||||
taskView.bind(groupTask.task1, mOrientationState);
|
||||
}
|
||||
} else if (isRemovalNeeded) {
|
||||
// If the task we need to remove is not part of a pair, bind it to the TaskView
|
||||
// first (to prevent problems), then remove the whole thing.
|
||||
taskView.bind(groupTask.task1, mOrientationState);
|
||||
removeView(taskView);
|
||||
} else if (taskView instanceof GroupedTaskView) {
|
||||
boolean firstTaskIsLeftTopTask =
|
||||
groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
|
||||
Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
|
||||
@@ -4269,7 +4329,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
mSplitSelectSource = splitSelectSource;
|
||||
mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
|
||||
splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
|
||||
splitSelectSource.splitEvent);
|
||||
splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTask);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user