summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chung <winsonc@google.com> 2020-11-10 17:24:57 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-11-10 17:24:57 +0000
commitb73cc69fbc8a18f94342e972f9ae42e2b85f1a32 (patch)
tree02e84d1d27ecf4b8676799428f9ebdb5af10823f
parentbe00e1b8d4e93d8ad745bfb3f2b41e6699c86209 (diff)
parent6dd73e98d77af599253ae26a2076abceaa44a78c (diff)
Merge changes from topic "shell_task_stack_listener"
* changes: 6/ Fix some flakey issues with dragging to split Clean up task stack listeners
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java182
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java116
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java437
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java59
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java30
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java125
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java81
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java258
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java108
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java13
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java9
-rw-r--r--services/core/java/com/android/server/wm/DragState.java5
-rw-r--r--services/core/java/com/android/server/wm/Task.java4
32 files changed, 1332 insertions, 325 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 51ddb17daa00..2d20feeb0832 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -346,15 +346,9 @@ public class ShellTaskOrganizer extends TaskOrganizer {
return mTaskListeners.get(taskListenerType);
}
- @WindowingMode
- public static int getWindowingMode(RunningTaskInfo taskInfo) {
- return taskInfo.configuration.windowConfiguration.getWindowingMode();
- }
-
@VisibleForTesting
static @TaskListenerType int taskInfoToTaskListenerType(RunningTaskInfo runningTaskInfo) {
- final int windowingMode = getWindowingMode(runningTaskInfo);
- switch (windowingMode) {
+ switch (runningTaskInfo.getWindowingMode()) {
case WINDOWING_MODE_FULLSCREEN:
return runningTaskInfo.letterboxActivityBounds != null
? TASK_LISTENER_TYPE_LETTERBOX
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
new file mode 100644
index 000000000000..87ddb181dcce
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
@@ -0,0 +1,182 @@
+/*
+ * 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.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.WindowManagerGlobal;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the input consumer that allows the Shell to directly receive input.
+ */
+public class PipInputConsumer {
+
+ private static final String TAG = PipInputConsumer.class.getSimpleName();
+
+ /**
+ * Listener interface for callers to subscribe to input events.
+ */
+ public interface InputListener {
+ /** Handles any input event. */
+ boolean onInputEvent(InputEvent ev);
+ }
+
+ /**
+ * Listener interface for callers to learn when this class is registered or unregistered with
+ * window manager
+ */
+ public interface RegistrationListener {
+ void onRegistrationChanged(boolean isRegistered);
+ }
+
+ /**
+ * Input handler used for the input consumer. Input events are batched and consumed with the
+ * SurfaceFlinger vsync.
+ */
+ private final class InputEventReceiver extends BatchedInputEventReceiver {
+
+ InputEventReceiver(InputChannel inputChannel, Looper looper,
+ Choreographer choreographer) {
+ super(inputChannel, looper, choreographer);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = true;
+ try {
+ if (mListener != null) {
+ handled = mListener.onInputEvent(event);
+ }
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+ }
+
+ private final IWindowManager mWindowManager;
+ private final IBinder mToken;
+ private final String mName;
+
+ private InputEventReceiver mInputEventReceiver;
+ private InputListener mListener;
+ private RegistrationListener mRegistrationListener;
+
+ /**
+ * @param name the name corresponding to the input consumer that is defined in the system.
+ */
+ public PipInputConsumer(IWindowManager windowManager, String name) {
+ mWindowManager = windowManager;
+ mToken = new Binder();
+ mName = name;
+ }
+
+ /**
+ * Sets the input listener.
+ */
+ public void setInputListener(InputListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Sets the registration listener.
+ */
+ public void setRegistrationListener(RegistrationListener listener) {
+ mRegistrationListener = listener;
+ if (mRegistrationListener != null) {
+ mRegistrationListener.onRegistrationChanged(mInputEventReceiver != null);
+ }
+ }
+
+ /**
+ * Check if the InputConsumer is currently registered with WindowManager
+ *
+ * @return {@code true} if registered, {@code false} if not.
+ */
+ public boolean isRegistered() {
+ return mInputEventReceiver != null;
+ }
+
+ /**
+ * Registers the input consumer.
+ */
+ public void registerInputConsumer() {
+ registerInputConsumer(false);
+ }
+
+ /**
+ * Registers the input consumer.
+ * @param withSfVsync the flag set using sf vsync signal or no
+ */
+ public void registerInputConsumer(boolean withSfVsync) {
+ if (mInputEventReceiver != null) {
+ return;
+ }
+ final InputChannel inputChannel = new InputChannel();
+ try {
+ // TODO(b/113087003): Support Picture-in-picture in multi-display.
+ mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create input consumer", e);
+ }
+ mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(),
+ withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance());
+ if (mRegistrationListener != null) {
+ mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
+ }
+ }
+
+ /**
+ * Unregisters the input consumer.
+ */
+ public void unregisterInputConsumer() {
+ if (mInputEventReceiver == null) {
+ return;
+ }
+ try {
+ // TODO(b/113087003): Support Picture-in-picture in multi-display.
+ mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to destroy input consumer", e);
+ }
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ if (mRegistrationListener != null) {
+ mRegistrationListener.onRegistrationChanged(false /* isRegistered */);
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null));
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
new file mode 100644
index 000000000000..0f6dd93f9c16
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -0,0 +1,116 @@
+/*
+ * 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.common;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskStackListener;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.os.IBinder;
+
+import androidx.annotation.BinderThread;
+import androidx.annotation.MainThread;
+
+/**
+ * An interface to track task stack changes. Classes should implement this instead of
+ * {@link ITaskStackListener} to reduce IPC calls from system services.
+ */
+public interface TaskStackListenerCallback {
+
+ @MainThread
+ default void onRecentTaskListUpdated() { }
+
+ @MainThread
+ default void onRecentTaskListFrozenChanged(boolean frozen) { }
+
+ @BinderThread
+ default void onTaskStackChangedBackground() { }
+
+ @MainThread
+ default void onTaskStackChanged() { }
+
+ @MainThread
+ default void onTaskProfileLocked(int taskId, int userId) { }
+
+ @MainThread
+ default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
+
+ @MainThread
+ default void onTaskCreated(int taskId, ComponentName componentName) { }
+
+ @MainThread
+ default void onTaskRemoved(int taskId) { }
+
+ @MainThread
+ default void onTaskMovedToFront(int taskId) { }
+
+ @MainThread
+ default void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+ onTaskMovedToFront(taskInfo.taskId);
+ }
+
+ @MainThread
+ default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
+
+ @MainThread
+ default void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) { }
+
+ @MainThread
+ default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
+
+ @MainThread
+ default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask, boolean wasVisible) { }
+
+ @MainThread
+ default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
+
+ @MainThread
+ default void onActivityUnpinned() { }
+
+ @MainThread
+ default void onActivityForcedResizable(String packageName, int taskId, int reason) { }
+
+ @MainThread
+ default void onActivityDismissingDockedStack() { }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayFailed() { }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
+ onActivityLaunchOnSecondaryDisplayFailed();
+ }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayRerouted() { }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) {
+ onActivityLaunchOnSecondaryDisplayRerouted();
+ }
+
+ @MainThread
+ default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
+
+ @MainThread
+ default void onActivityRotation(int displayId) { }
+
+ @MainThread
+ default void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
new file mode 100644
index 000000000000..7efacc7b2c1f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -0,0 +1,437 @@
+/*
+ * 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.common;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Trace;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a {@link android.app.TaskStackListener}.
+ */
+public class TaskStackListenerImpl extends TaskStackListener implements Handler.Callback {
+ private static final String TAG = TaskStackListenerImpl.class.getSimpleName();
+
+ private static final int ON_TASK_STACK_CHANGED = 1;
+ private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+ private static final int ON_ACTIVITY_PINNED = 3;
+ private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4;
+ private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
+ private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 6;
+ private static final int ON_TASK_PROFILE_LOCKED = 7;
+ private static final int ON_ACTIVITY_UNPINNED = 8;
+ private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 9;
+ private static final int ON_TASK_CREATED = 10;
+ private static final int ON_TASK_REMOVED = 11;
+ private static final int ON_TASK_MOVED_TO_FRONT = 12;
+ private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 13;
+ private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 14;
+ private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 15;
+ private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 16;
+ private static final int ON_TASK_DISPLAY_CHANGED = 17;
+ private static final int ON_TASK_LIST_UPDATED = 18;
+ private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 19;
+ private static final int ON_TASK_DESCRIPTION_CHANGED = 20;
+ private static final int ON_ACTIVITY_ROTATION = 21;
+
+ /**
+ * List of {@link TaskStackListenerCallback} registered from {@link #addListener}.
+ */
+ private final List<TaskStackListenerCallback> mTaskStackListeners = new ArrayList<>();
+ private final List<TaskStackListenerCallback> mTmpListeners = new ArrayList<>();
+
+ private final IActivityTaskManager mActivityTaskManager;
+ // NOTE: In this case we do want to use a handler since we rely on the message system to
+ // efficiently dedupe sequential calls
+ private Handler mHandler;
+
+ public TaskStackListenerImpl(Handler handler) {
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mHandler = new Handler(handler.getLooper(), this);
+ }
+
+ @VisibleForTesting
+ TaskStackListenerImpl(IActivityTaskManager activityTaskManager) {
+ mActivityTaskManager = activityTaskManager;
+ }
+
+ @VisibleForTesting
+ void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
+ public void addListener(TaskStackListenerCallback listener) {
+ final boolean wasEmpty;
+ synchronized (mTaskStackListeners) {
+ wasEmpty = mTaskStackListeners.isEmpty();
+ mTaskStackListeners.add(listener);
+ }
+ if (wasEmpty) {
+ // Register mTaskStackListener to IActivityManager only once if needed.
+ try {
+ mActivityTaskManager.registerTaskStackListener(this);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call registerTaskStackListener", e);
+ }
+ }
+ }
+
+ public void removeListener(TaskStackListenerCallback listener) {
+ final boolean wasEmpty;
+ final boolean isEmpty;
+ synchronized (mTaskStackListeners) {
+ wasEmpty = mTaskStackListeners.isEmpty();
+ mTaskStackListeners.remove(listener);
+ isEmpty = mTaskStackListeners.isEmpty();
+ }
+ if (!wasEmpty && isEmpty) {
+ // Unregister mTaskStackListener once we have no more listeners
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(this);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
+ }
+ }
+ }
+
+ @Override
+ public void onRecentTaskListUpdated() {
+ mHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
+ }
+
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onTaskStackChanged() {
+ // Call the task changed callback for the non-ui thread listeners first. Copy to a set
+ // of temp listeners so that we don't lock on mTaskStackListeners while calling all the
+ // callbacks. This call is always on the same binder thread, so we can just synchronize
+ // on the copying of the listener list.
+ synchronized (mTaskStackListeners) {
+ mTmpListeners.addAll(mTaskStackListeners);
+ }
+ for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
+ mTmpListeners.get(i).onTaskStackChangedBackground();
+ }
+ mTmpListeners.clear();
+
+ mHandler.removeMessages(ON_TASK_STACK_CHANGED);
+ mHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
+ }
+
+ @Override
+ public void onTaskProfileLocked(int taskId, int userId) {
+ mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+ }
+
+ @Override
+ public void onTaskDisplayChanged(int taskId, int newDisplayId) {
+ mHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
+ }
+
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ mHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ mHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
+ }
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) {
+ mHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = packageName;
+ args.argi1 = userId;
+ args.argi2 = taskId;
+ args.argi3 = stackId;
+ mHandler.removeMessages(ON_ACTIVITY_PINNED);
+ mHandler.obtainMessage(ON_ACTIVITY_PINNED, args).sendToTarget();
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ mHandler.removeMessages(ON_ACTIVITY_UNPINNED);
+ mHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
+ }
+
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask, boolean wasVisible) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ args.argi3 = wasVisible ? 1 : 0;
+ mHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
+ mHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId, int reason) {
+ mHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed(
+ ActivityManager.RunningTaskInfo taskInfo,
+ int requestedDisplayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
+ requestedDisplayId,
+ 0 /* unused */,
+ taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayRerouted(
+ ActivityManager.RunningTaskInfo taskInfo,
+ int requestedDisplayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
+ requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
+ mHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
+ requestedOrientation).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRotation(int displayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
+ mHandler.obtainMessage(ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId,
+ 0 /* unused */,
+ activityToken).sendToTarget();
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ synchronized (mTaskStackListeners) {
+ switch (msg.what) {
+ case ON_TASK_STACK_CHANGED: {
+ Trace.beginSection("onTaskStackChanged");
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskStackChanged();
+ }
+ Trace.endSection();
+ break;
+ }
+ case ON_TASK_SNAPSHOT_CHANGED: {
+ Trace.beginSection("onTaskSnapshotChanged");
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+ (ActivityManager.TaskSnapshot) msg.obj);
+ }
+ Trace.endSection();
+ break;
+ }
+ case ON_ACTIVITY_PINNED: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityPinned((String) args.arg1, args.argi1,
+ args.argi2, args.argi3);
+ }
+ break;
+ }
+ case ON_ACTIVITY_UNPINNED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityUnpinned();
+ }
+ break;
+ }
+ case ON_ACTIVITY_RESTART_ATTEMPT: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final ActivityManager.RunningTaskInfo
+ task = (ActivityManager.RunningTaskInfo) args.arg1;
+ final boolean homeTaskVisible = args.argi1 != 0;
+ final boolean clearedTask = args.argi2 != 0;
+ final boolean wasVisible = args.argi3 != 0;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRestartAttempt(task,
+ homeTaskVisible, clearedTask, wasVisible);
+ }
+ break;
+ }
+ case ON_ACTIVITY_FORCED_RESIZABLE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityForcedResizable(
+ (String) msg.obj, msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityDismissingDockedStack();
+ }
+ break;
+ }
+ case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i)
+ .onActivityLaunchOnSecondaryDisplayFailed(info);
+ }
+ break;
+ }
+ case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i)
+ .onActivityLaunchOnSecondaryDisplayRerouted(info);
+ }
+ break;
+ }
+ case ON_TASK_PROFILE_LOCKED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_TASK_CREATED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskCreated(msg.arg1,
+ (ComponentName) msg.obj);
+ }
+ break;
+ }
+ case ON_TASK_REMOVED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskRemoved(msg.arg1);
+ }
+ break;
+ }
+ case ON_TASK_MOVED_TO_FRONT: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskMovedToFront(info);
+ }
+ break;
+ }
+ case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i)
+ .onActivityRequestedOrientationChanged(msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onSizeCompatModeActivityChanged(
+ msg.arg1, (IBinder) msg.obj);
+ }
+ break;
+ }
+ case ON_BACK_PRESSED_ON_TASK_ROOT: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onBackPressedOnTaskRoot(
+ (ActivityManager.RunningTaskInfo) msg.obj);
+ }
+ break;
+ }
+ case ON_TASK_DISPLAY_CHANGED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskDisplayChanged(msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_TASK_LIST_UPDATED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onRecentTaskListUpdated();
+ }
+ break;
+ }
+ case ON_TASK_LIST_FROZEN_UNFROZEN: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(
+ msg.arg1 != 0);
+ }
+ break;
+ }
+ case ON_TASK_DESCRIPTION_CHANGED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskDescriptionChanged(info);
+ }
+ break;
+ }
+ case ON_ACTIVITY_ROTATION: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRotation(msg.arg1);
+ }
+ break;
+ }
+ }
+ }
+ if (msg.obj instanceof SomeArgs) {
+ ((SomeArgs) msg.obj).recycle();
+ }
+ return true;
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index 25890bc31b3c..8a547b4477fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.draganddrop;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
@@ -67,6 +68,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
/**
* The policy for handling drag and drop operations to shell.
@@ -133,20 +135,20 @@ public class DragAndDropPolicy {
// TODO(b/169894807): For now, only allow splitting to the right/bottom until we
// have split pairs
mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(0, 0, w, h / 2),
+ new Rect(l, t, l + iw, t + ih / 2),
new Rect(l, t, l + iw, t + ih),
new Rect(0, 0, w, h)));
mTargets.add(new Target(TYPE_SPLIT_BOTTOM,
- new Rect(0, h / 2, w, h),
+ new Rect(l, t + ih / 2, l + iw, t + ih),
new Rect(l, t + ih / 2, l + iw, t + ih),
new Rect(0, h / 2, w, h)));
} else {
mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(0, 0, w / 2, h),
+ new Rect(l, t, l + iw / 2, t + ih),
new Rect(l, t, l + iw, t + ih),
new Rect(0, 0, w, h)));
mTargets.add(new Target(TYPE_SPLIT_RIGHT,
- new Rect(w / 2, 0, w, h),
+ new Rect(l + iw / 2, t, l + iw, t + ih),
new Rect(l + iw / 2, t, l + iw, t + ih),
new Rect(w / 2, 0, w, h)));
}
@@ -162,12 +164,12 @@ public class DragAndDropPolicy {
secondarySplitBounds.intersect(new Rect(l, t, l + iw, t + ih));
if (isVerticalSplit) {
mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(0, 0, w, secondarySplitRawBounds.top),
+ new Rect(l, t, l + iw, secondarySplitRawBounds.top),
new Rect(l, t, l + iw, t + ih),
new Rect(0, 0, w, secondarySplitRawBounds.top)));
} else {
mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(0, 0, secondarySplitRawBounds.left, h),
+ new Rect(l, t, secondarySplitRawBounds.left, t + ih),
new Rect(l, t, l + iw, t + ih),
new Rect(0, 0, w, h)));
}
@@ -178,7 +180,7 @@ public class DragAndDropPolicy {
} else {
// Otherwise only show the fullscreen target
mTargets.add(new Target(TYPE_FULLSCREEN,
- new Rect(0, 0, w, h),
+ new Rect(l, t, l + iw, t + ih),
new Rect(l, t, l + iw, t + ih),
new Rect(0, 0, w, h)));
}
@@ -210,6 +212,7 @@ public class DragAndDropPolicy {
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
final Intent dragData = mSession.dragData;
+ boolean deferAppLaunchUntilSplit = false;
if (target.type == TYPE_FULLSCREEN) {
if (mSplitScreen != null && mSplitScreen.isDividerVisible()) {
// If in split, remove split and launch fullscreen
@@ -226,20 +229,40 @@ public class DragAndDropPolicy {
// Not in split, enter split now
mStarter.enterSplitScreen(mSession.runningTaskId,
target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP);
+ deferAppLaunchUntilSplit = true;
}
}
- Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
- ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
- : null;
- if (isTask) {
- mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
- } else if (isShortcut) {
- mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
- dragData.getStringExtra(EXTRA_SHORTCUT_ID),
- opts, dragData.getParcelableExtra(EXTRA_USER));
+ final Runnable startAppRunnable = () -> {
+ Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
+ ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
+ : null;
+ if (isTask) {
+ mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
+ } else if (isShortcut) {
+ mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
+ dragData.getStringExtra(EXTRA_SHORTCUT_ID),
+ opts, dragData.getParcelableExtra(EXTRA_USER));
+ } else {
+ mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
+ }
+ };
+ if (deferAppLaunchUntilSplit) {
+ // TODO(b/169894807): The enterSplitScreen() call above will trigger the current task
+ // into split, and we should wait for home and other tasks to be moved to
+ // split-secondary before trying to launch the new secondary task. This can be removed
+ // once we have app-pairs.
+ mSplitScreen.registerInSplitScreenListener(new Consumer<Boolean>() {
+ @Override
+ public void accept(Boolean inSplit) {
+ if (inSplit) {
+ startAppRunnable.run();
+ mSplitScreen.unregisterInSplitScreenListener(this);
+ }
+ }
+ });
} else {
- mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
+ startAppRunnable.run();
}
}
@@ -274,7 +297,7 @@ public class DragAndDropPolicy {
* Updates the session data based on the current state of the system.
*/
void update() {
- final ClipDescription description = mInitialDragData.getDescription();
+
try {
List<ActivityManager.RunningTaskInfo> tasks =
mIActivityTaskManager.getFilteredTasks(1,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index fa857cdd174c..5b7531c09a7b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -135,17 +135,25 @@ public class DragLayout extends View {
// visibility of the current region
DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(
(int) event.getX(), (int) event.getY());
- if (target != null && mCurrentTarget != target) {
+ if (mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
- Interpolator boundsInterpolator = FAST_OUT_SLOW_IN;
- if (mCurrentTarget == null) {
+ if (target == null) {
+ // Animating to no target
+ mDropOutline.startVisibilityAnimation(false, LINEAR);
+ Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
+ finalBounds.inset(mDisplayMargin, mDisplayMargin);
+ mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
+ } else if (mCurrentTarget == null) {
+ // Animating to first target
mDropOutline.startVisibilityAnimation(true, LINEAR);
Rect initialBounds = new Rect(target.drawRegion);
initialBounds.inset(mDisplayMargin, mDisplayMargin);
mDropOutline.setRegionBounds(initialBounds);
- boundsInterpolator = LINEAR_OUT_SLOW_IN;
+ mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
+ } else {
+ // Bounds change
+ mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
}
- mDropOutline.startBoundsAnimation(target.drawRegion, boundsInterpolator);
mCurrentTarget = target;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 7d039d4d92f6..f84936e5f386 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.onehanded;
import static android.os.UserHandle.USER_CURRENT;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.content.ComponentName;
import android.content.Context;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
@@ -38,6 +39,8 @@ import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
import java.io.PrintWriter;
@@ -164,7 +167,8 @@ public class OneHandedController implements OneHanded {
*/
@Nullable
public static OneHandedController create(
- Context context, DisplayController displayController) {
+ Context context, DisplayController displayController,
+ TaskStackListenerImpl taskStackListener) {
if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
Slog.w(TAG, "Device doesn't support OneHanded feature");
return null;
@@ -181,7 +185,7 @@ public class OneHandedController implements OneHanded {
IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
return new OneHandedController(context, displayController, organizer, touchHandler,
- tutorialHandler, gestureHandler, overlayManager);
+ tutorialHandler, gestureHandler, overlayManager, taskStackListener);
}
@VisibleForTesting
@@ -191,7 +195,8 @@ public class OneHandedController implements OneHanded {
OneHandedTouchHandler touchHandler,
OneHandedTutorialHandler tutorialHandler,
OneHandedGestureHandler gestureHandler,
- IOverlayManager overlayManager) {
+ IOverlayManager overlayManager,
+ TaskStackListenerImpl taskStackListener) {
mContext = context;
mDisplayAreaOrganizer = displayAreaOrganizer;
mDisplayController = displayController;
@@ -216,6 +221,19 @@ public class OneHandedController implements OneHanded {
setupTimeoutListener();
setupGesturalOverlay();
updateSettings();
+
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+ }
+
+ @Override
+ public void onTaskMovedToFront(int taskId) {
+ stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+ }
+ });
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 8d5da1a5ffcb..46270cf24f48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -81,30 +81,6 @@ public interface Pip {
}
/**
- * Called whenever an Activity is moved to the pinned stack from another stack.
- */
- default void onActivityPinned(String packageName) {
- }
-
- /**
- * Called whenever an Activity is moved from the pinned stack to another stack
- */
- default void onActivityUnpinned(ComponentName topActivity) {
- }
-
- /**
- * Called whenever IActivityManager.startActivity is called on an activity that is already
- * running, but the task is either brought to the front or a new Intent is delivered to it.
- *
- * @param task information about the task the activity was relaunched into
- * @param clearedTask whether or not the launch activity also cleared the task as a part of
- * starting
- */
- default void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean clearedTask) {
- }
-
- /**
* Called when display size or font size of settings changed
*/
default void onDensityOrFontScaleChanged() {
@@ -132,12 +108,6 @@ public interface Pip {
}
/**
- * Called when task stack changed.
- */
- default void onTaskStackChanged() {
- }
-
- /**
* Resize the Pip to the appropriate size for the input state.
*
* @param state In Pip state also used to determine the new size for the Pip.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index c4da7974dadb..c7926455e0de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -16,12 +16,15 @@
package com.android.wm.shell.pip.phone;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.content.ComponentName;
@@ -32,9 +35,12 @@ import android.graphics.Rect;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;
+import android.view.WindowManagerGlobal;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -44,13 +50,17 @@ import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.PipInputConsumer;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUtils;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -63,22 +73,22 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private Context mContext;
private ShellExecutor mMainExecutor;
+ private DisplayController mDisplayController;
+ private PipInputConsumer mPipInputConsumer;
+ private WindowManagerShellWrapper mWindowManagerShellWrapper;
+ private PipAppOpsListener mAppOpsListener;
+ private PipMediaController mMediaController;
+ private PipBoundsHandler mPipBoundsHandler;
+ private PipBoundsState mPipBoundsState;
+ private PipTouchHandler mTouchHandler;
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
private final Rect mTmpInsetBounds = new Rect();
private final Rect mTmpNormalBounds = new Rect();
protected final Rect mReentryBounds = new Rect();
- private DisplayController mDisplayController;
- private PipAppOpsListener mAppOpsListener;
- private PipBoundsHandler mPipBoundsHandler;
- private @NonNull PipBoundsState mPipBoundsState;
- private PipMediaController mMediaController;
- private PipTouchHandler mTouchHandler;
- private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
- private WindowManagerShellWrapper mWindowManagerShellWrapper;
-
private boolean mIsInFixedRotation;
+ private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
protected PipMenuActivityController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
@@ -221,6 +231,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler,
WindowManagerShellWrapper windowManagerShellWrapper,
+ TaskStackListenerImpl taskStackListener,
ShellExecutor mainExecutor
) {
// Ensure that we are the primary user's SystemUI.
@@ -254,7 +265,14 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
});
mMediaController = pipMediaController;
mMenuController = pipMenuActivityController;
+ mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
+ INPUT_CONSUMER_PIP);
mTouchHandler = pipTouchHandler;
+ if (mTouchHandler != null) {
+ // Register the listener for input consumer touch events. Only for Phone
+ mPipInputConsumer.setInputListener(mTouchHandler::handleTouchEvent);
+ mPipInputConsumer.setRegistrationListener(mTouchHandler::onRegistrationChanged);
+ }
mAppOpsListener = pipAppOpsListener;
displayController.addDisplayChangingController(mRotationController);
displayController.addDisplayWindowListener(mFixedRotationListener);
@@ -270,43 +288,66 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
} catch (RemoteException e) {
Slog.e(TAG, "Failed to register pinned stack listener", e);
}
- }
- @Override
- public void onDensityOrFontScaleChanged() {
- mMainExecutor.execute(() -> {
- mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
- });
- }
+ try {
+ ActivityTaskManager.RootTaskInfo taskInfo = ActivityTaskManager.getService()
+ .getRootTaskInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ if (taskInfo != null) {
+ // If SystemUI restart, and it already existed a pinned stack,
+ // register the pip input consumer to ensure touch can send to it.
+ mPipInputConsumer.registerInputConsumer(true /* withSfVsync */);
+ }
+ } catch (RemoteException | UnsupportedOperationException e) {
+ Log.e(TAG, "Failed to register pinned stack listener", e);
+ e.printStackTrace();
+ }
- @Override
- public void onActivityPinned(String packageName) {
- mMainExecutor.execute(() -> {
- mTouchHandler.onActivityPinned();
- mMediaController.onActivityPinned();
- mAppOpsListener.onActivityPinned(packageName);
- });
+ // Handle for system task stack changes.
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId,
+ int stackId) {
+ mMainExecutor.execute(() -> {
+ mTouchHandler.onActivityPinned();
+ mMediaController.onActivityPinned();
+ mAppOpsListener.onActivityPinned(packageName);
+ });
+ mPipInputConsumer.registerInputConsumer(true /* withSfVsync */);
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPipActivity(mContext);
+ final ComponentName topActivity = topPipActivityInfo.first;
+ mMainExecutor.execute(() -> {
+ mTouchHandler.onActivityUnpinned(topActivity);
+ mAppOpsListener.onActivityUnpinned();
+ });
+ mPipInputConsumer.unregisterInputConsumer();
+ }
+
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ return;
+ }
+ mTouchHandler.getMotionHelper().expandLeavePip(
+ clearedTask /* skipAnimation */);
+ }
+ });
}
@Override
- public void onActivityUnpinned(ComponentName topActivity) {
+ public void onDensityOrFontScaleChanged() {
mMainExecutor.execute(() -> {
- mTouchHandler.onActivityUnpinned(topActivity);
- mAppOpsListener.onActivityUnpinned();
+ mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
});
}
@Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean clearedTask) {
- if (task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_PINNED) {
- return;
- }
- mTouchHandler.getMotionHelper().expandLeavePip(clearedTask /* skipAnimation */);
- }
-
- @Override
public void onOverlayChanged() {
mMainExecutor.execute(() -> {
mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay()));
@@ -474,6 +515,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mPipBoundsHandler.dump(pw, innerPrefix);
mPipTaskOrganizer.dump(pw, innerPrefix);
mPipBoundsState.dump(pw, innerPrefix);
+ mPipInputConsumer.dump(pw, innerPrefix);
}
/**
@@ -483,17 +525,16 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
public static PipController create(Context context, DisplayController displayController,
PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler,
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController,
- PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler,
- WindowManagerShellWrapper windowManagerShellWrapper,
- ShellExecutor mainExecutor) {
+ PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
+ PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
+ TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
Slog.w(TAG, "Device doesn't support Pip feature");
return null;
}
return new PipController(context, displayController, pipAppOpsListener, pipBoundsHandler,
- pipBoundsState, pipMediaController, pipMenuActivityController,
- pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper, mainExecutor);
+ pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer,
+ pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 3468b888c06a..402d79c6fbd1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -44,16 +44,20 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import android.view.DisplayInfo;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUtils;
import java.util.ArrayList;
import java.util.List;
@@ -225,6 +229,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
PipTaskOrganizer pipTaskOrganizer,
PipMediaController pipMediaController,
PipNotification pipNotification,
+ TaskStackListenerImpl taskStackListener,
WindowManagerShellWrapper windowManagerShellWrapper) {
mContext = context;
mPipBoundsState = pipBoundsState;
@@ -263,6 +268,27 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
Log.e(TAG, "Failed to register pinned stack listener", e);
}
+ // Handle for system task stack changes.
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onTaskStackChanged() {
+ PipController.this.onTaskStackChanged();
+ }
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId,
+ int stackId) {
+ PipController.this.onActivityPinned(packageName);
+ }
+
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ PipController.this.onActivityRestartAttempt(task, clearedTask);
+ }
+ });
+
// TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
PipMenuActivity.setPipController(this);
}
@@ -351,8 +377,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
resizePinnedStack(STATE_NO_PIP);
}
- @Override
- public void onActivityPinned(String packageName) {
+ private void onActivityPinned(String packageName) {
if (DEBUG) Log.d(TAG, "onActivityPinned()");
RootTaskInfo taskInfo = getPinnedTaskInfo();
@@ -371,11 +396,9 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
}
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean clearedTask) {
- if (task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_PINNED) {
+ if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
return;
}
if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
@@ -384,8 +407,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
movePipToFullscreen();
}
- @Override
- public void onTaskStackChanged() {
+ private void onTaskStackChanged() {
if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
if (getState() != STATE_NO_PIP) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index d1176733deb9..e55f065c1bb2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -27,9 +27,6 @@ import java.util.function.Consumer;
* Interface to engage split screen feature.
*/
public interface SplitScreen {
- /** Returns {@code true} if split screen is supported on the device. */
- boolean isSplitScreenSupported();
-
/** Called when keyguard showing state changed. */
void onKeyguardVisibilityChanged(boolean isShowing);
@@ -48,15 +45,6 @@ public interface SplitScreen {
/** Switch to minimized state if appropriate. */
void setMinimized(boolean minimized);
- /** Called when there's an activity forced resizable. */
- void onActivityForcedResizable(String packageName, int taskId, int reason);
-
- /** Called when there's an activity dismissing split screen. */
- void onActivityDismissingSplitScreen();
-
- /** Called when there's an activity launch on secondary display failed. */
- void onActivityLaunchOnSecondaryDisplayFailed();
-
/** Called when there's a task undocking. */
void onUndockingTask();
@@ -69,6 +57,9 @@ public interface SplitScreen {
/** Registers listener that gets called whenever the existence of the divider changes. */
void registerInSplitScreenListener(Consumer<Boolean> listener);
+ /** Unregisters listener that gets called whenever the existence of the divider changes. */
+ void unregisterInSplitScreenListener(Consumer<Boolean> listener);
+
/** Registers listener that gets called whenever the split screen bounds changes. */
void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 341a459902db..07af289c4f35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -20,9 +20,11 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -48,12 +50,15 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -81,8 +86,8 @@ public class SplitScreenController implements SplitScreen,
private final WindowManagerProxy mWindowManagerProxy;
private final TaskOrganizer mTaskOrganizer;
- private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
- new ArrayList<>();
+ private final CopyOnWriteArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners
+ = new CopyOnWriteArrayList<>();
private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
new ArrayList<>();
@@ -107,7 +112,8 @@ public class SplitScreenController implements SplitScreen,
public SplitScreenController(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
- ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue) {
+ ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
+ TaskStackListenerImpl taskStackListener) {
mContext = context;
mDisplayController = displayController;
mSystemWindows = systemWindows;
@@ -162,6 +168,40 @@ public class SplitScreenController implements SplitScreen,
mWindowManager = new DividerWindowManager(mSystemWindows);
mDisplayController.addDisplayWindowListener(this);
// Don't initialize the divider or anything until we get the default display.
+
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (!wasVisible || task.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || !mSplits.isSplitScreenSupported()) {
+ return;
+ }
+
+ if (isMinimized()) {
+ onUndockingTask();
+ }
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId,
+ int reason) {
+ mForcedResizableController.activityForcedResizable(packageName, taskId,
+ reason);
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ mForcedResizableController.activityDismissingSplitScreen();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
+ }
+ });
}
void onSplitScreenSupported() {
@@ -173,11 +213,6 @@ public class SplitScreenController implements SplitScreen,
}
@Override
- public boolean isSplitScreenSupported() {
- return mSplits.isSplitScreenSupported();
- }
-
- @Override
public void onKeyguardVisibilityChanged(boolean showing) {
if (!isSplitActive() || mView == null) {
return;
@@ -404,21 +439,6 @@ public class SplitScreenController implements SplitScreen,
}
@Override
- public void onActivityForcedResizable(String packageName, int taskId, int reason) {
- mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingSplitScreen() {
- mForcedResizableController.activityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
- }
-
- @Override
public void onUndockingTask() {
if (mView != null) {
mView.onUndockingTask();
@@ -459,6 +479,17 @@ public class SplitScreenController implements SplitScreen,
}
@Override
+ public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
+ synchronized (mDockedStackExistsListeners) {
+ for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) {
+ if (mDockedStackExistsListeners.get(i) == listener) {
+ mDockedStackExistsListeners.remove(i);
+ }
+ }
+ }
+ }
+
+ @Override
public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
synchronized (mBoundsChangedListeners) {
mBoundsChangedListeners.add(new WeakReference<>(listener));
@@ -481,9 +512,7 @@ public class SplitScreenController implements SplitScreen,
}
// Note: The set of running tasks from the system is ordered by recency.
final RunningTaskInfo topRunningTask = runningTasks.get(0);
-
- final int activityType = topRunningTask.configuration.windowConfiguration
- .getActivityType();
+ final int activityType = topRunningTask.getActivityType();
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
index 64e9d6618390..5b2b38ba8189 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
@@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import android.app.ActivityManager.RunningTaskInfo;
@@ -42,6 +41,7 @@ import com.android.wm.shell.Transitions;
import com.android.wm.shell.common.SyncTransactionQueue;
import java.io.PrintWriter;
+import java.util.ArrayList;
class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "SplitScreenTaskListener";
@@ -106,7 +106,7 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
return;
}
- final int winMode = getWindowingMode(taskInfo);
+ final int winMode = taskInfo.getWindowingMode();
if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
ProtoLog.v(WM_SHELL_TASK_ORG,
"%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId);
@@ -283,6 +283,21 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
mSplitScreenController.startEnterSplit();
}
} else if (secondaryImpliesMinimize) {
+ // Workaround for b/172686383, we can't rely on the sync bounds change transaction for
+ // the home task to finish before the last updateChildTaskSurface() call even if it's
+ // queued on the sync transaction queue, so ensure that the home task surface is updated
+ // again before we minimize
+ final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
+ mSplitScreenController.getWmProxy().getHomeAndRecentsTasks(tasks,
+ mSplitScreenController.getSecondaryRoot());
+ for (int i = 0; i < tasks.size(); i++) {
+ final RunningTaskInfo taskInfo = tasks.get(i);
+ final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
+ if (leash != null) {
+ updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
+ }
+ }
+
// Both splits are populated but the secondary split has a home/recents stack on top,
// so enter minimized mode.
mSplitScreenController.ensureMinimizedSplit();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
index c51bbeb7b6c2..0307206e2def 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
@@ -120,7 +120,7 @@ class WindowManagerProxy {
new WindowOrganizer().applyTransaction(t);
}
- private boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
+ boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
WindowContainerToken parent) {
boolean resizable = false;
List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
@@ -209,8 +209,7 @@ class WindowManagerProxy {
continue;
}
// Only move fullscreen tasks to split secondary.
- if (rootTask.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_FULLSCREEN) {
+ if (rootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
continue;
}
// Since this iterates from bottom to top, update topHomeTask for every fullscreen task
@@ -232,7 +231,7 @@ class WindowManagerProxy {
}
boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
- final int atype = ti.configuration.windowConfiguration.getActivityType();
+ final int atype = ti.getActivityType();
return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
new file mode 100644
index 000000000000..884287209d53
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.common;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.wm.shell.common.TaskStackListenerImpl}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class TaskStackListenerImplTest {
+
+ @Mock
+ private IActivityTaskManager mActivityTaskManager;
+
+ @Mock
+ private TaskStackListenerCallback mCallback;
+
+ @Mock
+ private TaskStackListenerCallback mOtherCallback;
+
+ private TaskStackListenerImpl mImpl;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mImpl = new TaskStackListenerImpl(mActivityTaskManager);
+ mImpl.setHandler(new ProxyToListenerImplHandler(mImpl));
+ mImpl.addListener(mCallback);
+ mImpl.addListener(mOtherCallback);
+ }
+
+ @Test
+ public void testAddRemoveMultipleListeners_ExpectRegisterUnregisterOnce()
+ throws RemoteException {
+ TaskStackListenerImpl impl = new TaskStackListenerImpl(mActivityTaskManager);
+ impl.setHandler(new ProxyToListenerImplHandler(impl));
+ reset(mActivityTaskManager);
+ impl.addListener(mCallback);
+ impl.addListener(mOtherCallback);
+ verify(mActivityTaskManager, times(1)).registerTaskStackListener(any());
+
+ impl.removeListener(mOtherCallback);
+ impl.removeListener(mCallback);
+ verify(mActivityTaskManager, times(1)).unregisterTaskStackListener(any());
+ }
+
+ @Test
+ public void testOnRecentTaskListUpdated() {
+ mImpl.onRecentTaskListUpdated();
+ verify(mCallback).onRecentTaskListUpdated();
+ verify(mOtherCallback).onRecentTaskListUpdated();
+ }
+
+ @Test
+ public void testOnRecentTaskListFrozenChanged() {
+ mImpl.onRecentTaskListFrozenChanged(true);
+ verify(mCallback).onRecentTaskListFrozenChanged(eq(true));
+ verify(mOtherCallback).onRecentTaskListFrozenChanged(eq(true));
+ }
+
+ @Test
+ public void testOnTaskStackChanged() {
+ mImpl.onTaskStackChanged();
+ verify(mCallback).onTaskStackChangedBackground();
+ verify(mCallback).onTaskStackChanged();
+ verify(mOtherCallback).onTaskStackChangedBackground();
+ verify(mOtherCallback).onTaskStackChanged();
+ }
+
+ @Test
+ public void testOnTaskProfileLocked() {
+ mImpl.onTaskProfileLocked(1, 2);
+ verify(mCallback).onTaskProfileLocked(eq(1), eq(2));
+ verify(mOtherCallback).onTaskProfileLocked(eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnTaskDisplayChanged() {
+ mImpl.onTaskDisplayChanged(1, 2);
+ verify(mCallback).onTaskDisplayChanged(eq(1), eq(2));
+ verify(mOtherCallback).onTaskDisplayChanged(eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnTaskCreated() {
+ mImpl.onTaskCreated(1, new ComponentName("a", "b"));
+ verify(mCallback).onTaskCreated(eq(1), eq(new ComponentName("a", "b")));
+ verify(mOtherCallback).onTaskCreated(eq(1), eq(new ComponentName("a", "b")));
+ }
+
+ @Test
+ public void testOnTaskRemoved() {
+ mImpl.onTaskRemoved(123);
+ verify(mCallback).onTaskRemoved(eq(123));
+ verify(mOtherCallback).onTaskRemoved(eq(123));
+ }
+
+ @Test
+ public void testOnTaskMovedToFront() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onTaskMovedToFront(info);
+ verify(mCallback).onTaskMovedToFront(eq(info));
+ verify(mOtherCallback).onTaskMovedToFront(eq(info));
+ }
+
+ @Test
+ public void testOnTaskDescriptionChanged() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onTaskDescriptionChanged(info);
+ verify(mCallback).onTaskDescriptionChanged(eq(info));
+ verify(mOtherCallback).onTaskDescriptionChanged(eq(info));
+ }
+
+ @Test
+ public void testOnTaskSnapshotChanged() {
+ ActivityManager.TaskSnapshot snapshot = mock(ActivityManager.TaskSnapshot.class);
+ mImpl.onTaskSnapshotChanged(123, snapshot);
+ verify(mCallback).onTaskSnapshotChanged(eq(123), eq(snapshot));
+ verify(mOtherCallback).onTaskSnapshotChanged(eq(123), eq(snapshot));
+ }
+
+ @Test
+ public void testOnBackPressedOnTaskRoot() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onBackPressedOnTaskRoot(info);
+ verify(mCallback).onBackPressedOnTaskRoot(eq(info));
+ verify(mOtherCallback).onBackPressedOnTaskRoot(eq(info));
+ }
+
+ @Test
+ public void testOnActivityRestartAttempt() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onActivityRestartAttempt(info, true, true, true);
+ verify(mCallback).onActivityRestartAttempt(eq(info), eq(true), eq(true), eq(true));
+ verify(mOtherCallback).onActivityRestartAttempt(eq(info), eq(true), eq(true), eq(true));
+ }
+
+ @Test
+ public void testOnActivityPinned() {
+ mImpl.onActivityPinned("abc", 1, 2, 3);
+ verify(mCallback).onActivityPinned(eq("abc"), eq(1), eq(2), eq(3));
+ verify(mOtherCallback).onActivityPinned(eq("abc"), eq(1), eq(2), eq(3));
+ }
+
+ @Test
+ public void testOnActivityUnpinned() {
+ mImpl.onActivityUnpinned();
+ verify(mCallback).onActivityUnpinned();
+ verify(mOtherCallback).onActivityUnpinned();
+ }
+
+ @Test
+ public void testOnActivityForcedResizable() {
+ mImpl.onActivityForcedResizable("abc", 1, 2);
+ verify(mCallback).onActivityForcedResizable(eq("abc"), eq(1), eq(2));
+ verify(mOtherCallback).onActivityForcedResizable(eq("abc"), eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnActivityDismissingDockedStack() {
+ mImpl.onActivityDismissingDockedStack();
+ verify(mCallback).onActivityDismissingDockedStack();
+ verify(mOtherCallback).onActivityDismissingDockedStack();
+ }
+
+ @Test
+ public void testOnActivityLaunchOnSecondaryDisplayFailed() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onActivityLaunchOnSecondaryDisplayFailed(info, 1);
+ verify(mCallback).onActivityLaunchOnSecondaryDisplayFailed(eq(info));
+ verify(mOtherCallback).onActivityLaunchOnSecondaryDisplayFailed(eq(info));
+ }
+
+ @Test
+ public void testOnActivityLaunchOnSecondaryDisplayRerouted() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onActivityLaunchOnSecondaryDisplayRerouted(info, 1);
+ verify(mCallback).onActivityLaunchOnSecondaryDisplayRerouted(eq(info));
+ verify(mOtherCallback).onActivityLaunchOnSecondaryDisplayRerouted(eq(info));
+ }
+
+ @Test
+ public void testOnActivityRequestedOrientationChanged() {
+ mImpl.onActivityRequestedOrientationChanged(1, 2);
+ verify(mCallback).onActivityRequestedOrientationChanged(eq(1), eq(2));
+ verify(mOtherCallback).onActivityRequestedOrientationChanged(eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnActivityRotation() {
+ mImpl.onActivityRotation(123);
+ verify(mCallback).onActivityRotation(eq(123));
+ verify(mOtherCallback).onActivityRotation(eq(123));
+ }
+
+ @Test
+ public void testOnSizeCompatModeActivityChanged() {
+ IBinder b = mock(IBinder.class);
+ mImpl.onSizeCompatModeActivityChanged(123, b);
+ verify(mCallback).onSizeCompatModeActivityChanged(eq(123), eq(b));
+ verify(mOtherCallback).onSizeCompatModeActivityChanged(eq(123), eq(b));
+ }
+
+ /**
+ * Handler that synchronously calls TaskStackListenerImpl#handleMessage() when it receives a
+ * message.
+ */
+ private class ProxyToListenerImplHandler extends Handler {
+ public ProxyToListenerImplHandler(Callback callback) {
+ super(callback);
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ return mImpl.handleMessage(msg);
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index affd7367f472..fad1f057267a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -35,6 +35,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -68,10 +69,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.function.Consumer;
/**
* Tests for the drag and drop policy.
@@ -124,6 +128,12 @@ public class DragAndDropPolicyTest {
doReturn(new Rect(50, 0, 100, 100)).when(divider)
.getNonMinimizedSplitScreenSecondaryBounds();
+ doAnswer((Answer<Void>) invocation -> {
+ Consumer<Boolean> callback = invocation.getArgument(0);
+ callback.accept(true);
+ return null;
+ }).when(mSplitScreen).registerInSplitScreenListener(any());
+
mPolicy = new DragAndDropPolicy(mContext, mIActivityTaskManager, mSplitScreen, mStarter);
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 3645f1e56f92..8ef077e5f857 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -33,6 +33,7 @@ import android.view.Display;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.Before;
import org.junit.Ignore;
@@ -64,6 +65,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
OneHandedTimeoutHandler mMockTimeoutHandler;
@Mock
IOverlayManager mMockOverlayManager;
+ @Mock
+ TaskStackListenerImpl mMockTaskStackListener;
@Before
public void setUp() throws Exception {
@@ -76,7 +79,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
mMockTouchHandler,
mMockTutorialHandler,
mMockGestureHandler,
- mMockOverlayManager);
+ mMockOverlayManager,
+ mMockTaskStackListener);
mOneHandedController = Mockito.spy(oneHandedController);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 3341c9cbacb9..ba8c737924f4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -25,6 +25,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.Before;
import org.junit.Test;
@@ -47,6 +48,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
@Mock
IOverlayManager mMockOverlayManager;
+ @Mock
+ TaskStackListenerImpl mMockTaskStackListener;
@Before
public void setUp() {
@@ -60,7 +63,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
mTouchHandler,
mTutorialHandler,
mGestureHandler,
- mMockOverlayManager);
+ mMockOverlayManager,
+ mMockTaskStackListener);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index a00a3b6a654e..745d18804f0b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -39,6 +39,7 @@ import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
@@ -68,6 +69,7 @@ public class PipControllerTest extends ShellTestCase {
@Mock private PipTouchHandler mMockPipTouchHandler;
@Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
@Mock private PipBoundsState mMockPipBoundsState;
+ @Mock private TaskStackListenerImpl mMockTaskStackListener;
@Mock private ShellExecutor mMockExecutor;
@Before
@@ -76,7 +78,8 @@ public class PipControllerTest extends ShellTestCase {
mPipController = new PipController(mContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
- mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor);
+ mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
+ mMockExecutor);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
@@ -108,7 +111,8 @@ public class PipControllerTest extends ShellTestCase {
assertNull(PipController.create(spyContext, mMockDisplayController,
mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
- mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor));
+ mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
+ mMockExecutor));
}
@Test
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index 27e4c85e1e02..bf23a49df2c3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -36,6 +36,7 @@ import java.io.PrintWriter;
/**
* Manages the input consumer that allows the SystemUI to directly receive input.
+ * TODO: Refactor this for the gesture nav case
*/
public class InputConsumerController {
@@ -99,14 +100,6 @@ public class InputConsumerController {
}
/**
- * @return A controller for the pip input consumer.
- */
- public static InputConsumerController getPipInputConsumer() {
- return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(),
- INPUT_CONSUMER_PIP);
- }
-
- /**
* @return A controller for the recents animation input consumer.
*/
public static InputConsumerController getRecentsAnimationInputConsumer() {
@@ -155,7 +148,6 @@ public class InputConsumerController {
if (mInputEventReceiver == null) {
final InputChannel inputChannel = new InputChannel();
try {
- // TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
@@ -175,7 +167,6 @@ public class InputConsumerController {
public void unregisterInputConsumer() {
if (mInputEventReceiver != null) {
try {
- // TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
} catch (RemoteException e) {
Log.e(TAG, "Failed to destroy input consumer", e);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 17bb40e69e27..f073ced0bcee 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -118,10 +118,7 @@ public class SystemUIFactory {
.setBubbles(Optional.ofNullable(null))
.setShellDump(Optional.ofNullable(null));
}
- mSysUIComponent = builder
- .setInputConsumerController(mWMComponent.getInputConsumerController())
- .setShellTaskOrganizer(mWMComponent.getShellTaskOrganizer())
- .build();
+ mSysUIComponent = builder.build();
if (initializeComponents) {
mSysUIComponent.init();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index b94a68b2441d..54aeab50763f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,11 +22,9 @@ import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
import com.android.wm.shell.ShellDump;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
@@ -68,12 +66,6 @@ public interface SysUIComponent {
Builder setBubbles(Optional<Bubbles> b);
@BindsInstance
- Builder setInputConsumerController(InputConsumerController i);
-
- @BindsInstance
- Builder setShellTaskOrganizer(ShellTaskOrganizer s);
-
- @BindsInstance
Builder setShellDump(Optional<ShellDump> shellDump);
SysUIComponent build();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 8f3d8eaac2d3..9154ddba5d88 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -16,11 +16,9 @@
package com.android.systemui.dagger;
-import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.wmshell.WMShellModule;
import com.android.wm.shell.ShellDump;
import com.android.wm.shell.ShellInit;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
@@ -60,14 +58,6 @@ public interface WMComponent {
@WMSingleton
Optional<ShellDump> getShellDump();
- // TODO(b/162923491): Refactor this out so Pip doesn't need to inject this
- @WMSingleton
- InputConsumerController getInputConsumerController();
-
- // TODO(b/162923491): To be removed once Bubbles migrates over to the Shell
- @WMSingleton
- ShellTaskOrganizer getShellTaskOrganizer();
-
// TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
// depending on the threading mechanism we go with
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 5caab6ab0e7e..694b4a03fa64 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipBoundsState;
@@ -54,6 +55,7 @@ public abstract class TvPipModule {
PipTaskOrganizer pipTaskOrganizer,
PipMediaController pipMediaController,
PipNotification pipNotification,
+ TaskStackListenerImpl taskStackListener,
WindowManagerShellWrapper windowManagerShellWrapper) {
return Optional.of(
new PipController(
@@ -63,6 +65,7 @@ public abstract class TvPipModule {
pipTaskOrganizer,
pipMediaController,
pipNotification,
+ taskStackListener,
windowManagerShellWrapper));
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 294c749a2abe..f88bedd88d9f 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -27,6 +27,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -57,8 +58,9 @@ public class TvWMShellModule {
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue) {
+ SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
return new SplitScreenController(context, displayController, systemWindows,
- displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue);
+ displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
+ taskStackListener);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index f896891c5039..7a244389a3bc 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -55,7 +55,6 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.tracing.ProtoTraceable;
@@ -71,7 +70,6 @@ import com.android.wm.shell.onehanded.OneHandedEvents;
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogImpl;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -100,9 +98,7 @@ public final class WMShell extends SystemUI
private final CommandQueue mCommandQueue;
private final ConfigurationController mConfigurationController;
- private final InputConsumerController mInputConsumerController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final TaskStackChangeListeners mTaskStackChangeListeners;
private final NavigationModeController mNavigationModeController;
private final ScreenLifecycle mScreenLifecycle;
private final SysUiState mSysUiState;
@@ -120,9 +116,7 @@ public final class WMShell extends SystemUI
@Inject
public WMShell(Context context, CommandQueue commandQueue,
ConfigurationController configurationController,
- InputConsumerController inputConsumerController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- TaskStackChangeListeners taskStackChangeListeners,
NavigationModeController navigationModeController,
ScreenLifecycle screenLifecycle,
SysUiState sysUiState,
@@ -134,9 +128,7 @@ public final class WMShell extends SystemUI
super(context);
mCommandQueue = commandQueue;
mConfigurationController = configurationController;
- mInputConsumerController = inputConsumerController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mTaskStackChangeListeners = taskStackChangeListeners;
mNavigationModeController = navigationModeController;
mScreenLifecycle = screenLifecycle;
mSysUiState = sysUiState;
@@ -192,58 +184,6 @@ public final class WMShell extends SystemUI
}
});
- // TODO: Move this into the shell
- // Handle for system task stack changes.
- mTaskStackChangeListeners.registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onTaskStackChanged() {
- pip.onTaskStackChanged();
- }
-
- @Override
- public void onActivityPinned(String packageName, int userId, int taskId,
- int stackId) {
- pip.onActivityPinned(packageName);
- mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
- }
-
- @Override
- public void onActivityUnpinned() {
- final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPipActivity(mContext);
- final ComponentName topActivity = topPipActivityInfo.first;
- pip.onActivityUnpinned(topActivity);
- mInputConsumerController.unregisterInputConsumer();
- }
-
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- pip.onActivityRestartAttempt(task, clearedTask);
- }
- });
-
- try {
- RootTaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (taskInfo != null) {
- // If SystemUI restart, and it already existed a pinned stack,
- // register the pip input consumer to ensure touch can send to it.
- mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
- }
- } catch (RemoteException | UnsupportedOperationException e) {
- Log.e(TAG, "Failed to register pinned stack listener", e);
- e.printStackTrace();
- }
-
- // Register the listener for input consumer touch events. Only for Phone
- if (pip.getPipTouchHandler() != null) {
- mInputConsumerController.setInputListener(pip.getPipTouchHandler()::handleTouchEvent);
- mInputConsumerController.setRegistrationListener(
- pip.getPipTouchHandler()::onRegistrationChanged);
- }
-
// The media session listener needs to be re-registered when switching users
UserInfoController userInfoController = Dependency.get(UserInfoController.class);
userInfoController.addCallback((String name, Drawable picture, String userAccount) ->
@@ -263,39 +203,6 @@ public final class WMShell extends SystemUI
}
};
mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
-
- mTaskStackChangeListeners.registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !splitScreen.isSplitScreenSupported()) {
- return;
- }
-
- if (splitScreen.isMinimized()) {
- splitScreen.onUndockingTask();
- }
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- splitScreen.onActivityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- splitScreen.onActivityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- splitScreen.onActivityLaunchOnSecondaryDisplayFailed();
- }
- });
}
@VisibleForTesting
@@ -375,21 +282,6 @@ public final class WMShell extends SystemUI
}
}
});
-
- mTaskStackChangeListeners.registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onTaskCreated(int taskId, ComponentName componentName) {
- oneHanded.stopOneHanded(
- OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
- }
-
- @Override
- public void onTaskMovedToFront(int taskId) {
- oneHanded.stopOneHanded(
- OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
- }
- });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index bdca503f40c1..6546ed5577b1 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -43,6 +43,7 @@ import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHanded;
@@ -116,12 +117,6 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static InputConsumerController provideInputConsumerController() {
- return InputConsumerController.getPipInputConsumer();
- }
-
- @WMSingleton
- @Provides
static FloatingContentCoordinator provideFloatingContentCoordinator() {
return new FloatingContentCoordinator();
}
@@ -181,6 +176,12 @@ public abstract class WMShellBaseModule {
mainExecutor, AnimationThread.instance().getExecutor());
}
+ @WMSingleton
+ @Provides
+ static TaskStackListenerImpl providerTaskStackListenerImpl(@Main Handler handler) {
+ return new TaskStackListenerImpl(handler);
+ }
+
@BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
@@ -203,8 +204,9 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static Optional<OneHanded> provideOneHandedController(Context context,
- DisplayController displayController) {
- return Optional.ofNullable(OneHandedController.create(context, displayController));
+ DisplayController displayController, TaskStackListenerImpl taskStackListener) {
+ return Optional.ofNullable(OneHandedController.create(context, displayController,
+ taskStackListener));
}
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 25ca7ade6077..1cdec27af870 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -30,6 +30,7 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
@@ -72,9 +73,10 @@ public class WMShellModule {
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue) {
+ SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
return new SplitScreenController(context, displayController, systemWindows,
- displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue);
+ displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
+ taskStackListener);
}
@WMSingleton
@@ -84,11 +86,11 @@ public class WMShellModule {
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
- ShellExecutor mainExecutor) {
+ TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
return Optional.ofNullable(PipController.create(context, displayController,
pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController,
pipMenuActivityController, pipTaskOrganizer, pipTouchHandler,
- windowManagerShellWrapper, mainExecutor));
+ windowManagerShellWrapper, taskStackListener, mainExecutor));
}
@WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index d0bf281f343f..6a303a941960 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -62,7 +62,6 @@ public class WMShellTest extends SysuiTestCase {
@Mock CommandQueue mCommandQueue;
@Mock ConfigurationController mConfigurationController;
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock TaskStackChangeListeners mTaskStackChangeListeners;
@Mock InputConsumerController mMockInputConsumerController;
@Mock NavigationModeController mNavigationModeController;
@Mock ScreenLifecycle mScreenLifecycle;
@@ -77,13 +76,11 @@ public class WMShellTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mInputConsumerController = InputConsumerController.getPipInputConsumer();
mWMShell = new WMShell(mContext, mCommandQueue, mConfigurationController,
- mInputConsumerController, mKeyguardUpdateMonitor, mTaskStackChangeListeners,
- mNavigationModeController, mScreenLifecycle, mSysUiState, Optional.of(mPip),
- Optional.of(mSplitScreen), Optional.of(mOneHanded), mProtoTracer,
- Optional.of(mShellDump));
+ mKeyguardUpdateMonitor, mNavigationModeController,
+ mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
+ Optional.of(mOneHanded), mProtoTracer, Optional.of(mShellDump));
when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
}
@@ -100,8 +97,6 @@ public class WMShellTest extends SysuiTestCase {
mWMShell.initSplitScreen(mSplitScreen);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
- verify(mTaskStackChangeListeners).registerTaskStackListener(
- any(TaskStackChangeListener.class));
}
@Test
@@ -113,8 +108,6 @@ public class WMShellTest extends SysuiTestCase {
verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
verify(mNavigationModeController).addListener(
any(NavigationModeController.ModeChangedListener.class));
- verify(mTaskStackChangeListeners).registerTaskStackListener(
- any(TaskStackChangeListener.class));
verify(mOneHanded).registerGestureCallback(any(
OneHandedGestureHandler.OneHandedGestureEventCallback.class));
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 3eac1be3ebee..627af9149fe5 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -49,6 +49,7 @@ class DragDropController {
static final int MSG_DRAG_END_TIMEOUT = 0;
static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 1;
static final int MSG_ANIMATION_END = 2;
+ static final int MSG_REMOVE_DRAG_SURFACE_TIMEOUT = 3;
/**
* Drag state per operation.
@@ -384,6 +385,14 @@ class DragDropController {
}
break;
}
+
+ case MSG_REMOVE_DRAG_SURFACE_TIMEOUT: {
+ synchronized (mService.mGlobalLock) {
+ mService.mTransactionFactory.get()
+ .reparent((SurfaceControl) msg.obj, null).apply();
+ }
+ break;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 8c80205a9e45..e7d8ad690bc4 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -23,6 +23,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
+import static com.android.server.wm.DragDropController.MSG_REMOVE_DRAG_SURFACE_TIMEOUT;
import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -59,6 +60,7 @@ import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import com.android.internal.os.SomeArgs;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.view.IDragAndDropPermissions;
import com.android.server.LocalServices;
@@ -248,6 +250,9 @@ class DragState {
if (mSurfaceControl != null) {
if (!mRelinquishDragSurface) {
mTransaction.reparent(mSurfaceControl, null).apply();
+ } else {
+ mDragDropController.sendTimeoutMessage(MSG_REMOVE_DRAG_SURFACE_TIMEOUT,
+ mSurfaceControl);
}
mSurfaceControl = null;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1255bb2a02e9..86f1cf71e2e0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4071,6 +4071,10 @@ class Task extends WindowContainer<WindowContainer> {
info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.configuration.setTo(getConfiguration());
+ // Update to the task's current activity type and windowing mode which may differ from the
+ // window configuration
+ info.configuration.windowConfiguration.setActivityType(getActivityType());
+ info.configuration.windowConfiguration.setWindowingMode(getWindowingMode());
info.token = mRemoteToken.toWindowContainerToken();
//TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child