Merge "Organize Fullscreen tasks"
This commit is contained in:
@@ -1,6 +1,12 @@
|
|||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"messages": {
|
"messages": {
|
||||||
|
"-1501874464": {
|
||||||
|
"message": "Fullscreen Task Appeared: #%d",
|
||||||
|
"level": "VERBOSE",
|
||||||
|
"group": "WM_SHELL_TASK_ORG",
|
||||||
|
"at": "com\/android\/wm\/shell\/FullscreenTaskListener.java"
|
||||||
|
},
|
||||||
"-1340279385": {
|
"-1340279385": {
|
||||||
"message": "Remove listener=%s",
|
"message": "Remove listener=%s",
|
||||||
"level": "VERBOSE",
|
"level": "VERBOSE",
|
||||||
@@ -31,6 +37,12 @@
|
|||||||
"group": "WM_SHELL_TASK_ORG",
|
"group": "WM_SHELL_TASK_ORG",
|
||||||
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
|
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
|
||||||
},
|
},
|
||||||
|
"564235578": {
|
||||||
|
"message": "Fullscreen Task Vanished: #%d",
|
||||||
|
"level": "VERBOSE",
|
||||||
|
"group": "WM_SHELL_TASK_ORG",
|
||||||
|
"at": "com\/android\/wm\/shell\/FullscreenTaskListener.java"
|
||||||
|
},
|
||||||
"980952660": {
|
"980952660": {
|
||||||
"message": "Task root back pressed taskId=%d",
|
"message": "Task root back pressed taskId=%d",
|
||||||
"level": "VERBOSE",
|
"level": "VERBOSE",
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
import android.util.Slog;
|
||||||
|
import android.view.SurfaceControl;
|
||||||
|
|
||||||
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
|
|
||||||
|
class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||||
|
private static final String TAG = "FullscreenTaskOrg";
|
||||||
|
|
||||||
|
private final TransactionPool mTransactionPool;
|
||||||
|
|
||||||
|
private final ArraySet<Integer> mTasks = new ArraySet<>();
|
||||||
|
|
||||||
|
FullscreenTaskListener(TransactionPool transactionPool) {
|
||||||
|
mTransactionPool = transactionPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
|
||||||
|
synchronized (mTasks) {
|
||||||
|
if (mTasks.contains(taskInfo.taskId)) {
|
||||||
|
throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId);
|
||||||
|
}
|
||||||
|
mTasks.add(taskInfo.taskId);
|
||||||
|
final SurfaceControl.Transaction t = mTransactionPool.acquire();
|
||||||
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
|
||||||
|
taskInfo.taskId);
|
||||||
|
t.show(leash);
|
||||||
|
t.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
|
||||||
|
synchronized (mTasks) {
|
||||||
|
if (!mTasks.remove(taskInfo.taskId)) {
|
||||||
|
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
|
||||||
|
taskInfo.taskId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.wm.shell;
|
package com.android.wm.shell;
|
||||||
|
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
|
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -26,6 +28,7 @@ import android.window.TaskOrganizer;
|
|||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.protolog.common.ProtoLog;
|
import com.android.internal.protolog.common.ProtoLog;
|
||||||
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -56,13 +59,16 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
|||||||
// require us to report to both old and new listeners)
|
// require us to report to both old and new listeners)
|
||||||
private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
|
private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
|
||||||
|
|
||||||
public ShellTaskOrganizer() {
|
public ShellTaskOrganizer(TransactionPool transactionPool) {
|
||||||
super();
|
super();
|
||||||
|
addListener(new FullscreenTaskListener(transactionPool), WINDOWING_MODE_FULLSCREEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController) {
|
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController,
|
||||||
|
TransactionPool transactionPool) {
|
||||||
super(taskOrganizerController);
|
super(taskOrganizerController);
|
||||||
|
addListener(new FullscreenTaskListener(transactionPool), WINDOWING_MODE_FULLSCREEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,6 +131,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
|||||||
Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
|
Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
|
||||||
int winMode = getWindowingMode(taskInfo);
|
int winMode = getWindowingMode(taskInfo);
|
||||||
int prevWinMode = getWindowingMode(data.first);
|
int prevWinMode = getWindowingMode(data.first);
|
||||||
|
mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, data.second));
|
||||||
if (prevWinMode != -1 && prevWinMode != winMode) {
|
if (prevWinMode != -1 && prevWinMode != winMode) {
|
||||||
// TODO: We currently send vanished/appeared as the task moves between win modes, but
|
// TODO: We currently send vanished/appeared as the task moves between win modes, but
|
||||||
// we should consider adding a different mode-changed callback
|
// we should consider adding a different mode-changed callback
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
@@ -32,6 +33,8 @@ import android.window.ITaskOrganizerController;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.wm.shell.common.TransactionPool;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -51,6 +54,7 @@ public class ShellTaskOrganizerTests {
|
|||||||
private ITaskOrganizerController mTaskOrganizerController;
|
private ITaskOrganizerController mTaskOrganizerController;
|
||||||
|
|
||||||
ShellTaskOrganizer mOrganizer;
|
ShellTaskOrganizer mOrganizer;
|
||||||
|
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
|
||||||
|
|
||||||
private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener {
|
private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||||
final ArrayList<RunningTaskInfo> appeared = new ArrayList<>();
|
final ArrayList<RunningTaskInfo> appeared = new ArrayList<>();
|
||||||
@@ -81,7 +85,7 @@ public class ShellTaskOrganizerTests {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController);
|
mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController, mTransactionPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.android.systemui.shared.tracing.ProtoTraceable;
|
|||||||
import com.android.systemui.statusbar.CommandQueue;
|
import com.android.systemui.statusbar.CommandQueue;
|
||||||
import com.android.systemui.tracing.ProtoTracer;
|
import com.android.systemui.tracing.ProtoTracer;
|
||||||
import com.android.systemui.tracing.nano.SystemUiTraceProto;
|
import com.android.systemui.tracing.nano.SystemUiTraceProto;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
import com.android.wm.shell.nano.WmShellTraceProto;
|
import com.android.wm.shell.nano.WmShellTraceProto;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
@@ -76,6 +77,9 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
|
|||||||
private final Optional<Pip> mPipOptional;
|
private final Optional<Pip> mPipOptional;
|
||||||
private final Optional<SplitScreen> mSplitScreenOptional;
|
private final Optional<SplitScreen> mSplitScreenOptional;
|
||||||
private final Optional<OneHanded> mOneHandedOptional;
|
private final Optional<OneHanded> mOneHandedOptional;
|
||||||
|
// Inject the organizer directly in case the optionals aren't loaded to depend on it. There
|
||||||
|
// are non-optional windowing features like FULLSCREEN.
|
||||||
|
private final ShellTaskOrganizer mShellTaskOrganizer;
|
||||||
private final ProtoTracer mProtoTracer;
|
private final ProtoTracer mProtoTracer;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -89,6 +93,7 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
|
|||||||
Optional<Pip> pipOptional,
|
Optional<Pip> pipOptional,
|
||||||
Optional<SplitScreen> splitScreenOptional,
|
Optional<SplitScreen> splitScreenOptional,
|
||||||
Optional<OneHanded> oneHandedOptional,
|
Optional<OneHanded> oneHandedOptional,
|
||||||
|
ShellTaskOrganizer shellTaskOrganizer,
|
||||||
ProtoTracer protoTracer) {
|
ProtoTracer protoTracer) {
|
||||||
super(context);
|
super(context);
|
||||||
mCommandQueue = commandQueue;
|
mCommandQueue = commandQueue;
|
||||||
@@ -101,6 +106,7 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
|
|||||||
mPipOptional = pipOptional;
|
mPipOptional = pipOptional;
|
||||||
mSplitScreenOptional = splitScreenOptional;
|
mSplitScreenOptional = splitScreenOptional;
|
||||||
mOneHandedOptional = oneHandedOptional;
|
mOneHandedOptional = oneHandedOptional;
|
||||||
|
mShellTaskOrganizer = shellTaskOrganizer;
|
||||||
mProtoTracer = protoTracer;
|
mProtoTracer = protoTracer;
|
||||||
mProtoTracer.add(this);
|
mProtoTracer.add(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,8 +96,8 @@ public abstract class WMShellBaseModule {
|
|||||||
|
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
@Provides
|
@Provides
|
||||||
static ShellTaskOrganizer provideShellTaskOrganizer() {
|
static ShellTaskOrganizer provideShellTaskOrganizer(TransactionPool transactionPool) {
|
||||||
ShellTaskOrganizer organizer = new ShellTaskOrganizer();
|
ShellTaskOrganizer organizer = new ShellTaskOrganizer(transactionPool);
|
||||||
organizer.registerOrganizer();
|
organizer.registerOrganizer();
|
||||||
return organizer;
|
return organizer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
|
|||||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||||
import com.android.systemui.statusbar.CommandQueue;
|
import com.android.systemui.statusbar.CommandQueue;
|
||||||
import com.android.systemui.tracing.ProtoTracer;
|
import com.android.systemui.tracing.ProtoTracer;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
import com.android.wm.shell.common.DisplayImeController;
|
import com.android.wm.shell.common.DisplayImeController;
|
||||||
import com.android.wm.shell.onehanded.OneHanded;
|
import com.android.wm.shell.onehanded.OneHanded;
|
||||||
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
|
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
|
||||||
@@ -64,6 +65,7 @@ public class WMShellTest extends SysuiTestCase {
|
|||||||
@Mock Pip mPip;
|
@Mock Pip mPip;
|
||||||
@Mock SplitScreen mSplitScreen;
|
@Mock SplitScreen mSplitScreen;
|
||||||
@Mock OneHanded mOneHanded;
|
@Mock OneHanded mOneHanded;
|
||||||
|
@Mock ShellTaskOrganizer mTaskOrganizer;
|
||||||
@Mock ProtoTracer mProtoTracer;
|
@Mock ProtoTracer mProtoTracer;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -72,7 +74,7 @@ public class WMShellTest extends SysuiTestCase {
|
|||||||
mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor,
|
mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor,
|
||||||
mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
|
mActivityManagerWrapper, mDisplayImeController, mNavigationModeController,
|
||||||
mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
|
mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
|
||||||
Optional.of(mOneHanded), mProtoTracer);
|
Optional.of(mOneHanded), mTaskOrganizer, mProtoTracer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
|
||||||
import static android.view.Display.INVALID_DISPLAY;
|
import static android.view.Display.INVALID_DISPLAY;
|
||||||
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
|
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
|
||||||
@@ -308,10 +309,13 @@ final class InputMonitor {
|
|||||||
* This means we need to make sure that these changes in crop are reflected
|
* This means we need to make sure that these changes in crop are reflected
|
||||||
* in the input windows, and so ensure this flag is set so that
|
* in the input windows, and so ensure this flag is set so that
|
||||||
* the input crop always reflects the surface hierarchy.
|
* the input crop always reflects the surface hierarchy.
|
||||||
* we may have some issues with modal-windows, but I guess we can
|
*
|
||||||
* cross that bridge when we come to implementing full-screen TaskOrg
|
* TODO(b/168252846): we have some issues with modal-windows, so we need to
|
||||||
|
* cross that bridge now that we organize full-screen Tasks.
|
||||||
*/
|
*/
|
||||||
if (child.getTask() != null && child.getTask().isOrganized()) {
|
if (child.getTask() != null
|
||||||
|
&& child.getTask().isOrganized()
|
||||||
|
&& child.getTask().getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
|
||||||
inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
|
inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1393,7 +1393,8 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (display != null) {
|
if (display != null) {
|
||||||
// TODO(NOW!): Chat with the erosky@ of this code to see if this really makes sense here...
|
// TODO(b/168037178): Chat with the erosky@ of this code to see if this really makes
|
||||||
|
// sense here...
|
||||||
// Rotations are relative to the display. This means if there are 2 displays rotated
|
// Rotations are relative to the display. This means if there are 2 displays rotated
|
||||||
// differently (eg. 2 monitors with one landscape and one portrait), moving a stack
|
// differently (eg. 2 monitors with one landscape and one portrait), moving a stack
|
||||||
// from one to the other could look like a rotation change. To prevent this
|
// from one to the other could look like a rotation change. To prevent this
|
||||||
@@ -1407,11 +1408,16 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
|
|
||||||
super.onParentChanged(newParent, oldParent);
|
super.onParentChanged(newParent, oldParent);
|
||||||
|
|
||||||
// TODO(NOW): The check for null display content and setting it to null doesn't really
|
// Call this again after super onParentChanged in-case the surface wasn't created yet
|
||||||
// make sense here...
|
// (happens when the task is first inserted into the hierarchy). It's a no-op if it
|
||||||
|
// already ran fully within super.onParentChanged
|
||||||
|
updateTaskOrganizerState(false /* forceUpdate */);
|
||||||
|
|
||||||
// TODO(stack-merge): This is mostly taking care of the case where the stask is removing from
|
// TODO(b/168037178): The check for null display content and setting it to null doesn't
|
||||||
// the display, so we should probably consolidate it there instead.
|
// really make sense here...
|
||||||
|
|
||||||
|
// TODO(b/168037178): This is mostly taking care of the case where the stask is removing
|
||||||
|
// from the display, so we should probably consolidate it there instead.
|
||||||
|
|
||||||
if (getParent() == null && mDisplayContent != null) {
|
if (getParent() == null && mDisplayContent != null) {
|
||||||
EventLogTags.writeWmStackRemoved(getRootTaskId());
|
EventLogTags.writeWmStackRemoved(getRootTaskId());
|
||||||
@@ -4849,6 +4855,11 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
* @return {@code true} if task organizer changed.
|
* @return {@code true} if task organizer changed.
|
||||||
*/
|
*/
|
||||||
boolean updateTaskOrganizerState(boolean forceUpdate) {
|
boolean updateTaskOrganizerState(boolean forceUpdate) {
|
||||||
|
if (getSurfaceControl() == null) {
|
||||||
|
// Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
|
||||||
|
// is created.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!isRootTask()) {
|
if (!isRootTask()) {
|
||||||
return setTaskOrganizer(null);
|
return setTaskOrganizer(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,8 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
|
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
|
||||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
|
|
||||||
|
|
||||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
||||||
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
|
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
|
||||||
@@ -73,11 +71,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
// The set of modes that are currently supports
|
// The set of modes that are currently supports
|
||||||
// TODO: Remove once the task organizer can support all modes
|
// TODO: Remove once the task organizer can support all modes
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int[] SUPPORTED_WINDOWING_MODES = {
|
static final int[] UNSUPPORTED_WINDOWING_MODES = {
|
||||||
WINDOWING_MODE_PINNED,
|
WINDOWING_MODE_UNDEFINED,
|
||||||
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
|
WINDOWING_MODE_FREEFORM
|
||||||
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
|
|
||||||
WINDOWING_MODE_MULTI_WINDOW,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private final WindowManagerGlobalLock mGlobalLock;
|
private final WindowManagerGlobalLock mGlobalLock;
|
||||||
@@ -311,18 +307,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
synchronized (mGlobalLock) {
|
synchronized (mGlobalLock) {
|
||||||
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
|
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
|
||||||
organizer.asBinder(), uid);
|
organizer.asBinder(), uid);
|
||||||
for (int winMode : SUPPORTED_WINDOWING_MODES) {
|
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
|
||||||
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
|
mTaskOrganizers.add(organizer);
|
||||||
mTaskOrganizers.add(organizer);
|
mTaskOrganizerStates.put(organizer.asBinder(),
|
||||||
mTaskOrganizerStates.put(organizer.asBinder(),
|
new TaskOrganizerState(organizer, uid));
|
||||||
new TaskOrganizerState(organizer, uid));
|
|
||||||
}
|
|
||||||
mService.mRootWindowContainer.forAllTasks((task) -> {
|
|
||||||
if (task.getWindowingMode() == winMode) {
|
|
||||||
task.updateTaskOrganizerState(true /* forceUpdate */);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
mService.mRootWindowContainer.forAllTasks((task) -> {
|
||||||
|
if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, task.getWindowingMode())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task.updateTaskOrganizerState(true /* forceUpdate */);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(origId);
|
Binder.restoreCallingIdentity(origId);
|
||||||
@@ -360,12 +355,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSupportedWindowingMode(int winMode) {
|
private boolean isSupportedWindowingMode(int winMode) {
|
||||||
for (int i = 0; i < SUPPORTED_WINDOWING_MODES.length; i++) {
|
return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
|
||||||
if (SUPPORTED_WINDOWING_MODES[i] == winMode) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
|
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
|
||||||
@@ -659,21 +649,18 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|
|||||||
public void dump(PrintWriter pw, String prefix) {
|
public void dump(PrintWriter pw, String prefix) {
|
||||||
final String innerPrefix = prefix + " ";
|
final String innerPrefix = prefix + " ";
|
||||||
pw.print(prefix); pw.println("TaskOrganizerController:");
|
pw.print(prefix); pw.println("TaskOrganizerController:");
|
||||||
pw.print(innerPrefix); pw.println("Per windowing mode:");
|
for (final TaskOrganizerState state : mTaskOrganizerStates.values()) {
|
||||||
for (int i = 0; i < SUPPORTED_WINDOWING_MODES.length; i++) {
|
final ArrayList<Task> tasks = state.mOrganizedTasks;
|
||||||
final int windowingMode = SUPPORTED_WINDOWING_MODES[i];
|
pw.print(innerPrefix + " ");
|
||||||
pw.println(innerPrefix + " "
|
pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
|
||||||
+ WindowConfiguration.windowingModeToString(windowingMode) + ":");
|
for (int k = 0; k < tasks.size(); k++) {
|
||||||
for (final TaskOrganizerState state : mTaskOrganizerStates.values()) {
|
final Task task = tasks.get(k);
|
||||||
final ArrayList<Task> tasks = state.mOrganizedTasks;
|
final int mode = task.getWindowingMode();
|
||||||
pw.print(innerPrefix + " ");
|
if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, mode)) {
|
||||||
pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
|
continue;
|
||||||
for (int k = 0; k < tasks.size(); k++) {
|
|
||||||
final Task task = tasks.get(k);
|
|
||||||
if (windowingMode == task.getWindowingMode()) {
|
|
||||||
pw.println(innerPrefix + " " + task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pw.println(innerPrefix + " ("
|
||||||
|
+ WindowConfiguration.windowingModeToString(mode) + ") " + task);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
|
||||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||||
@@ -2464,8 +2465,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
|||||||
|
|
||||||
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
|
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
|
||||||
boolean isVoiceInteraction) {
|
boolean isVoiceInteraction) {
|
||||||
if (isOrganized()) {
|
if (isOrganized()
|
||||||
// Defer to the task organizer to run animations
|
// TODO(b/161711458): Clean-up when moved to shell.
|
||||||
|
&& getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -229,58 +229,32 @@ public class WindowOrganizerTests extends WindowTestsBase {
|
|||||||
final Task task3 = createTask(stack3);
|
final Task task3 = createTask(stack3);
|
||||||
final ITaskOrganizer organizer = registerMockOrganizer();
|
final ITaskOrganizer organizer = registerMockOrganizer();
|
||||||
|
|
||||||
// First organizer is registered, verify a task appears when changing windowing mode
|
// verify that tasks are appeared on registration
|
||||||
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
verify(organizer, times(3))
|
||||||
verify(organizer, times(1))
|
|
||||||
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
||||||
assertTrue(stack.isOrganized());
|
assertTrue(stack.isOrganized());
|
||||||
|
|
||||||
// Now we replace the registration and1 verify the new organizer receives tasks
|
// Now we replace the registration and1 verify the new organizer receives tasks
|
||||||
// newly entering the windowing mode.
|
|
||||||
final ITaskOrganizer organizer2 = registerMockOrganizer();
|
final ITaskOrganizer organizer2 = registerMockOrganizer();
|
||||||
stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
verify(organizer2, times(3))
|
||||||
// One each for task and task2
|
|
||||||
verify(organizer2, times(2))
|
|
||||||
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
||||||
verify(organizer2, times(0)).onTaskVanished(any());
|
verify(organizer2, times(0)).onTaskVanished(any());
|
||||||
// One for task
|
// One for task
|
||||||
verify(organizer).onTaskVanished(any());
|
verify(organizer, times(3)).onTaskVanished(any());
|
||||||
assertTrue(stack2.isOrganized());
|
assertTrue(stack2.isOrganized());
|
||||||
|
|
||||||
// Now we unregister the second one, the first one should automatically be reregistered
|
// Now we unregister the second one, the first one should automatically be reregistered
|
||||||
// so we verify that it's now seeing changes.
|
// so we verify that it's now seeing changes.
|
||||||
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
|
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
|
||||||
verify(organizer, times(3))
|
verify(organizer, times(6))
|
||||||
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
||||||
verify(organizer2, times(2)).onTaskVanished(any());
|
verify(organizer2, times(3)).onTaskVanished(any());
|
||||||
|
|
||||||
stack3.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
|
||||||
verify(organizer, times(4))
|
|
||||||
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
|
||||||
verify(organizer2, times(2)).onTaskVanished(any());
|
|
||||||
assertTrue(stack3.isOrganized());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRegisterTaskOrganizerStackWindowingModeChanges() throws RemoteException {
|
|
||||||
final ITaskOrganizer organizer = registerMockOrganizer();
|
|
||||||
|
|
||||||
final Task stack = createStack();
|
|
||||||
final Task task = createTask(stack);
|
|
||||||
final Task task2 = createTask(stack);
|
|
||||||
stack.setWindowingMode(WINDOWING_MODE_PINNED);
|
|
||||||
verify(organizer, times(1))
|
|
||||||
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
|
|
||||||
|
|
||||||
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
|
|
||||||
verify(organizer, times(1)).onTaskVanished(any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
|
public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
|
||||||
final Task stack = createStack();
|
final Task stack = createStack();
|
||||||
final Task task = createTask(stack);
|
final Task task = createTask(stack);
|
||||||
stack.setWindowingMode(WINDOWING_MODE_PINNED);
|
|
||||||
|
|
||||||
final ITaskOrganizer organizer = registerMockOrganizer();
|
final ITaskOrganizer organizer = registerMockOrganizer();
|
||||||
verify(organizer, times(1))
|
verify(organizer, times(1))
|
||||||
|
|||||||
Reference in New Issue
Block a user