Merge "Move letterbox task positioning to LetterboxTaskListener."

This commit is contained in:
Mariia Sandrikova
2020-10-26 18:03:53 +00:00
committed by Android (Google) Code Review
10 changed files with 381 additions and 44 deletions

View File

@@ -24,6 +24,8 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
@@ -180,6 +182,20 @@ public class TaskInfo {
*/
public boolean isResizeable;
/**
* Activity bounds if this task or its top activity is presented in letterbox mode and
* {@code null} otherwise.
* @hide
*/
@Nullable
public Rect letterboxActivityBounds;
/**
* Relative position of the task's top left corner in the parent container.
* @hide
*/
public Point positionInParent;
/**
* The launch cookies associated with activities in this task if any.
* @see ActivityOptions#setLaunchCookie(IBinder)
@@ -256,6 +272,8 @@ public class TaskInfo {
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
isResizeable = source.readBoolean();
source.readBinderList(launchCookies);
letterboxActivityBounds = source.readTypedObject(Rect.CREATOR);
positionInParent = source.readTypedObject(Point.CREATOR);
}
/**
@@ -287,6 +305,8 @@ public class TaskInfo {
dest.writeTypedObject(topActivityInfo, flags);
dest.writeBoolean(isResizeable);
dest.writeBinderList(launchCookies);
dest.writeTypedObject(letterboxActivityBounds, flags);
dest.writeTypedObject(positionInParent, flags);
}
@Override
@@ -306,6 +326,9 @@ public class TaskInfo {
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
+ " topActivityInfo=" + topActivityInfo
+ " launchCookies" + launchCookies;
+ " launchCookies" + launchCookies
+ " letterboxActivityBounds=" + letterboxActivityBounds
+ " positionInParent=" + positionInParent
+ "}";
}
}

View File

@@ -55,6 +55,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-848099324": {
"message": "Letterbox Task Appeared: #%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/LetterboxTaskListener.java"
},
"-712674749": {
"message": "Clip description: %s",
"level": "VERBOSE",
@@ -115,12 +121,24 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"1104702476": {
"message": "Letterbox Task Changed: #%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/LetterboxTaskListener.java"
},
"1184615936": {
"message": "Set drop target window visibility: displayId=%d visibility=%d",
"level": "VERBOSE",
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
},
"1218010718": {
"message": "Letterbox Task Vanished: #%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/LetterboxTaskListener.java"
},
"1481772149": {
"message": "Current target: %s",
"level": "VERBOSE",

View File

@@ -20,9 +20,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCR
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
import android.app.ActivityManager;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.view.SurfaceControl;
@@ -39,7 +37,7 @@ class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
private final SyncTransactionQueue mSyncQueue;
private final ArrayMap<Integer, SurfaceControl> mTasks = new ArrayMap<>();
private final ArraySet<Integer> mTasks = new ArraySet<>();
FullscreenTaskListener(SyncTransactionQueue syncQueue) {
mSyncQueue = syncQueue;
@@ -48,17 +46,17 @@ class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
synchronized (mTasks) {
if (mTasks.containsKey(taskInfo.taskId)) {
if (mTasks.contains(taskInfo.taskId)) {
throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId);
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
taskInfo.taskId);
mTasks.put(taskInfo.taskId, leash);
mTasks.add(taskInfo.taskId);
mSyncQueue.runInSync(t -> {
// Reset several properties back to fullscreen (PiP, for example, leaves all these
// properties in a bad state).
updateSurfacePosition(t, taskInfo, leash);
t.setWindowCrop(leash, null);
t.setPosition(leash, 0, 0);
// TODO(shell-transitions): Eventually set everything in transition so there's no
// SF Transaction here.
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -73,7 +71,7 @@ class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
synchronized (mTasks) {
if (mTasks.remove(taskInfo.taskId) == null) {
if (!mTasks.remove(taskInfo.taskId)) {
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
return;
}
@@ -82,23 +80,6 @@ class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
synchronized (mTasks) {
if (!mTasks.containsKey(taskInfo.taskId)) {
Slog.e(TAG, "Changed Task wasn't appeared or already vanished: #"
+ taskInfo.taskId);
return;
}
final SurfaceControl leash = mTasks.get(taskInfo.taskId);
mSyncQueue.runInSync(t -> {
// Reposition the task in case the bounds has been changed (such as Task level
// letterboxing).
updateSurfacePosition(t, taskInfo, leash);
});
}
}
@Override
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
@@ -112,12 +93,4 @@ class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
}
/** Places the Task surface to the latest position. */
private static void updateSurfacePosition(SurfaceControl.Transaction t,
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
// TODO(170725334) drop this after ag/12876439
final Configuration config = taskInfo.getConfiguration();
final Rect bounds = config.windowConfiguration.getBounds();
t.setPosition(leash, bounds.left, bounds.top);
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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.graphics.Point;
import android.graphics.Rect;
import android.util.Slog;
import android.util.SparseArray;
import android.view.SurfaceControl;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
/**
* Organizes a task in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN} when
* it's presented in the letterbox mode either because orientations of a top activity and a device
* don't match or because a top activity is in a size compat mode.
*/
final class LetterboxTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "LetterboxTaskListener";
private final SyncTransactionQueue mSyncQueue;
private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
LetterboxTaskListener(SyncTransactionQueue syncQueue) {
mSyncQueue = syncQueue;
}
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
synchronized (mLeashByTaskId) {
if (mLeashByTaskId.get(taskInfo.taskId) != null) {
throw new RuntimeException("Task appeared more than once: #" + taskInfo.taskId);
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Letterbox Task Appeared: #%d",
taskInfo.taskId);
mLeashByTaskId.put(taskInfo.taskId, leash);
final Rect taskBounds = taskInfo.getConfiguration().windowConfiguration.getBounds();
final Rect activtyBounds = taskInfo.letterboxActivityBounds;
final Point taskPositionInParent = taskInfo.positionInParent;
mSyncQueue.runInSync(t -> {
setPositionAndWindowCrop(
t, leash, activtyBounds, taskBounds, taskPositionInParent);
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
t.setAlpha(leash, 1f);
t.setMatrix(leash, 1, 0, 0, 1);
t.show(leash);
}
});
}
}
@Override
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
synchronized (mLeashByTaskId) {
if (mLeashByTaskId.get(taskInfo.taskId) == null) {
Slog.e(TAG, "Task already vanished: #" + taskInfo.taskId);
return;
}
mLeashByTaskId.remove(taskInfo.taskId);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Letterbox Task Vanished: #%d",
taskInfo.taskId);
}
}
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
synchronized (mLeashByTaskId) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Letterbox Task Changed: #%d",
taskInfo.taskId);
final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
final Rect taskBounds = taskInfo.getConfiguration().windowConfiguration.getBounds();
final Rect activtyBounds = taskInfo.letterboxActivityBounds;
final Point taskPositionInParent = taskInfo.positionInParent;
mSyncQueue.runInSync(t -> {
setPositionAndWindowCrop(
t, leash, activtyBounds, taskBounds, taskPositionInParent);
});
}
}
private static void setPositionAndWindowCrop(
SurfaceControl.Transaction transaction,
SurfaceControl leash,
final Rect activityBounds,
final Rect taskBounds,
final Point taskPositionInParent) {
Rect activtyInTaskCoordinates = new Rect(activityBounds);
activtyInTaskCoordinates.offset(-taskBounds.left, -taskBounds.top);
transaction.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
transaction.setWindowCrop(leash, activtyInTaskCoordinates);
}
}

View File

@@ -45,7 +45,6 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -65,6 +64,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3;
public static final int TASK_LISTENER_TYPE_PIP = -4;
public static final int TASK_LISTENER_TYPE_SPLIT_SCREEN = -5;
public static final int TASK_LISTENER_TYPE_LETTERBOX = -6;
@IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = {
TASK_LISTENER_TYPE_UNDEFINED,
@@ -72,6 +72,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
TASK_LISTENER_TYPE_MULTI_WINDOW,
TASK_LISTENER_TYPE_PIP,
TASK_LISTENER_TYPE_SPLIT_SCREEN,
TASK_LISTENER_TYPE_LETTERBOX,
})
public @interface TaskListenerType {}
@@ -118,6 +119,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
ShellExecutor mainExecutor, ShellExecutor animExecutor) {
super(taskOrganizerController, mainExecutor);
addListenerForType(new FullscreenTaskListener(syncQueue), TASK_LISTENER_TYPE_FULLSCREEN);
addListenerForType(new LetterboxTaskListener(syncQueue), TASK_LISTENER_TYPE_LETTERBOX);
mTransitions = new Transitions(this, transactionPool, mainExecutor, animExecutor);
if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
}
@@ -329,8 +331,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
if (listener != null) return listener;
// Next we try type specific listeners.
final int windowingMode = getWindowingMode(runningTaskInfo);
final int taskListenerType = windowingModeToTaskListenerType(windowingMode);
final int taskListenerType = taskInfoToTaskListenerType(runningTaskInfo);
return mTaskListeners.get(taskListenerType);
}
@@ -339,11 +340,14 @@ public class ShellTaskOrganizer extends TaskOrganizer {
return taskInfo.configuration.windowConfiguration.getWindowingMode();
}
private static @TaskListenerType int windowingModeToTaskListenerType(
@WindowingMode int windowingMode) {
@VisibleForTesting
static @TaskListenerType int taskInfoToTaskListenerType(RunningTaskInfo runningTaskInfo) {
final int windowingMode = getWindowingMode(runningTaskInfo);
switch (windowingMode) {
case WINDOWING_MODE_FULLSCREEN:
return TASK_LISTENER_TYPE_FULLSCREEN;
return runningTaskInfo.letterboxActivityBounds != null
? TASK_LISTENER_TYPE_LETTERBOX
: TASK_LISTENER_TYPE_FULLSCREEN;
case WINDOWING_MODE_MULTI_WINDOW:
return TASK_LISTENER_TYPE_MULTI_WINDOW;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
@@ -362,6 +366,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
switch (type) {
case TASK_LISTENER_TYPE_FULLSCREEN:
return "TASK_LISTENER_TYPE_FULLSCREEN";
case TASK_LISTENER_TYPE_LETTERBOX:
return "TASK_LISTENER_TYPE_LETTERBOX";
case TASK_LISTENER_TYPE_MULTI_WINDOW:
return "TASK_LISTENER_TYPE_MULTI_WINDOW";
case TASK_LISTENER_TYPE_SPLIT_SCREEN:

View File

@@ -0,0 +1,125 @@
/*
* 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 static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.mockito.ArgumentMatchers.eq;
import android.app.ActivityManager.RunningTaskInfo;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.view.SurfaceControl;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
* Tests for {@link LetterboxTaskListener}.
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class LetterboxTaskListenerTest {
private static final Rect ACTIVITY_BOUNDS = new Rect(300, 200, 700, 400);
private static final Rect TASK_BOUNDS = new Rect(200, 100, 800, 500);
private static final Rect TASK_BOUNDS_2 = new Rect(300, 200, 800, 500);
private static final Point TASK_POSITION_IN_PARENT = new Point(100, 50);
private static final Point TASK_POSITION_IN_PARENT_2 = new Point(200, 100);
private static final Rect EXPECTED_WINDOW_CROP = new Rect(100, 100, 500, 300);
private static final Rect EXPECTED_WINDOW_CROP_2 = new Rect(0, 0, 400, 200);
private static final RunningTaskInfo TASK_INFO = createTaskInfo(
/* taskId */ 1, ACTIVITY_BOUNDS, TASK_BOUNDS, TASK_POSITION_IN_PARENT);
private static final RunningTaskInfo TASK_INFO_2 = createTaskInfo(
/* taskId */ 1, ACTIVITY_BOUNDS, TASK_BOUNDS_2, TASK_POSITION_IN_PARENT_2);
@Mock private SurfaceControl mLeash;
@Mock private SurfaceControl.Transaction mTransaction;
private LetterboxTaskListener mLetterboxTaskListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mLetterboxTaskListener = new LetterboxTaskListener(
new SyncTransactionQueue(
new TransactionPool() {
@Override
public SurfaceControl.Transaction acquire() {
return mTransaction;
}
@Override
public void release(SurfaceControl.Transaction t) {
}
},
new Handler(Looper.getMainLooper())));
}
@Test
public void testOnTaskAppearedAndonTaskInfoChanged_setCorrectPositionAndCrop() {
mLetterboxTaskListener.onTaskAppeared(TASK_INFO, mLeash);
verify(mTransaction).setPosition(
eq(mLeash),
eq((float) TASK_POSITION_IN_PARENT.x),
eq((float) TASK_POSITION_IN_PARENT.y));
// Should return activty coordinates offset by task coordinates
verify(mTransaction).setWindowCrop(eq(mLeash), eq(EXPECTED_WINDOW_CROP));
mLetterboxTaskListener.onTaskInfoChanged(TASK_INFO_2);
verify(mTransaction).setPosition(
eq(mLeash),
eq((float) TASK_POSITION_IN_PARENT_2.x),
eq((float) TASK_POSITION_IN_PARENT_2.y));
// Should return activty coordinates offset by task coordinates
verify(mTransaction).setWindowCrop(eq(mLeash), eq(EXPECTED_WINDOW_CROP_2));
}
@Test(expected = RuntimeException.class)
public void testOnTaskAppeared_calledSecondTimeWithSameTaskId_throwsException() {
mLetterboxTaskListener.onTaskAppeared(TASK_INFO, mLeash);
mLetterboxTaskListener.onTaskAppeared(TASK_INFO, mLeash);
}
private static RunningTaskInfo createTaskInfo(
int taskId,
final Rect activityBounds,
final Rect taskBounds,
final Point taskPositionInParent) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
taskInfo.configuration.windowConfiguration.setBounds(taskBounds);
taskInfo.letterboxActivityBounds = Rect.copyOrNull(activityBounds);
taskInfo.positionInParent = new Point(taskPositionInParent);
return taskInfo;
}
}

View File

@@ -16,15 +16,18 @@
package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FULLSCREEN;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_LETTERBOX;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -34,6 +37,7 @@ import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -42,6 +46,7 @@ import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.TaskAppearedInfo;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -242,10 +247,41 @@ public class ShellTaskOrganizerTests {
assertTrue(gotException);
}
private RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
@Test
public void testTaskInfoToTaskListenerType_whenLetterboxBoundsPassed_returnsLetterboxType() {
RunningTaskInfo taskInfo = createTaskInfo(
/* taskId */ 1,
WINDOWING_MODE_FULLSCREEN,
/* letterboxActivityBounds */ new Rect(1, 1, 1, 1));
assertEquals(
ShellTaskOrganizer.taskInfoToTaskListenerType(taskInfo),
TASK_LISTENER_TYPE_LETTERBOX);
}
@Test
public void testTaskInfoToTaskListenerType_whenLetterboxBoundsIsNull_returnsFullscreenType() {
RunningTaskInfo taskInfo = createTaskInfo(
/* taskId */ 1, WINDOWING_MODE_FULLSCREEN, /* letterboxActivityBounds */ null);
assertEquals(
ShellTaskOrganizer.taskInfoToTaskListenerType(taskInfo),
TASK_LISTENER_TYPE_FULLSCREEN);
}
private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
return taskInfo;
}
private static RunningTaskInfo createTaskInfo(
int taskId, int windowingMode, @Nullable Rect letterboxActivityBounds) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
taskInfo.letterboxActivityBounds = Rect.copyOrNull(letterboxActivityBounds);
return taskInfo;
}
}

View File

@@ -1364,6 +1364,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else if (mLetterbox != null) {
mLetterbox.hide();
}
task.maybeUpdateLetterboxBounds(this, getLetterboxParams(w));
}
void updateLetterboxSurface(WindowState winHint) {
@@ -1377,6 +1378,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
@Nullable
private Rect getLetterboxParams(WindowState w) {
boolean isLetterboxed = w.isLetterboxedAppWindow() && fillsParent();
return isLetterboxed ? getBounds() : null;
}
Rect getLetterboxInsets() {
if (mLetterbox != null) {
return mLetterbox.getInsets();

View File

@@ -528,6 +528,11 @@ class Task extends WindowContainer<WindowContainer> {
// {@link ActivityInfo#FLAG_SUPPORTS_PICTURE_IN_PICTURE} flag of the root activity.
boolean mSupportsPictureInPicture;
// Activity bounds if this task or its top activity is presented in letterbox mode and
// {@code null} otherwise.
@Nullable
private Rect mLetterboxActivityBounds;
// Whether the task is currently being drag-resized
private boolean mDragResizing;
private int mDragResizeMode;
@@ -4072,6 +4077,12 @@ class Task extends WindowContainer<WindowContainer> {
info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
info.topActivityType = top.getActivityType();
info.isResizeable = isResizeable();
// Don't query getTopNonFinishingActivity().getBounds() directly because when fillTaskInfo
// is triggered for the first time after activities change, getBounds() may return non final
// bounds, e.g. fullscreen bounds instead of letterboxed bounds. To work around this,
// assigning bounds from ActivityRecord#layoutLetterbox when they are ready.
info.letterboxActivityBounds = Rect.copyOrNull(mLetterboxActivityBounds);
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams();
info.topActivityInfo = mReuseActivitiesReport.top != null
@@ -4090,6 +4101,21 @@ class Task extends WindowContainer<WindowContainer> {
? null : rootActivity.pictureInPictureArgs;
}
void maybeUpdateLetterboxBounds(
ActivityRecord activityRecord, @Nullable Rect letterboxActivityBounds) {
if (isOrganized()
&& mReuseActivitiesReport.top == activityRecord
// Want to force update only if letterbox bounds have changed.
&& !Objects.equals(
mLetterboxActivityBounds,
letterboxActivityBounds)) {
mLetterboxActivityBounds = Rect.copyOrNull(letterboxActivityBounds);
// Forcing update to reduce visual jank during the transition.
mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
this, /* force= */ true);
}
}
/**
* Returns a {@link TaskInfo} with information from this task.
*/
@@ -7467,6 +7493,12 @@ class Task extends WindowContainer<WindowContainer> {
outPos.y -= outset;
}
private Point getRelativePosition() {
Point position = new Point();
getRelativePosition(position);
return position;
}
boolean shouldIgnoreInput() {
if (inSplitScreenPrimaryWindowingMode() && !isFocusable()) {
return true;

View File

@@ -53,6 +53,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Consumer;
@@ -475,6 +476,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
boolean changed = lastInfo == null
|| mTmpTaskInfo.topActivityType != lastInfo.topActivityType
|| mTmpTaskInfo.isResizeable != lastInfo.isResizeable
|| !Objects.equals(
mTmpTaskInfo.letterboxActivityBounds,
lastInfo.letterboxActivityBounds)
|| !Objects.equals(
mTmpTaskInfo.positionInParent,
lastInfo.positionInParent)
|| mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
|| mTmpTaskInfo.getConfiguration().windowConfiguration.getWindowingMode()
!= lastInfo.getConfiguration().windowConfiguration.getWindowingMode()