Merge "Handle alwaysOnTop in DisplayAreas." into tm-qpr-dev
This commit is contained in:
@@ -693,7 +693,39 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
.build();
|
||||
mHierarchyOps.add(hierarchyOp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets/removes the always on top flag for this {@code windowContainer}. See
|
||||
* {@link com.android.server.wm.ConfigurationContainer#setAlwaysOnTop(boolean)}.
|
||||
* Please note that this method is only intended to be used for a
|
||||
* {@link com.android.server.wm.DisplayArea}.
|
||||
*
|
||||
* <p>
|
||||
* Setting always on top to {@code True} will also make the {@code windowContainer} to move
|
||||
* to the top.
|
||||
* </p>
|
||||
* <p>
|
||||
* Setting always on top to {@code False} will make this {@code windowContainer} to move
|
||||
* below the other always on top sibling containers.
|
||||
* </p>
|
||||
*
|
||||
* @param windowContainer the container which the flag need to be updated for.
|
||||
* @param alwaysOnTop denotes whether or not always on top flag should be set.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public WindowContainerTransaction setAlwaysOnTop(
|
||||
@NonNull WindowContainerToken windowContainer,
|
||||
boolean alwaysOnTop) {
|
||||
final HierarchyOp hierarchyOp =
|
||||
new HierarchyOp.Builder(
|
||||
HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP)
|
||||
.setContainer(windowContainer.asBinder())
|
||||
.setAlwaysOnTop(alwaysOnTop)
|
||||
.build();
|
||||
mHierarchyOps.add(hierarchyOp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1121,6 +1153,7 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
public static final int HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER = 16;
|
||||
public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
|
||||
public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
|
||||
public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
|
||||
|
||||
// The following key(s) are for use with mLaunchOptions:
|
||||
// When launching a task (eg. from recents), this is the taskId to be launched.
|
||||
@@ -1171,6 +1204,8 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
@Nullable
|
||||
private ShortcutInfo mShortcutInfo;
|
||||
|
||||
private boolean mAlwaysOnTop;
|
||||
|
||||
public static HierarchyOp createForReparent(
|
||||
@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
|
||||
return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
|
||||
@@ -1268,6 +1303,7 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions;
|
||||
mPendingIntent = copy.mPendingIntent;
|
||||
mShortcutInfo = copy.mShortcutInfo;
|
||||
mAlwaysOnTop = copy.mAlwaysOnTop;
|
||||
}
|
||||
|
||||
protected HierarchyOp(Parcel in) {
|
||||
@@ -1289,6 +1325,7 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR);
|
||||
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
|
||||
mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
|
||||
mAlwaysOnTop = in.readBoolean();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
@@ -1354,6 +1391,10 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
return mActivityIntent;
|
||||
}
|
||||
|
||||
public boolean isAlwaysOnTop() {
|
||||
return mAlwaysOnTop;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
|
||||
return mTaskFragmentCreationOptions;
|
||||
@@ -1422,6 +1463,9 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
+ " insetsType=" + Arrays.toString(mInsetsTypes) + "}";
|
||||
case HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT:
|
||||
return "{requestFocusOnTaskFragment: container=" + mContainer + "}";
|
||||
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
|
||||
return "{setAlwaysOnTop: container=" + mContainer
|
||||
+ " alwaysOnTop=" + mAlwaysOnTop + "}";
|
||||
default:
|
||||
return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
|
||||
+ " mToTop=" + mToTop
|
||||
@@ -1451,6 +1495,7 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
dest.writeTypedObject(mTaskFragmentCreationOptions, flags);
|
||||
dest.writeTypedObject(mPendingIntent, flags);
|
||||
dest.writeTypedObject(mShortcutInfo, flags);
|
||||
dest.writeBoolean(mAlwaysOnTop);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1509,6 +1554,8 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
@Nullable
|
||||
private ShortcutInfo mShortcutInfo;
|
||||
|
||||
private boolean mAlwaysOnTop;
|
||||
|
||||
Builder(int type) {
|
||||
mType = type;
|
||||
}
|
||||
@@ -1568,6 +1615,11 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder setAlwaysOnTop(boolean alwaysOnTop) {
|
||||
mAlwaysOnTop = alwaysOnTop;
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder setTaskFragmentCreationOptions(
|
||||
@Nullable TaskFragmentCreationParams taskFragmentCreationOptions) {
|
||||
mTaskFragmentCreationOptions = taskFragmentCreationOptions;
|
||||
@@ -1596,6 +1648,7 @@ public final class WindowContainerTransaction implements Parcelable {
|
||||
hierarchyOp.mLaunchOptions = mLaunchOptions;
|
||||
hierarchyOp.mActivityIntent = mActivityIntent;
|
||||
hierarchyOp.mPendingIntent = mPendingIntent;
|
||||
hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
|
||||
hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
|
||||
hierarchyOp.mShortcutInfo = mShortcutInfo;
|
||||
|
||||
|
||||
@@ -207,6 +207,23 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlwaysOnTop(boolean alwaysOnTop) {
|
||||
if (isAlwaysOnTop() == alwaysOnTop) {
|
||||
return;
|
||||
}
|
||||
super.setAlwaysOnTop(alwaysOnTop);
|
||||
// positionChildAtTop() must be called even when always on top gets turned off because
|
||||
// we need to make sure that the display area is moved from among always on top containers
|
||||
// to below other always on top containers. Since the position the display area should be
|
||||
// inserted into is calculated properly in {@link DisplayContent#getTopInsertPosition()}
|
||||
// in both cases, we can just request that the root task is put at top here.
|
||||
if (getParent().asDisplayArea() != null) {
|
||||
getParent().asDisplayArea().positionChildAt(POSITION_TOP, this,
|
||||
false /* includingParents */);
|
||||
}
|
||||
}
|
||||
|
||||
boolean getIgnoreOrientationRequest() {
|
||||
// Adding an exception for when ignoreOrientationRequest is overridden at runtime for all
|
||||
// DisplayArea-s. For example, this is needed for the Kids Mode since many Kids apps aren't
|
||||
@@ -234,6 +251,18 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
|
||||
// The min possible position we can insert the child at.
|
||||
int minPosition = findMinPositionForChildDisplayArea(child);
|
||||
|
||||
// Place all non-always-on-top containers below always-on-top ones.
|
||||
int alwaysOnTopCount = 0;
|
||||
for (int i = minPosition; i <= maxPosition; i++) {
|
||||
if (mChildren.get(i).isAlwaysOnTop()) {
|
||||
alwaysOnTopCount++;
|
||||
}
|
||||
}
|
||||
if (child.isAlwaysOnTop()) {
|
||||
minPosition = maxPosition - alwaysOnTopCount + 1;
|
||||
} else {
|
||||
maxPosition -= alwaysOnTopCount;
|
||||
}
|
||||
return Math.max(Math.min(requestPosition, maxPosition), minPosition);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
|
||||
@@ -1079,6 +1080,18 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
WindowContainer.fromBinder(hop.getContainer())
|
||||
.removeLocalInsetsSourceProvider(hop.getInsetsTypes());
|
||||
break;
|
||||
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
|
||||
final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
|
||||
if (container == null || container.asDisplayArea() == null
|
||||
|| !container.isAttached()) {
|
||||
Slog.e(TAG, "Attempt to operate on unknown or detached display area: "
|
||||
+ container);
|
||||
break;
|
||||
}
|
||||
container.setAlwaysOnTop(hop.isAlwaysOnTop());
|
||||
effects |= TRANSACT_EFFECTS_LIFECYCLE;
|
||||
break;
|
||||
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
|
||||
@@ -399,9 +400,9 @@ public class DisplayAreaTest extends WindowTestsBase {
|
||||
parentBounds.right / 2, parentBounds.bottom);
|
||||
final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top,
|
||||
parentBounds.right, parentBounds.bottom);
|
||||
TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds);
|
||||
TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1);
|
||||
TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2);
|
||||
TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds, "Parent");
|
||||
TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1, "Child1");
|
||||
TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2, "Child2");
|
||||
parentDa.addChild(childDa1, 0);
|
||||
parentDa.addChild(childDa2, 1);
|
||||
|
||||
@@ -619,9 +620,67 @@ public class DisplayAreaTest extends WindowTestsBase {
|
||||
controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAlwaysOnTop_movesDisplayAreaToTop() {
|
||||
final Rect bounds = new Rect(0, 0, 100, 100);
|
||||
DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
|
||||
parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
DisplayArea<WindowContainer> child1 = new TestDisplayArea(mWm, bounds, "Child1");
|
||||
child1.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
DisplayArea<WindowContainer> child2 = new TestDisplayArea(mWm, bounds, "Child2");
|
||||
child2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
parent.addChild(child2, 0);
|
||||
parent.addChild(child1, 1);
|
||||
|
||||
child2.setAlwaysOnTop(true);
|
||||
|
||||
assertEquals(parent.getChildAt(1), child2);
|
||||
assertThat(child2.isAlwaysOnTop()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisplayAreaRequestsTopPosition_alwaysOnTopSiblingExists_doesNotMoveToTop() {
|
||||
final Rect bounds = new Rect(0, 0, 100, 100);
|
||||
DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
|
||||
parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds,
|
||||
"AlwaysOnTopChild");
|
||||
alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child");
|
||||
child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
parent.addChild(alwaysOnTopChild, 0);
|
||||
parent.addChild(child, 1);
|
||||
alwaysOnTopChild.setAlwaysOnTop(true);
|
||||
|
||||
parent.positionChildAt(POSITION_TOP, child, false /* includingParents */);
|
||||
|
||||
assertEquals(parent.getChildAt(1), alwaysOnTopChild);
|
||||
assertEquals(parent.getChildAt(0), child);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlwaysOnTopDisplayArea_requestsNonTopLocation_doesNotMove() {
|
||||
final Rect bounds = new Rect(0, 0, 100, 100);
|
||||
DisplayArea<WindowContainer> parent = new TestDisplayArea(mWm, bounds, "Parent");
|
||||
parent.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
DisplayArea<WindowContainer> alwaysOnTopChild = new TestDisplayArea(mWm, bounds,
|
||||
"AlwaysOnTopChild");
|
||||
alwaysOnTopChild.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
DisplayArea<WindowContainer> child = new TestDisplayArea(mWm, bounds, "Child");
|
||||
child.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
parent.addChild(alwaysOnTopChild, 0);
|
||||
parent.addChild(child, 1);
|
||||
alwaysOnTopChild.setAlwaysOnTop(true);
|
||||
|
||||
parent.positionChildAt(POSITION_BOTTOM, alwaysOnTopChild, false /* includingParents */);
|
||||
|
||||
assertEquals(parent.getChildAt(1), alwaysOnTopChild);
|
||||
assertEquals(parent.getChildAt(0), child);
|
||||
}
|
||||
|
||||
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
|
||||
private TestDisplayArea(WindowManagerService wms, Rect bounds) {
|
||||
super(wms, ANY, "half display area");
|
||||
private TestDisplayArea(WindowManagerService wms, Rect bounds, String name) {
|
||||
super(wms, ANY, name);
|
||||
setBounds(bounds);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user