From 70dd96cea7c07f42db96adf8690135fa2cab9612 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Mon, 12 Jul 2021 15:44:27 -0700 Subject: [PATCH] Fix letterbox issue when auto-enter-pip from landscape Included in this CL - Skip layout of window when in transition to PiP mode - Pass display cutout info via TaskInfo - Removed TaskInfoCompat Video: http://recall/-/aaaaaabFQoRHlzixHdtY/bpKcGg1eoOo5Jz5U6IwBYK Bug: 191310680 Test: manual, auto-enter-pip from landscape with source rect hint being turned on, see the video Change-Id: Ie657d15d9edb9d07555bd166b5919bb12cb217e6 --- core/java/android/app/TaskInfo.java | 15 +++++ .../shared/system/TaskInfoCompat.java | 67 ------------------- .../com/android/server/wm/ActivityRecord.java | 5 ++ .../com/android/server/wm/DisplayPolicy.java | 4 ++ .../server/wm/RootWindowContainer.java | 1 + .../core/java/com/android/server/wm/Task.java | 15 +++++ 6 files changed, 40 insertions(+), 67 deletions(-) delete mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 1569e6042ebf7..cac763988d5eb 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -29,11 +29,13 @@ import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Point; +import android.graphics.Rect; import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.util.Log; +import android.view.DisplayCutout; import android.window.TaskSnapshot; import android.window.WindowContainerToken; @@ -180,6 +182,15 @@ public class TaskInfo { @Nullable public PictureInPictureParams pictureInPictureParams; + /** + * The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of + * (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS), + * {@code null} otherwise. + * @hide + */ + @Nullable + public Rect displayCutoutInsets; + /** * The activity type of the top activity in this task. * @hide @@ -345,6 +356,7 @@ public class TaskInfo { && displayAreaFeatureId == that.displayAreaFeatureId && Objects.equals(positionInParent, that.positionInParent) && Objects.equals(pictureInPictureParams, that.pictureInPictureParams) + && Objects.equals(displayCutoutInsets, that.displayCutoutInsets) && getWindowingMode() == that.getWindowingMode() && Objects.equals(taskDescription, that.taskDescription) && isFocused == that.isFocused @@ -396,6 +408,7 @@ public class TaskInfo { token = WindowContainerToken.CREATOR.createFromParcel(source); topActivityType = source.readInt(); pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR); + displayCutoutInsets = source.readTypedObject(Rect.CREATOR); topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR); isResizeable = source.readBoolean(); source.readBinderList(launchCookies); @@ -435,6 +448,7 @@ public class TaskInfo { token.writeToParcel(dest, flags); dest.writeInt(topActivityType); dest.writeTypedObject(pictureInPictureParams, flags); + dest.writeTypedObject(displayCutoutInsets, flags); dest.writeTypedObject(topActivityInfo, flags); dest.writeBoolean(isResizeable); dest.writeBinderList(launchCookies); @@ -465,6 +479,7 @@ public class TaskInfo { + " token=" + token + " topActivityType=" + topActivityType + " pictureInPictureParams=" + pictureInPictureParams + + " displayCutoutSafeInsets=" + displayCutoutInsets + " topActivityInfo=" + topActivityInfo + " launchCookies=" + launchCookies + " positionInParent=" + positionInParent diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java deleted file mode 100644 index 7b9ebc0d4656f..0000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.shared.system; - -import android.app.ActivityManager; -import android.app.PictureInPictureParams; -import android.app.TaskInfo; -import android.content.ComponentName; -import android.content.pm.ActivityInfo; -import android.graphics.Rect; - -public class TaskInfoCompat { - - public static int getUserId(TaskInfo info) { - return info.userId; - } - - public static int getActivityType(TaskInfo info) { - return info.configuration.windowConfiguration.getActivityType(); - } - - public static int getWindowingMode(TaskInfo info) { - return info.configuration.windowConfiguration.getWindowingMode(); - } - - public static Rect getWindowConfigurationBounds(TaskInfo info) { - return info.configuration.windowConfiguration.getBounds(); - } - - public static boolean supportsSplitScreenMultiWindow(TaskInfo info) { - return info.supportsSplitScreenMultiWindow; - } - - public static ComponentName getTopActivity(TaskInfo info) { - return info.topActivity; - } - - public static ActivityManager.TaskDescription getTaskDescription(TaskInfo info) { - return info.taskDescription; - } - - public static ActivityInfo getTopActivityInfo(TaskInfo info) { - return info.topActivityInfo; - } - - public static boolean isAutoEnterPipEnabled(PictureInPictureParams params) { - return params.isAutoEnterEnabled(); - } - - public static Rect getPipSourceRectHint(PictureInPictureParams params) { - return params.getSourceRectHint(); - } -} diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 45eb7cdcbf6cb..0d03756628d4e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -830,6 +830,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Tracking cookie for the launch of this activity and it's task. IBinder mLaunchCookie; + // Entering PiP is usually done in two phases, we put the task into pinned mode first and + // SystemUi sets the pinned mode on activity after transition is done. + boolean mWaitForEnteringPinnedMode; + private final Runnable mPauseTimeoutRunnable = new Runnable() { @Override public void run() { @@ -7894,6 +7898,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // mode (see RootWindowContainer#moveActivityToPinnedRootTask). So once the windowing mode // of activity is changed, it is the signal of the last step to update the PiP states. if (!wasInPictureInPicture && inPinnedWindowingMode() && task != null) { + mWaitForEnteringPinnedMode = false; mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, task.getBounds()); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index d5a4345cb0734..22bb1afff532b 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1648,6 +1648,10 @@ public class DisplayPolicy { layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR)); return; } + if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) { + // Skip layout of the window when in transition to pip mode. + return; + } final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation); final int type = attrs.type; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 0b80bae71ab83..240fe9f4a8346 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2192,6 +2192,7 @@ class RootWindowContainer extends WindowContainer // from doing work and changing the activity visuals while animating // TODO(task-org): Figure-out more structured way to do this long term. r.setWindowingMode(intermediateWindowingMode); + r.mWaitForEnteringPinnedMode = true; rootTask.setWindowingMode(WINDOWING_MODE_PINNED); rootTask.setDeferTaskAppear(false); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index d8681f6a0c9d9..e8b696708ea66 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -54,6 +54,8 @@ import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.SurfaceControl.METADATA_TASK_ID; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; @@ -3335,6 +3337,7 @@ class Task extends TaskFragment { info.positionInParent = getRelativePosition(); info.pictureInPictureParams = getPictureInPictureParams(top); + info.displayCutoutInsets = getDisplayCutoutInsets(top); info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; @@ -3370,6 +3373,18 @@ class Task extends TaskFragment { ? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs); } + private Rect getDisplayCutoutInsets(Task top) { + if (top == null || top.mDisplayContent == null + || top.getDisplayInfo().displayCutout == null) return null; + final WindowState w = top.getTopVisibleAppMainWindow(); + final int displayCutoutMode = w == null + ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT + : w.getAttrs().layoutInDisplayCutoutMode; + return (displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + || displayCutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) + ? null : top.getDisplayInfo().displayCutout.getSafeInsets(); + } + /** * Returns a {@link TaskInfo} with information from this task. */