Merge "Add shell recents interface" into sc-v2-dev am: df857527f5
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16069114 Change-Id: Iaa15cb5de5dd86457bc74a0e26e51dad51961930
This commit is contained in:
@@ -38,6 +38,7 @@ filegroup {
|
|||||||
path: "src",
|
path: "src",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sources that have no dependencies that can be used directly downstream of this library
|
||||||
filegroup {
|
filegroup {
|
||||||
name: "wm_shell_util-sources",
|
name: "wm_shell_util-sources",
|
||||||
srcs: [
|
srcs: [
|
||||||
@@ -46,6 +47,7 @@ filegroup {
|
|||||||
path: "src",
|
path: "src",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aidls which can be used directly downstream of this library
|
||||||
filegroup {
|
filegroup {
|
||||||
name: "wm_shell-aidls",
|
name: "wm_shell-aidls",
|
||||||
srcs: [
|
srcs: [
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
|
|||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||||
import com.android.wm.shell.onehanded.OneHandedController;
|
import com.android.wm.shell.onehanded.OneHandedController;
|
||||||
import com.android.wm.shell.pip.Pip;
|
import com.android.wm.shell.pip.Pip;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -43,6 +44,7 @@ public final class ShellCommandHandlerImpl {
|
|||||||
private final Optional<OneHandedController> mOneHandedOptional;
|
private final Optional<OneHandedController> mOneHandedOptional;
|
||||||
private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
|
private final Optional<HideDisplayCutoutController> mHideDisplayCutout;
|
||||||
private final Optional<AppPairsController> mAppPairsOptional;
|
private final Optional<AppPairsController> mAppPairsOptional;
|
||||||
|
private final Optional<RecentTasksController> mRecentTasks;
|
||||||
private final ShellTaskOrganizer mShellTaskOrganizer;
|
private final ShellTaskOrganizer mShellTaskOrganizer;
|
||||||
private final ShellExecutor mMainExecutor;
|
private final ShellExecutor mMainExecutor;
|
||||||
private final HandlerImpl mImpl = new HandlerImpl();
|
private final HandlerImpl mImpl = new HandlerImpl();
|
||||||
@@ -55,8 +57,10 @@ public final class ShellCommandHandlerImpl {
|
|||||||
Optional<OneHandedController> oneHandedOptional,
|
Optional<OneHandedController> oneHandedOptional,
|
||||||
Optional<HideDisplayCutoutController> hideDisplayCutout,
|
Optional<HideDisplayCutoutController> hideDisplayCutout,
|
||||||
Optional<AppPairsController> appPairsOptional,
|
Optional<AppPairsController> appPairsOptional,
|
||||||
|
Optional<RecentTasksController> recentTasks,
|
||||||
ShellExecutor mainExecutor) {
|
ShellExecutor mainExecutor) {
|
||||||
mShellTaskOrganizer = shellTaskOrganizer;
|
mShellTaskOrganizer = shellTaskOrganizer;
|
||||||
|
mRecentTasks = recentTasks;
|
||||||
mLegacySplitScreenOptional = legacySplitScreenOptional;
|
mLegacySplitScreenOptional = legacySplitScreenOptional;
|
||||||
mSplitScreenOptional = splitScreenOptional;
|
mSplitScreenOptional = splitScreenOptional;
|
||||||
mPipOptional = pipOptional;
|
mPipOptional = pipOptional;
|
||||||
@@ -85,6 +89,9 @@ public final class ShellCommandHandlerImpl {
|
|||||||
pw.println();
|
pw.println();
|
||||||
pw.println();
|
pw.println();
|
||||||
mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
|
mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw, ""));
|
||||||
|
pw.println();
|
||||||
|
pw.println();
|
||||||
|
mRecentTasks.ifPresent(recentTasks -> recentTasks.dump(pw, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
|
|||||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||||
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
|
||||||
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
|
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
|
||||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
import com.android.wm.shell.startingsurface.StartingWindowController;
|
import com.android.wm.shell.startingsurface.StartingWindowController;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
import com.android.wm.shell.transition.Transitions;
|
||||||
@@ -49,7 +49,6 @@ public class ShellInitImpl {
|
|||||||
private final DragAndDropController mDragAndDropController;
|
private final DragAndDropController mDragAndDropController;
|
||||||
private final ShellTaskOrganizer mShellTaskOrganizer;
|
private final ShellTaskOrganizer mShellTaskOrganizer;
|
||||||
private final Optional<BubbleController> mBubblesOptional;
|
private final Optional<BubbleController> mBubblesOptional;
|
||||||
private final Optional<LegacySplitScreenController> mLegacySplitScreenOptional;
|
|
||||||
private final Optional<SplitScreenController> mSplitScreenOptional;
|
private final Optional<SplitScreenController> mSplitScreenOptional;
|
||||||
private final Optional<AppPairsController> mAppPairsOptional;
|
private final Optional<AppPairsController> mAppPairsOptional;
|
||||||
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
|
private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
|
||||||
@@ -59,6 +58,7 @@ public class ShellInitImpl {
|
|||||||
private final ShellExecutor mMainExecutor;
|
private final ShellExecutor mMainExecutor;
|
||||||
private final Transitions mTransitions;
|
private final Transitions mTransitions;
|
||||||
private final StartingWindowController mStartingWindow;
|
private final StartingWindowController mStartingWindow;
|
||||||
|
private final Optional<RecentTasksController> mRecentTasks;
|
||||||
|
|
||||||
private final InitImpl mImpl = new InitImpl();
|
private final InitImpl mImpl = new InitImpl();
|
||||||
|
|
||||||
@@ -69,13 +69,13 @@ public class ShellInitImpl {
|
|||||||
DragAndDropController dragAndDropController,
|
DragAndDropController dragAndDropController,
|
||||||
ShellTaskOrganizer shellTaskOrganizer,
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
Optional<BubbleController> bubblesOptional,
|
Optional<BubbleController> bubblesOptional,
|
||||||
Optional<LegacySplitScreenController> legacySplitScreenOptional,
|
|
||||||
Optional<SplitScreenController> splitScreenOptional,
|
Optional<SplitScreenController> splitScreenOptional,
|
||||||
Optional<AppPairsController> appPairsOptional,
|
Optional<AppPairsController> appPairsOptional,
|
||||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||||
FullscreenTaskListener fullscreenTaskListener,
|
FullscreenTaskListener fullscreenTaskListener,
|
||||||
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
|
Optional<FullscreenUnfoldController> fullscreenUnfoldTransitionController,
|
||||||
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
|
Optional<Optional<FreeformTaskListener>> freeformTaskListenerOptional,
|
||||||
|
Optional<RecentTasksController> recentTasks,
|
||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
StartingWindowController startingWindow,
|
StartingWindowController startingWindow,
|
||||||
ShellExecutor mainExecutor) {
|
ShellExecutor mainExecutor) {
|
||||||
@@ -85,13 +85,13 @@ public class ShellInitImpl {
|
|||||||
mDragAndDropController = dragAndDropController;
|
mDragAndDropController = dragAndDropController;
|
||||||
mShellTaskOrganizer = shellTaskOrganizer;
|
mShellTaskOrganizer = shellTaskOrganizer;
|
||||||
mBubblesOptional = bubblesOptional;
|
mBubblesOptional = bubblesOptional;
|
||||||
mLegacySplitScreenOptional = legacySplitScreenOptional;
|
|
||||||
mSplitScreenOptional = splitScreenOptional;
|
mSplitScreenOptional = splitScreenOptional;
|
||||||
mAppPairsOptional = appPairsOptional;
|
mAppPairsOptional = appPairsOptional;
|
||||||
mFullscreenTaskListener = fullscreenTaskListener;
|
mFullscreenTaskListener = fullscreenTaskListener;
|
||||||
mPipTouchHandlerOptional = pipTouchHandlerOptional;
|
mPipTouchHandlerOptional = pipTouchHandlerOptional;
|
||||||
mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
|
mFullscreenUnfoldController = fullscreenUnfoldTransitionController;
|
||||||
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
|
mFreeformTaskListenerOptional = freeformTaskListenerOptional.flatMap(f -> f);
|
||||||
|
mRecentTasks = recentTasks;
|
||||||
mTransitions = transitions;
|
mTransitions = transitions;
|
||||||
mMainExecutor = mainExecutor;
|
mMainExecutor = mainExecutor;
|
||||||
mStartingWindow = startingWindow;
|
mStartingWindow = startingWindow;
|
||||||
@@ -135,6 +135,7 @@ public class ShellInitImpl {
|
|||||||
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
f, ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM));
|
||||||
|
|
||||||
mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
|
mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
|
||||||
|
mRecentTasks.ifPresent(RecentTasksController::init);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExternalThread
|
@ExternalThread
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import com.android.internal.protolog.common.ProtoLog;
|
|||||||
import com.android.internal.util.FrameworkStatsLog;
|
import com.android.internal.util.FrameworkStatsLog;
|
||||||
import com.android.wm.shell.common.ScreenshotUtils;
|
import com.android.wm.shell.common.ScreenshotUtils;
|
||||||
import com.android.wm.shell.common.ShellExecutor;
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
||||||
import com.android.wm.shell.startingsurface.StartingWindowController;
|
import com.android.wm.shell.startingsurface.StartingWindowController;
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,20 +152,34 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final SizeCompatUIController mSizeCompatUI;
|
private final SizeCompatUIController mSizeCompatUI;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Optional<RecentTasksController> mRecentTasks;
|
||||||
|
|
||||||
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
|
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
|
||||||
this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */);
|
this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
|
||||||
|
Optional.empty() /* recentTasksController */);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
|
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
|
||||||
SizeCompatUIController sizeCompatUI) {
|
SizeCompatUIController sizeCompatUI) {
|
||||||
this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI);
|
this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
|
||||||
|
Optional.empty() /* recentTasksController */);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
|
||||||
|
SizeCompatUIController sizeCompatUI,
|
||||||
|
Optional<RecentTasksController> recentTasks) {
|
||||||
|
this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
|
||||||
|
recentTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
|
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
|
||||||
Context context, @Nullable SizeCompatUIController sizeCompatUI) {
|
Context context, @Nullable SizeCompatUIController sizeCompatUI,
|
||||||
|
Optional<RecentTasksController> recentTasks) {
|
||||||
super(taskOrganizerController, mainExecutor);
|
super(taskOrganizerController, mainExecutor);
|
||||||
mSizeCompatUI = sizeCompatUI;
|
mSizeCompatUI = sizeCompatUI;
|
||||||
|
mRecentTasks = recentTasks;
|
||||||
if (sizeCompatUI != null) {
|
if (sizeCompatUI != null) {
|
||||||
sizeCompatUI.setSizeCompatUICallback(this);
|
sizeCompatUI.setSizeCompatUICallback(this);
|
||||||
}
|
}
|
||||||
@@ -401,6 +417,11 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
|||||||
// Notify the size compat UI if the listener or task info changed.
|
// Notify the size compat UI if the listener or task info changed.
|
||||||
notifySizeCompatUI(taskInfo, newListener);
|
notifySizeCompatUI(taskInfo, newListener);
|
||||||
}
|
}
|
||||||
|
if (data.getTaskInfo().getWindowingMode() != taskInfo.getWindowingMode()) {
|
||||||
|
// Notify the recent tasks when a task changes windowing modes
|
||||||
|
mRecentTasks.ifPresent(recentTasks ->
|
||||||
|
recentTasks.onTaskWindowingModeChanged(taskInfo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,6 +449,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
|
|||||||
notifyLocusVisibilityIfNeeded(taskInfo);
|
notifyLocusVisibilityIfNeeded(taskInfo);
|
||||||
// Pass null for listener to remove the size compat UI on this task if there is any.
|
// Pass null for listener to remove the size compat UI on this task if there is any.
|
||||||
notifySizeCompatUI(taskInfo, null /* taskListener */);
|
notifySizeCompatUI(taskInfo, null /* taskListener */);
|
||||||
|
// Notify the recent tasks that a task has been removed
|
||||||
|
mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskRemoved(taskInfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.recents;
|
||||||
|
|
||||||
|
import com.android.wm.shell.recents.IRecentTasksListener;
|
||||||
|
import com.android.wm.shell.util.GroupedRecentTaskInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that is exposed to remote callers to fetch recent tasks.
|
||||||
|
*/
|
||||||
|
interface IRecentTasks {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a recent tasks listener.
|
||||||
|
*/
|
||||||
|
oneway void registerRecentTasksListener(in IRecentTasksListener listener) = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a recent tasks listener.
|
||||||
|
*/
|
||||||
|
oneway void unregisterRecentTasksListener(in IRecentTasksListener listener) = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of recent tasks.
|
||||||
|
*/
|
||||||
|
GroupedRecentTaskInfo[] getRecentTasks(int maxNum, int flags, int userId) = 3;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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 distshellributed 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.wm.shell.recents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
|
||||||
|
*/
|
||||||
|
oneway interface IRecentTasksListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the set of recent tasks change.
|
||||||
|
*/
|
||||||
|
void onRecentTasksChanged();
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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.wm.shell.recents;
|
||||||
|
|
||||||
|
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for interacting with the recent tasks.
|
||||||
|
*/
|
||||||
|
@ExternalThread
|
||||||
|
public interface RecentTasks {
|
||||||
|
/**
|
||||||
|
* Returns a binder that can be passed to an external process to fetch recent tasks.
|
||||||
|
*/
|
||||||
|
default IRecentTasks createExternalInterface() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.recents;
|
||||||
|
|
||||||
|
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||||
|
|
||||||
|
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.ActivityTaskManager;
|
||||||
|
import android.app.TaskInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
|
import androidx.annotation.BinderThread;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.wm.shell.common.RemoteCallable;
|
||||||
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
import com.android.wm.shell.common.SingleInstanceRemoteListener;
|
||||||
|
import com.android.wm.shell.common.TaskStackListenerCallback;
|
||||||
|
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||||
|
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||||
|
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||||
|
import com.android.wm.shell.util.GroupedRecentTaskInfo;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the recent task list from the system, caching it as necessary.
|
||||||
|
*/
|
||||||
|
public class RecentTasksController implements TaskStackListenerCallback,
|
||||||
|
RemoteCallable<RecentTasksController> {
|
||||||
|
private static final String TAG = RecentTasksController.class.getSimpleName();
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final ShellExecutor mMainExecutor;
|
||||||
|
private final TaskStackListenerImpl mTaskStackListener;
|
||||||
|
private final RecentTasks mImpl = new RecentTasksImpl();
|
||||||
|
|
||||||
|
private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
|
||||||
|
// Mapping of split task ids, mappings are symmetrical (ie. if t1 is the taskid of a task in a
|
||||||
|
// pair, then mSplitTasks[t1] = t2, and mSplitTasks[t2] = t1)
|
||||||
|
private final SparseIntArray mSplitTasks = new SparseIntArray();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link RecentTasksController}, returns {@code null} if the feature is not
|
||||||
|
* supported.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static RecentTasksController create(
|
||||||
|
Context context,
|
||||||
|
TaskStackListenerImpl taskStackListener,
|
||||||
|
@ShellMainThread ShellExecutor mainExecutor
|
||||||
|
) {
|
||||||
|
if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new RecentTasksController(context, taskStackListener, mainExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecentTasksController(Context context, TaskStackListenerImpl taskStackListener,
|
||||||
|
ShellExecutor mainExecutor) {
|
||||||
|
mContext = context;
|
||||||
|
mTaskStackListener = taskStackListener;
|
||||||
|
mMainExecutor = mainExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecentTasks asRecentTasks() {
|
||||||
|
return mImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
mTaskStackListener.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a split pair. This call does not validate the taskIds, only that they are not the same.
|
||||||
|
*/
|
||||||
|
public void addSplitPair(int taskId1, int taskId2) {
|
||||||
|
if (taskId1 == taskId2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Remove any previous pairs
|
||||||
|
removeSplitPair(taskId1);
|
||||||
|
removeSplitPair(taskId2);
|
||||||
|
mSplitTasks.put(taskId1, taskId2);
|
||||||
|
mSplitTasks.put(taskId2, taskId1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a split pair.
|
||||||
|
*/
|
||||||
|
public void removeSplitPair(int taskId) {
|
||||||
|
int pairedTaskId = mSplitTasks.get(taskId, INVALID_TASK_ID);
|
||||||
|
if (pairedTaskId != INVALID_TASK_ID) {
|
||||||
|
mSplitTasks.delete(taskId);
|
||||||
|
mSplitTasks.delete(pairedTaskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Context getContext() {
|
||||||
|
return mContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShellExecutor getRemoteCallExecutor() {
|
||||||
|
return mMainExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskStackChanged() {
|
||||||
|
notifyRecentTasksChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRecentTaskListUpdated() {
|
||||||
|
// In some cases immediately after booting, the tasks in the system recent task list may be
|
||||||
|
// loaded, but not in the active task hierarchy in the system. These tasks are displayed in
|
||||||
|
// overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
|
||||||
|
// callback (those are for changes to the active tasks), but the task list is still updated,
|
||||||
|
// so we should also invalidate the change id to ensure we load a new list instead of
|
||||||
|
// reusing a stale list.
|
||||||
|
notifyRecentTasksChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTaskRemoved(TaskInfo taskInfo) {
|
||||||
|
// Remove any split pairs associated with this task
|
||||||
|
removeSplitPair(taskInfo.taskId);
|
||||||
|
notifyRecentTasksChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onTaskWindowingModeChanged(TaskInfo taskInfo) {
|
||||||
|
notifyRecentTasksChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void notifyRecentTasksChanged() {
|
||||||
|
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||||
|
mCallbacks.get(i).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerRecentTasksListener(Runnable listener) {
|
||||||
|
if (!mCallbacks.contains(listener)) {
|
||||||
|
mCallbacks.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterRecentTasksListener(Runnable listener) {
|
||||||
|
mCallbacks.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
List<ActivityManager.RecentTaskInfo> getRawRecentTasks(int maxNum, int flags, int userId) {
|
||||||
|
return ActivityTaskManager.getInstance().getRecentTasks(maxNum, flags, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
ArrayList<GroupedRecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
|
||||||
|
// Note: the returned task list is from the most-recent to least-recent order
|
||||||
|
final List<ActivityManager.RecentTaskInfo> rawList = getRawRecentTasks(maxNum, flags,
|
||||||
|
userId);
|
||||||
|
|
||||||
|
// Make a mapping of task id -> task info
|
||||||
|
final SparseArray<ActivityManager.RecentTaskInfo> rawMapping = new SparseArray<>();
|
||||||
|
for (int i = 0; i < rawList.size(); i++) {
|
||||||
|
final ActivityManager.RecentTaskInfo taskInfo = rawList.get(i);
|
||||||
|
rawMapping.put(taskInfo.taskId, taskInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull out the pairs as we iterate back in the list
|
||||||
|
ArrayList<GroupedRecentTaskInfo> recentTasks = new ArrayList<>();
|
||||||
|
for (int i = 0; i < rawList.size(); i++) {
|
||||||
|
final ActivityManager.RecentTaskInfo taskInfo = rawList.get(i);
|
||||||
|
if (!rawMapping.contains(taskInfo.taskId)) {
|
||||||
|
// If it's not in the mapping, then it was already paired with another task
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
|
||||||
|
if (pairedTaskId != INVALID_TASK_ID) {
|
||||||
|
final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
|
||||||
|
rawMapping.remove(pairedTaskId);
|
||||||
|
recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo));
|
||||||
|
} else {
|
||||||
|
recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recentTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump(@NonNull PrintWriter pw, String prefix) {
|
||||||
|
final String innerPrefix = prefix + " ";
|
||||||
|
pw.println(prefix + TAG);
|
||||||
|
ArrayList<GroupedRecentTaskInfo> recentTasks = getRecentTasks(Integer.MAX_VALUE,
|
||||||
|
ActivityManager.RECENT_IGNORE_UNAVAILABLE, ActivityManager.getCurrentUser());
|
||||||
|
for (int i = 0; i < recentTasks.size(); i++) {
|
||||||
|
pw.println(innerPrefix + recentTasks.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface for calls from outside the Shell, within the host process.
|
||||||
|
*/
|
||||||
|
@ExternalThread
|
||||||
|
private class RecentTasksImpl implements RecentTasks {
|
||||||
|
private IRecentTasksImpl mIRecentTasks;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IRecentTasks createExternalInterface() {
|
||||||
|
if (mIRecentTasks != null) {
|
||||||
|
mIRecentTasks.invalidate();
|
||||||
|
}
|
||||||
|
mIRecentTasks = new IRecentTasksImpl(RecentTasksController.this);
|
||||||
|
return mIRecentTasks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface for calls from outside the host process.
|
||||||
|
*/
|
||||||
|
@BinderThread
|
||||||
|
private static class IRecentTasksImpl extends IRecentTasks.Stub {
|
||||||
|
private RecentTasksController mController;
|
||||||
|
private final SingleInstanceRemoteListener<RecentTasksController,
|
||||||
|
IRecentTasksListener> mListener;
|
||||||
|
private final Runnable mRecentTasksListener =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mListener.call(l -> l.onRecentTasksChanged());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public IRecentTasksImpl(RecentTasksController controller) {
|
||||||
|
mController = controller;
|
||||||
|
mListener = new SingleInstanceRemoteListener<>(controller,
|
||||||
|
c -> c.registerRecentTasksListener(mRecentTasksListener),
|
||||||
|
c -> c.unregisterRecentTasksListener(mRecentTasksListener));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates this instance, preventing future calls from updating the controller.
|
||||||
|
*/
|
||||||
|
void invalidate() {
|
||||||
|
mController = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerRecentTasksListener(IRecentTasksListener listener)
|
||||||
|
throws RemoteException {
|
||||||
|
executeRemoteCallWithTaskPermission(mController, "registerRecentTasksListener",
|
||||||
|
(controller) -> mListener.register(listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterRecentTasksListener(IRecentTasksListener listener)
|
||||||
|
throws RemoteException {
|
||||||
|
executeRemoteCallWithTaskPermission(mController, "unregisterRecentTasksListener",
|
||||||
|
(controller) -> mListener.unregister());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupedRecentTaskInfo[] getRecentTasks(int maxNum, int flags, int userId)
|
||||||
|
throws RemoteException {
|
||||||
|
final GroupedRecentTaskInfo[][] out = new GroupedRecentTaskInfo[][]{null};
|
||||||
|
executeRemoteCallWithTaskPermission(mController, "getRecentTasks",
|
||||||
|
(controller) -> out[0] = controller.getRecentTasks(maxNum, flags, userId)
|
||||||
|
.toArray(new GroupedRecentTaskInfo[0]),
|
||||||
|
true /* blocking */);
|
||||||
|
return out[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.util;
|
||||||
|
|
||||||
|
parcelable GroupedRecentTaskInfo;
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.util;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.WindowConfiguration;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple container for recent tasks. May contain either a single or pair of tasks.
|
||||||
|
*/
|
||||||
|
public class GroupedRecentTaskInfo implements Parcelable {
|
||||||
|
public @NonNull ActivityManager.RecentTaskInfo mTaskInfo1;
|
||||||
|
public @Nullable ActivityManager.RecentTaskInfo mTaskInfo2;
|
||||||
|
|
||||||
|
public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1) {
|
||||||
|
this(task1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1,
|
||||||
|
@Nullable ActivityManager.RecentTaskInfo task2) {
|
||||||
|
mTaskInfo1 = task1;
|
||||||
|
mTaskInfo2 = task2;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupedRecentTaskInfo(Parcel parcel) {
|
||||||
|
mTaskInfo1 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
|
||||||
|
mTaskInfo2 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Task1: " + getTaskInfo(mTaskInfo1) + ", Task2: " + getTaskInfo(mTaskInfo2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
|
||||||
|
if (taskInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return "id=" + taskInfo.taskId
|
||||||
|
+ " baseIntent=" + (taskInfo.baseIntent != null
|
||||||
|
? taskInfo.baseIntent.getComponent()
|
||||||
|
: "null")
|
||||||
|
+ " winMode=" + WindowConfiguration.windowingModeToString(
|
||||||
|
taskInfo.getWindowingMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel parcel, int flags) {
|
||||||
|
parcel.writeTypedObject(mTaskInfo1, flags);
|
||||||
|
parcel.writeTypedObject(mTaskInfo2, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final @android.annotation.NonNull Creator<GroupedRecentTaskInfo> CREATOR =
|
||||||
|
new Creator<GroupedRecentTaskInfo>() {
|
||||||
|
public GroupedRecentTaskInfo createFromParcel(Parcel source) {
|
||||||
|
return new GroupedRecentTaskInfo(source);
|
||||||
|
}
|
||||||
|
public GroupedRecentTaskInfo[] newArray(int size) {
|
||||||
|
return new GroupedRecentTaskInfo[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -65,6 +65,7 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the shell task organizer.
|
* Tests for the shell task organizer.
|
||||||
@@ -131,7 +132,7 @@ public class ShellTaskOrganizerTests {
|
|||||||
.when(mTaskOrganizerController).registerTaskOrganizer(any());
|
.when(mTaskOrganizerController).registerTaskOrganizer(any());
|
||||||
} catch (RemoteException e) {}
|
} catch (RemoteException e) {}
|
||||||
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
|
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
|
||||||
mSizeCompatUI));
|
mSizeCompatUI, Optional.empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import androidx.test.InstrumentationRegistry;
|
|||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class that does shell test case setup.
|
* Base class that does shell test case setup.
|
||||||
@@ -36,6 +37,7 @@ public abstract class ShellTestCase {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void shellSetup() {
|
public void shellSetup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
final Context context =
|
final Context context =
|
||||||
InstrumentationRegistry.getInstrumentation().getTargetContext();
|
InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
final DisplayManager dm = context.getSystemService(DisplayManager.class);
|
final DisplayManager dm = context.getSystemService(DisplayManager.class);
|
||||||
|
|||||||
@@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.wm.shell.recents;
|
||||||
|
|
||||||
|
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import static java.lang.Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.WindowConfiguration;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
import android.window.TaskAppearedInfo;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.ShellTestCase;
|
||||||
|
import com.android.wm.shell.TestShellExecutor;
|
||||||
|
import com.android.wm.shell.common.ShellExecutor;
|
||||||
|
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||||
|
import com.android.wm.shell.util.GroupedRecentTaskInfo;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link RecentTasksController}.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public class RecentTasksControllerTest extends ShellTestCase {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private TaskStackListenerImpl mTaskStackListener;
|
||||||
|
|
||||||
|
private ShellTaskOrganizer mShellTaskOrganizer;
|
||||||
|
private RecentTasksController mRecentTasksController;
|
||||||
|
private ShellExecutor mMainExecutor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mMainExecutor = new TestShellExecutor();
|
||||||
|
mRecentTasksController = spy(new RecentTasksController(mContext, mTaskStackListener,
|
||||||
|
mMainExecutor));
|
||||||
|
mShellTaskOrganizer = new ShellTaskOrganizer(mMainExecutor, mContext,
|
||||||
|
null /* sizeCompatUI */, Optional.of(mRecentTasksController));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetRecentTasks() {
|
||||||
|
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
|
||||||
|
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
|
||||||
|
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
|
||||||
|
setRawList(t1, t2, t3);
|
||||||
|
|
||||||
|
ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
|
||||||
|
MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
|
||||||
|
assertGroupedTasksListEquals(recentTasks,
|
||||||
|
t1.taskId, -1,
|
||||||
|
t2.taskId, -1,
|
||||||
|
t3.taskId, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetRecentTasks_withPairs() {
|
||||||
|
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
|
||||||
|
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
|
||||||
|
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
|
||||||
|
ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
|
||||||
|
ActivityManager.RecentTaskInfo t5 = makeTaskInfo(5);
|
||||||
|
ActivityManager.RecentTaskInfo t6 = makeTaskInfo(6);
|
||||||
|
setRawList(t1, t2, t3, t4, t5, t6);
|
||||||
|
|
||||||
|
// Mark a couple pairs [t2, t4], [t3, t5]
|
||||||
|
mRecentTasksController.addSplitPair(t2.taskId, t4.taskId);
|
||||||
|
mRecentTasksController.addSplitPair(t3.taskId, t5.taskId);
|
||||||
|
|
||||||
|
ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
|
||||||
|
MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
|
||||||
|
assertGroupedTasksListEquals(recentTasks,
|
||||||
|
t1.taskId, -1,
|
||||||
|
t2.taskId, t4.taskId,
|
||||||
|
t3.taskId, t5.taskId,
|
||||||
|
t6.taskId, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemovedTaskRemovesSplit() {
|
||||||
|
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
|
||||||
|
ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
|
||||||
|
ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
|
||||||
|
setRawList(t1, t2, t3);
|
||||||
|
|
||||||
|
// Add a pair
|
||||||
|
mRecentTasksController.addSplitPair(t2.taskId, t3.taskId);
|
||||||
|
reset(mRecentTasksController);
|
||||||
|
|
||||||
|
// Remove one of the tasks and ensure the pair is removed
|
||||||
|
SurfaceControl mockLeash = mock(SurfaceControl.class);
|
||||||
|
ActivityManager.RunningTaskInfo rt2 = makeRunningTaskInfo(2);
|
||||||
|
mShellTaskOrganizer.onTaskAppeared(rt2, mockLeash);
|
||||||
|
mShellTaskOrganizer.onTaskVanished(rt2);
|
||||||
|
|
||||||
|
verify(mRecentTasksController).removeSplitPair(t2.taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTaskWindowingModeChangedNotifiesChange() {
|
||||||
|
ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
|
||||||
|
setRawList(t1);
|
||||||
|
|
||||||
|
// Remove one of the tasks and ensure the pair is removed
|
||||||
|
SurfaceControl mockLeash = mock(SurfaceControl.class);
|
||||||
|
ActivityManager.RunningTaskInfo rt2Fullscreen = makeRunningTaskInfo(2);
|
||||||
|
rt2Fullscreen.configuration.windowConfiguration.setWindowingMode(
|
||||||
|
WINDOWING_MODE_FULLSCREEN);
|
||||||
|
mShellTaskOrganizer.onTaskAppeared(rt2Fullscreen, mockLeash);
|
||||||
|
|
||||||
|
// Change the windowing mode and ensure the recent tasks change is notified
|
||||||
|
ActivityManager.RunningTaskInfo rt2MultiWIndow = makeRunningTaskInfo(2);
|
||||||
|
rt2MultiWIndow.configuration.windowConfiguration.setWindowingMode(
|
||||||
|
WINDOWING_MODE_MULTI_WINDOW);
|
||||||
|
mShellTaskOrganizer.onTaskInfoChanged(rt2MultiWIndow);
|
||||||
|
|
||||||
|
verify(mRecentTasksController).notifyRecentTasksChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create a task with a given task id.
|
||||||
|
*/
|
||||||
|
private ActivityManager.RecentTaskInfo makeTaskInfo(int taskId) {
|
||||||
|
ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
|
||||||
|
info.taskId = taskId;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to create a running task with a given task id.
|
||||||
|
*/
|
||||||
|
private ActivityManager.RunningTaskInfo makeRunningTaskInfo(int taskId) {
|
||||||
|
ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
|
||||||
|
info.taskId = taskId;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to set the raw task list on the controller.
|
||||||
|
*/
|
||||||
|
private ArrayList<ActivityManager.RecentTaskInfo> setRawList(
|
||||||
|
ActivityManager.RecentTaskInfo... tasks) {
|
||||||
|
ArrayList<ActivityManager.RecentTaskInfo> rawList = new ArrayList<>();
|
||||||
|
for (ActivityManager.RecentTaskInfo task : tasks) {
|
||||||
|
rawList.add(task);
|
||||||
|
}
|
||||||
|
doReturn(rawList).when(mRecentTasksController).getRawRecentTasks(anyInt(), anyInt(),
|
||||||
|
anyInt());
|
||||||
|
return rawList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the recent tasks matches the given task ids.
|
||||||
|
* @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
|
||||||
|
* the grouped task list
|
||||||
|
*/
|
||||||
|
private void assertGroupedTasksListEquals(ArrayList<GroupedRecentTaskInfo> recentTasks,
|
||||||
|
int... expectedTaskIds) {
|
||||||
|
int[] flattenedTaskIds = new int[recentTasks.size() * 2];
|
||||||
|
for (int i = 0; i < recentTasks.size(); i++) {
|
||||||
|
GroupedRecentTaskInfo pair = recentTasks.get(i);
|
||||||
|
flattenedTaskIds[2 * i] = pair.mTaskInfo1.taskId;
|
||||||
|
flattenedTaskIds[2 * i + 1] = pair.mTaskInfo2 != null
|
||||||
|
? pair.mTaskInfo2.taskId
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
|
assertTrue("Expected: " + Arrays.toString(expectedTaskIds)
|
||||||
|
+ " Received: " + Arrays.toString(flattenedTaskIds),
|
||||||
|
Arrays.equals(flattenedTaskIds, expectedTaskIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.systemui.shared.recents.model;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A group task in the recent tasks list.
|
||||||
|
* TODO: Move this into Launcher
|
||||||
|
*/
|
||||||
|
public class GroupTask {
|
||||||
|
public @NonNull Task task1;
|
||||||
|
public @Nullable Task task2;
|
||||||
|
|
||||||
|
public GroupTask(@NonNull Task t1, @Nullable Task t2) {
|
||||||
|
task1 = t1;
|
||||||
|
task2 = t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupTask(@NonNull GroupTask group) {
|
||||||
|
task1 = new Task(group.task1);
|
||||||
|
task2 = group.task2 != null
|
||||||
|
? new Task(group.task2)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsTask(int taskId) {
|
||||||
|
return task1.key.id == taskId || (task2 != null && task2.key.id == taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,6 +38,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A task in the recent tasks list.
|
* A task in the recent tasks list.
|
||||||
|
* TODO: Move this into Launcher or see if we can remove now
|
||||||
*/
|
*/
|
||||||
public class Task {
|
public class Task {
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ public class QuickStepContract {
|
|||||||
"extra_shell_starting_window";
|
"extra_shell_starting_window";
|
||||||
// See ISmartspaceTransitionController.aidl
|
// See ISmartspaceTransitionController.aidl
|
||||||
public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
|
public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
|
||||||
|
// See IRecentTasks.aidl
|
||||||
|
public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks";
|
||||||
|
|
||||||
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
|
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
|
||||||
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
|
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvid
|
|||||||
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
|
import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider;
|
||||||
import com.android.wm.shell.transition.ShellTransitions;
|
import com.android.wm.shell.transition.ShellTransitions;
|
||||||
import com.android.wm.shell.transition.Transitions;
|
import com.android.wm.shell.transition.Transitions;
|
||||||
|
import com.android.wm.shell.recents.RecentTasks;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@@ -120,7 +121,8 @@ public class SystemUIFactory {
|
|||||||
.setTransitions(mWMComponent.getTransitions())
|
.setTransitions(mWMComponent.getTransitions())
|
||||||
.setStartingSurface(mWMComponent.getStartingSurface())
|
.setStartingSurface(mWMComponent.getStartingSurface())
|
||||||
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
|
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
|
||||||
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper());
|
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
|
||||||
|
.setRecentTasks(mWMComponent.getRecentTasks());
|
||||||
} else {
|
} else {
|
||||||
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
|
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
|
||||||
// is separating this logic into newly creating SystemUITestsFactory.
|
// is separating this logic into newly creating SystemUITestsFactory.
|
||||||
@@ -137,7 +139,8 @@ public class SystemUIFactory {
|
|||||||
.setTransitions(new ShellTransitions() {})
|
.setTransitions(new ShellTransitions() {})
|
||||||
.setDisplayAreaHelper(Optional.ofNullable(null))
|
.setDisplayAreaHelper(Optional.ofNullable(null))
|
||||||
.setStartingSurface(Optional.ofNullable(null))
|
.setStartingSurface(Optional.ofNullable(null))
|
||||||
.setTaskSurfaceHelper(Optional.ofNullable(null));
|
.setTaskSurfaceHelper(Optional.ofNullable(null))
|
||||||
|
.setRecentTasks(Optional.ofNullable(null));
|
||||||
}
|
}
|
||||||
mSysUIComponent = builder.build();
|
mSysUIComponent = builder.build();
|
||||||
if (mInitializeComponents) {
|
if (mInitializeComponents) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
|||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
import com.android.wm.shell.pip.Pip;
|
import com.android.wm.shell.pip.Pip;
|
||||||
|
import com.android.wm.shell.recents.RecentTasks;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||||
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
|
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
|
||||||
@@ -101,6 +102,9 @@ public interface SysUIComponent {
|
|||||||
@BindsInstance
|
@BindsInstance
|
||||||
Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t);
|
Builder setTaskSurfaceHelper(Optional<TaskSurfaceHelper> t);
|
||||||
|
|
||||||
|
@BindsInstance
|
||||||
|
Builder setRecentTasks(Optional<RecentTasks> r);
|
||||||
|
|
||||||
SysUIComponent build();
|
SysUIComponent build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
|
|||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
import com.android.wm.shell.pip.Pip;
|
import com.android.wm.shell.pip.Pip;
|
||||||
|
import com.android.wm.shell.recents.RecentTasks;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||||
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
|
import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper;
|
||||||
@@ -110,4 +111,7 @@ public interface WMComponent {
|
|||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
Optional<TaskSurfaceHelper> getTaskSurfaceHelper();
|
Optional<TaskSurfaceHelper> getTaskSurfaceHelper();
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
Optional<RecentTasks> getRecentTasks();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
|
|||||||
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
|
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
|
||||||
|
|
||||||
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
|
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
|
||||||
|
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
|
||||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
|
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
|
||||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
|
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
|
||||||
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
|
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
|
||||||
@@ -105,6 +106,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
|||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
import com.android.wm.shell.pip.Pip;
|
import com.android.wm.shell.pip.Pip;
|
||||||
import com.android.wm.shell.pip.PipAnimationController;
|
import com.android.wm.shell.pip.PipAnimationController;
|
||||||
|
import com.android.wm.shell.recents.RecentTasks;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||||
import com.android.wm.shell.transition.ShellTransitions;
|
import com.android.wm.shell.transition.ShellTransitions;
|
||||||
@@ -158,6 +160,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
private final ShellTransitions mShellTransitions;
|
private final ShellTransitions mShellTransitions;
|
||||||
private final Optional<StartingSurface> mStartingSurface;
|
private final Optional<StartingSurface> mStartingSurface;
|
||||||
private final SmartspaceTransitionController mSmartspaceTransitionController;
|
private final SmartspaceTransitionController mSmartspaceTransitionController;
|
||||||
|
private final Optional<RecentTasks> mRecentTasks;
|
||||||
|
|
||||||
private Region mActiveNavBarRegion;
|
private Region mActiveNavBarRegion;
|
||||||
|
|
||||||
@@ -491,6 +494,9 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
params.putBinder(
|
params.putBinder(
|
||||||
KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
|
KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
|
||||||
mSmartspaceTransitionController.createExternalInterface().asBinder());
|
mSmartspaceTransitionController.createExternalInterface().asBinder());
|
||||||
|
mRecentTasks.ifPresent(recentTasks -> params.putBinder(
|
||||||
|
KEY_EXTRA_RECENT_TASKS,
|
||||||
|
recentTasks.createExternalInterface().asBinder()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mOverviewProxy.onInitialize(params);
|
mOverviewProxy.onInitialize(params);
|
||||||
@@ -541,17 +547,18 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
@Inject
|
@Inject
|
||||||
public OverviewProxyService(Context context, CommandQueue commandQueue,
|
public OverviewProxyService(Context context, CommandQueue commandQueue,
|
||||||
Lazy<NavigationBarController> navBarControllerLazy,
|
Lazy<NavigationBarController> navBarControllerLazy,
|
||||||
|
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
|
||||||
NavigationModeController navModeController,
|
NavigationModeController navModeController,
|
||||||
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
|
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
|
||||||
Optional<Pip> pipOptional,
|
Optional<Pip> pipOptional,
|
||||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||||
Optional<SplitScreen> splitScreenOptional,
|
Optional<SplitScreen> splitScreenOptional,
|
||||||
Lazy<Optional<StatusBar>> statusBarOptionalLazy,
|
|
||||||
Optional<OneHanded> oneHandedOptional,
|
Optional<OneHanded> oneHandedOptional,
|
||||||
|
Optional<RecentTasks> recentTasks,
|
||||||
|
Optional<StartingSurface> startingSurface,
|
||||||
BroadcastDispatcher broadcastDispatcher,
|
BroadcastDispatcher broadcastDispatcher,
|
||||||
ShellTransitions shellTransitions,
|
ShellTransitions shellTransitions,
|
||||||
ScreenLifecycle screenLifecycle,
|
ScreenLifecycle screenLifecycle,
|
||||||
Optional<StartingSurface> startingSurface,
|
|
||||||
SmartspaceTransitionController smartspaceTransitionController,
|
SmartspaceTransitionController smartspaceTransitionController,
|
||||||
DumpManager dumpManager) {
|
DumpManager dumpManager) {
|
||||||
super(broadcastDispatcher);
|
super(broadcastDispatcher);
|
||||||
@@ -573,6 +580,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
|||||||
mSysUiState.addCallback(this::notifySystemUiStateFlags);
|
mSysUiState.addCallback(this::notifySystemUiStateFlags);
|
||||||
mOneHandedOptional = oneHandedOptional;
|
mOneHandedOptional = oneHandedOptional;
|
||||||
mShellTransitions = shellTransitions;
|
mShellTransitions = shellTransitions;
|
||||||
|
mRecentTasks = recentTasks;
|
||||||
|
|
||||||
// Assumes device always starts with back button until launcher tells it that it does not
|
// Assumes device always starts with back button until launcher tells it that it does not
|
||||||
mNavBarButtonAlpha = 1.0f;
|
mNavBarButtonAlpha = 1.0f;
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
|
|||||||
import com.android.wm.shell.pip.PipUiEventLogger;
|
import com.android.wm.shell.pip.PipUiEventLogger;
|
||||||
import com.android.wm.shell.pip.phone.PipAppOpsListener;
|
import com.android.wm.shell.pip.phone.PipAppOpsListener;
|
||||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||||
|
import com.android.wm.shell.recents.RecentTasks;
|
||||||
|
import com.android.wm.shell.recents.RecentTasksController;
|
||||||
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||||
@@ -144,8 +146,11 @@ public abstract class WMShellBaseModule {
|
|||||||
@WMSingleton
|
@WMSingleton
|
||||||
@Provides
|
@Provides
|
||||||
static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor,
|
static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecutor mainExecutor,
|
||||||
Context context, SizeCompatUIController sizeCompatUI) {
|
Context context,
|
||||||
return new ShellTaskOrganizer(mainExecutor, context, sizeCompatUI);
|
SizeCompatUIController sizeCompatUI,
|
||||||
|
Optional<RecentTasksController> recentTasksOptional
|
||||||
|
) {
|
||||||
|
return new ShellTaskOrganizer(mainExecutor, context, sizeCompatUI, recentTasksOptional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@WMSingleton
|
@WMSingleton
|
||||||
@@ -409,6 +414,28 @@ public abstract class WMShellBaseModule {
|
|||||||
@BindsOptionalOf
|
@BindsOptionalOf
|
||||||
abstract PipTouchHandler optionalPipTouchHandler();
|
abstract PipTouchHandler optionalPipTouchHandler();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Recent tasks
|
||||||
|
//
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
@Provides
|
||||||
|
static Optional<RecentTasks> provideRecentTasks(
|
||||||
|
Optional<RecentTasksController> recentTasksController) {
|
||||||
|
return recentTasksController.map((controller) -> controller.asRecentTasks());
|
||||||
|
}
|
||||||
|
|
||||||
|
@WMSingleton
|
||||||
|
@Provides
|
||||||
|
static Optional<RecentTasksController> provideRecentTasksController(
|
||||||
|
Context context,
|
||||||
|
TaskStackListenerImpl taskStackListener,
|
||||||
|
@ShellMainThread ShellExecutor mainExecutor
|
||||||
|
) {
|
||||||
|
return Optional.ofNullable(
|
||||||
|
RecentTasksController.create(context, taskStackListener, mainExecutor));
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Shell transitions
|
// Shell transitions
|
||||||
//
|
//
|
||||||
@@ -555,13 +582,13 @@ public abstract class WMShellBaseModule {
|
|||||||
DragAndDropController dragAndDropController,
|
DragAndDropController dragAndDropController,
|
||||||
ShellTaskOrganizer shellTaskOrganizer,
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
Optional<BubbleController> bubblesOptional,
|
Optional<BubbleController> bubblesOptional,
|
||||||
Optional<LegacySplitScreenController> legacySplitScreenOptional,
|
|
||||||
Optional<SplitScreenController> splitScreenOptional,
|
Optional<SplitScreenController> splitScreenOptional,
|
||||||
Optional<AppPairsController> appPairsOptional,
|
Optional<AppPairsController> appPairsOptional,
|
||||||
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
Optional<PipTouchHandler> pipTouchHandlerOptional,
|
||||||
FullscreenTaskListener fullscreenTaskListener,
|
FullscreenTaskListener fullscreenTaskListener,
|
||||||
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
|
Optional<FullscreenUnfoldController> appUnfoldTransitionController,
|
||||||
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
|
Optional<Optional<FreeformTaskListener>> freeformTaskListener,
|
||||||
|
Optional<RecentTasksController> recentTasksOptional,
|
||||||
Transitions transitions,
|
Transitions transitions,
|
||||||
StartingWindowController startingWindow,
|
StartingWindowController startingWindow,
|
||||||
@ShellMainThread ShellExecutor mainExecutor) {
|
@ShellMainThread ShellExecutor mainExecutor) {
|
||||||
@@ -571,13 +598,13 @@ public abstract class WMShellBaseModule {
|
|||||||
dragAndDropController,
|
dragAndDropController,
|
||||||
shellTaskOrganizer,
|
shellTaskOrganizer,
|
||||||
bubblesOptional,
|
bubblesOptional,
|
||||||
legacySplitScreenOptional,
|
|
||||||
splitScreenOptional,
|
splitScreenOptional,
|
||||||
appPairsOptional,
|
appPairsOptional,
|
||||||
pipTouchHandlerOptional,
|
pipTouchHandlerOptional,
|
||||||
fullscreenTaskListener,
|
fullscreenTaskListener,
|
||||||
appUnfoldTransitionController,
|
appUnfoldTransitionController,
|
||||||
freeformTaskListener,
|
freeformTaskListener,
|
||||||
|
recentTasksOptional,
|
||||||
transitions,
|
transitions,
|
||||||
startingWindow,
|
startingWindow,
|
||||||
mainExecutor);
|
mainExecutor);
|
||||||
@@ -603,9 +630,10 @@ public abstract class WMShellBaseModule {
|
|||||||
Optional<OneHandedController> oneHandedOptional,
|
Optional<OneHandedController> oneHandedOptional,
|
||||||
Optional<HideDisplayCutoutController> hideDisplayCutout,
|
Optional<HideDisplayCutoutController> hideDisplayCutout,
|
||||||
Optional<AppPairsController> appPairsOptional,
|
Optional<AppPairsController> appPairsOptional,
|
||||||
|
Optional<RecentTasksController> recentTasksOptional,
|
||||||
@ShellMainThread ShellExecutor mainExecutor) {
|
@ShellMainThread ShellExecutor mainExecutor) {
|
||||||
return new ShellCommandHandlerImpl(shellTaskOrganizer,
|
return new ShellCommandHandlerImpl(shellTaskOrganizer,
|
||||||
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
|
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
|
||||||
hideDisplayCutout, appPairsOptional, mainExecutor);
|
hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user