Merge "Use already-running app instances when splitting" into tm-qpr-dev

This commit is contained in:
Jeremy Sim
2022-12-13 18:21:12 +00:00
committed by Android (Google) Code Review
5 changed files with 137 additions and 47 deletions

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
);
}
}

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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);
}
/**