summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java114
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java54
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java84
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java9
27 files changed, 445 insertions, 102 deletions
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
index e6f8388b031f..62959b7b95e9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
@@ -28,7 +28,7 @@ public class SidecarProvider {
* an OEM by overriding this method.
*/
public static SidecarInterface getSidecarImpl(Context context) {
- return new SampleSidecarImpl(context);
+ return new SampleSidecarImpl(context.getApplicationContext());
}
/**
@@ -36,6 +36,6 @@ public class SidecarProvider {
* @return API version string in MAJOR.MINOR.PATCH-description format.
*/
public static String getApiVersion() {
- return "0.1.0-settings_sample";
+ return "1.0.0-reference";
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
new file mode 100644
index 000000000000..14ba9df93f24
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.util.SparseArray;
+import android.view.SurfaceControl;
+import android.window.DisplayAreaAppearedInfo;
+import android.window.DisplayAreaInfo;
+import android.window.DisplayAreaOrganizer;
+
+import androidx.annotation.NonNull;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/** Display area organizer for the root display areas */
+public class RootDisplayAreaOrganizer extends DisplayAreaOrganizer {
+
+ private static final String TAG = RootDisplayAreaOrganizer.class.getSimpleName();
+
+ /** {@link DisplayAreaInfo} list, which is mapped by display IDs. */
+ private final SparseArray<DisplayAreaInfo> mDisplayAreasInfo = new SparseArray<>();
+ /** Display area leashes, which is mapped by display IDs. */
+ private final SparseArray<SurfaceControl> mLeashes = new SparseArray<>();
+
+ public RootDisplayAreaOrganizer(Executor executor) {
+ super(executor);
+ List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_ROOT);
+ for (int i = infos.size() - 1; i >= 0; --i) {
+ onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash());
+ }
+ }
+
+ public void attachToDisplayArea(int displayId, SurfaceControl.Builder b) {
+ final SurfaceControl sc = mLeashes.get(displayId);
+ if (sc != null) {
+ b.setParent(sc);
+ }
+ }
+
+ @Override
+ public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
+ @NonNull SurfaceControl leash) {
+ if (displayAreaInfo.featureId != FEATURE_ROOT) {
+ throw new IllegalArgumentException(
+ "Unknown feature: " + displayAreaInfo.featureId
+ + "displayAreaInfo:" + displayAreaInfo);
+ }
+
+ final int displayId = displayAreaInfo.displayId;
+ if (mDisplayAreasInfo.get(displayId) != null) {
+ throw new IllegalArgumentException(
+ "Duplicate DA for displayId: " + displayId
+ + " displayAreaInfo:" + displayAreaInfo
+ + " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId));
+ }
+
+ mDisplayAreasInfo.put(displayId, displayAreaInfo);
+ mLeashes.put(displayId, leash);
+ }
+
+ @Override
+ public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
+ final int displayId = displayAreaInfo.displayId;
+ if (mDisplayAreasInfo.get(displayId) == null) {
+ throw new IllegalArgumentException(
+ "onDisplayAreaVanished() Unknown DA displayId: " + displayId
+ + " displayAreaInfo:" + displayAreaInfo
+ + " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId));
+ }
+
+ mDisplayAreasInfo.remove(displayId);
+ }
+
+ @Override
+ public void onDisplayAreaInfoChanged(@NonNull DisplayAreaInfo displayAreaInfo) {
+ final int displayId = displayAreaInfo.displayId;
+ if (mDisplayAreasInfo.get(displayId) == null) {
+ throw new IllegalArgumentException(
+ "onDisplayAreaInfoChanged() Unknown DA displayId: " + displayId
+ + " displayAreaInfo:" + displayAreaInfo
+ + " mDisplayAreasInfo.get():" + mDisplayAreasInfo.get(displayId));
+ }
+
+ mDisplayAreasInfo.put(displayId, displayAreaInfo);
+ }
+
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ final String childPrefix = innerPrefix + " ";
+ pw.println(prefix + this);
+ }
+
+ @Override
+ public String toString() {
+ return TAG + "#" + mDisplayAreasInfo.size();
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index 10d7725b6184..6a252e0d7dcb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -232,7 +232,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
- onLayoutChanged(mSplitLayout);
+ onLayoutSizeChanged(mSplitLayout);
}
} else if (taskInfo.taskId == getTaskId1()) {
mTaskInfo1 = taskInfo;
@@ -313,13 +313,19 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
}
@Override
- public void onLayoutChanging(SplitLayout layout) {
+ public void onLayoutPositionChanging(SplitLayout layout) {
mSyncQueue.runInSync(t ->
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
}
@Override
- public void onLayoutChanged(SplitLayout layout) {
+ public void onLayoutSizeChanging(SplitLayout layout) {
+ mSyncQueue.runInSync(t ->
+ layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
+ }
+
+ @Override
+ public void onLayoutSizeChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
mSyncQueue.queue(wct);
@@ -328,9 +334,9 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
}
@Override
- public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyLayoutShifted(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
+ layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
mController.getTaskOrganizer().applyTransaction(wct);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 05ebbba4e955..8d43f1375a8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -121,7 +121,7 @@ public class Bubble implements BubbleViewProvider {
@Nullable
private Icon mIcon;
private boolean mIsBubble;
- private boolean mIsVisuallyInterruptive;
+ private boolean mIsTextChanged;
private boolean mIsClearable;
private boolean mShouldSuppressNotificationDot;
private boolean mShouldSuppressNotificationList;
@@ -342,12 +342,12 @@ public class Bubble implements BubbleViewProvider {
}
/**
- * Sets whether this bubble is considered visually interruptive. This method is purely for
+ * Sets whether this bubble is considered text changed. This method is purely for
* testing.
*/
@VisibleForTesting
- void setVisuallyInterruptiveForTest(boolean visuallyInterruptive) {
- mIsVisuallyInterruptive = visuallyInterruptive;
+ void setTextChangedForTest(boolean textChanged) {
+ mIsTextChanged = textChanged;
}
/**
@@ -454,7 +454,7 @@ public class Bubble implements BubbleViewProvider {
mFlyoutMessage = extractFlyoutMessage(entry);
if (entry.getRanking() != null) {
mShortcutInfo = entry.getRanking().getConversationShortcutInfo();
- mIsVisuallyInterruptive = entry.getRanking().visuallyInterruptive();
+ mIsTextChanged = entry.getRanking().isTextChanged();
if (entry.getRanking().getChannel() != null) {
mIsImportantConversation =
entry.getRanking().getChannel().isImportantConversation();
@@ -495,8 +495,8 @@ public class Bubble implements BubbleViewProvider {
return mIcon;
}
- boolean isVisuallyInterruptive() {
- return mIsVisuallyInterruptive;
+ boolean isTextChanged() {
+ return mIsTextChanged;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index c126f32387f0..b6d65bebff28 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -939,7 +939,7 @@ public class BubbleController {
public void updateBubble(BubbleEntry notif, boolean suppressFlyout, boolean showInShade) {
// If this is an interruptive notif, mark that it's interrupted
mSysuiProxy.setNotificationInterruption(notif.getKey());
- if (!notif.getRanking().visuallyInterruptive()
+ if (!notif.getRanking().isTextChanged()
&& (notif.getBubbleMetadata() != null
&& !notif.getBubbleMetadata().getAutoExpandBubble())
&& mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index bef26bfffef3..519a856538c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -323,7 +323,7 @@ public class BubbleData {
}
mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
- suppressFlyout |= !bubble.isVisuallyInterruptive();
+ suppressFlyout |= !bubble.isTextChanged();
if (prevBubble == null) {
// Create a new bubble
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index d590ab112aae..300319a2f78f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -120,8 +120,6 @@ public class BubbleStackView extends FrameLayout
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
- private static final int MANAGE_MENU_SCRIM_ANIM_DURATION = 150;
-
private static final float SCRIM_ALPHA = 0.6f;
/**
@@ -894,6 +892,7 @@ public class BubbleStackView extends FrameLayout
updatePointerPosition(false /* forIme */);
mExpandedAnimationController.expandFromStack(() -> {
afterExpandedViewAnimation();
+ showManageMenu(mShowingManage);
} /* after */);
final float translationY = mPositioner.getExpandedViewY(mExpandedBubble,
getBubbleIndex(mExpandedBubble));
@@ -1253,9 +1252,6 @@ public class BubbleStackView extends FrameLayout
mRelativeStackPositionBeforeRotation = new RelativeStackPosition(
mPositioner.getRestingPosition(),
mStackAnimationController.getAllowableStackPositionRegion());
- mManageMenu.setVisibility(View.INVISIBLE);
- mShowingManage = false;
-
addOnLayoutChangeListener(mOrientationChangedListener);
hideFlyoutImmediate();
}
@@ -2555,16 +2551,19 @@ public class BubbleStackView extends FrameLayout
invalidate();
}
- private void showManageMenu(boolean show) {
+ /** Hide or show the manage menu for the currently expanded bubble. */
+ @VisibleForTesting
+ public void showManageMenu(boolean show) {
mShowingManage = show;
// This should not happen, since the manage menu is only visible when there's an expanded
// bubble. If we end up in this state, just hide the menu immediately.
if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) {
mManageMenu.setVisibility(View.INVISIBLE);
+ mManageMenuScrim.setVisibility(INVISIBLE);
+ mBubbleController.getSysuiProxy().onManageMenuExpandChanged(false /* show */);
return;
}
-
if (show) {
mManageMenuScrim.setVisibility(VISIBLE);
mManageMenuScrim.setTranslationZ(mManageMenu.getElevation() - 1f);
@@ -2576,8 +2575,8 @@ public class BubbleStackView extends FrameLayout
}
};
+ mBubbleController.getSysuiProxy().onManageMenuExpandChanged(show);
mManageMenuScrim.animate()
- .setDuration(MANAGE_MENU_SCRIM_ANIM_DURATION)
.setInterpolator(show ? ALPHA_IN : ALPHA_OUT)
.alpha(show ? SCRIM_ALPHA : 0f)
.withEndAction(endAction)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 9b7eb2f1cfb3..c82249b8a369 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -284,6 +284,8 @@ public interface Bubbles {
void onStackExpandChanged(boolean shouldExpand);
+ void onManageMenuExpandChanged(boolean menuExpanded);
+
void onUnbubbleConversation(String key);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 596a2f4467c3..5b3ce2dbaeb9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -291,13 +291,13 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
void updateDivideBounds(int position) {
updateBounds(position);
mSplitWindowManager.setResizingSplits(true);
- mSplitLayoutHandler.onLayoutChanging(this);
+ mSplitLayoutHandler.onLayoutSizeChanging(this);
}
void setDividePosition(int position) {
mDividePosition = position;
updateBounds(mDividePosition);
- mSplitLayoutHandler.onLayoutChanged(this);
+ mSplitLayoutHandler.onLayoutSizeChanged(this);
mSplitWindowManager.setResizingSplits(false);
}
@@ -451,7 +451,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
* Shift configuration bounds to prevent client apps get configuration changed or relaunch. And
* restore shifted configuration bounds if it's no longer shifted.
*/
- public void applyLayoutShifted(WindowContainerTransaction wct, int offsetX, int offsetY,
+ public void applyLayoutOffsetTarget(WindowContainerTransaction wct, int offsetX, int offsetY,
ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
if (offsetX == 0 && offsetY == 0) {
wct.setBounds(taskInfo1.token, mBounds1);
@@ -492,19 +492,43 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
/** Calls when dismissing split. */
void onSnappedToDismiss(boolean snappedToEnd);
- /** Calls when the bounds is changing due to animation or dragging divider bar. */
- void onLayoutChanging(SplitLayout layout);
+ /**
+ * Calls when resizing the split bounds.
+ *
+ * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl,
+ * SurfaceControl, SurfaceControl)
+ */
+ void onLayoutSizeChanging(SplitLayout layout);
- /** Calls when the target bounds changed. */
- void onLayoutChanged(SplitLayout layout);
+ /**
+ * Calls when finish resizing the split bounds.
+ *
+ * @see #applyTaskChanges(WindowContainerTransaction, ActivityManager.RunningTaskInfo,
+ * ActivityManager.RunningTaskInfo)
+ * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl,
+ * SurfaceControl, SurfaceControl)
+ */
+ void onLayoutSizeChanged(SplitLayout layout);
/**
- * Notifies when the layout shifted. So the layout handler can shift configuration
+ * Calls when re-positioning the split bounds. Like moving split bounds while showing IME
+ * panel.
+ *
+ * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl,
+ * SurfaceControl, SurfaceControl)
+ */
+ void onLayoutPositionChanging(SplitLayout layout);
+
+ /**
+ * Notifies the target offset for shifting layout. So layout handler can shift configuration
* bounds correspondingly to make sure client apps won't get configuration changed or
- * relaunch. If the layout is no longer shifted, layout handler should restore shifted
+ * relaunched. If the layout is no longer shifted, layout handler should restore shifted
* configuration bounds.
+ *
+ * @see #applyLayoutOffsetTarget(WindowContainerTransaction, int, int,
+ * ActivityManager.RunningTaskInfo, ActivityManager.RunningTaskInfo)
*/
- void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout);
+ void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout);
/** Calls when user double tapped on the divider bar. */
default void onDoubleTappedDivider() {
@@ -674,9 +698,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
// changed or relaunch. This is required to make sure client apps will calculate
// insets properly after layout shifted.
if (mTargetYOffset == 0) {
- mSplitLayoutHandler.onLayoutShifted(0, 0, SplitLayout.this);
+ mSplitLayoutHandler.setLayoutOffsetTarget(0, 0, SplitLayout.this);
} else {
- mSplitLayoutHandler.onLayoutShifted(0, mTargetYOffset - mLastYOffset,
+ mSplitLayoutHandler.setLayoutOffsetTarget(0, mTargetYOffset - mLastYOffset,
SplitLayout.this);
}
}
@@ -695,7 +719,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
if (displayId != mDisplayId) return;
onProgress(getProgress(imeTop));
- mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
@Override
@@ -703,7 +727,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
SurfaceControl.Transaction t) {
if (displayId != mDisplayId || cancel) return;
onProgress(1.0f);
- mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
@Override
@@ -713,7 +737,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
if (!controlling && mImeShown) {
reset();
mSplitWindowManager.setInteractive(true);
- mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
+ mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java
new file mode 100644
index 000000000000..defbd5af01d9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelper.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.displayareahelper;
+
+import android.view.SurfaceControl;
+
+import java.util.function.Consumer;
+
+/**
+ * Interface that allows to perform various display area related actions
+ */
+public interface DisplayAreaHelper {
+
+ /**
+ * Updates SurfaceControl builder to reparent it to the root display area
+ * @param displayId id of the display to which root display area it should be reparented to
+ * @param builder surface control builder that should be updated
+ * @param onUpdated callback that is invoked after updating the builder, called on
+ * the shell main thread
+ */
+ default void attachToRootDisplayArea(int displayId, SurfaceControl.Builder builder,
+ Consumer<SurfaceControl.Builder> onUpdated) {
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java
new file mode 100644
index 000000000000..ef9ad6d10e6b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/displayareahelper/DisplayAreaHelperController.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 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.displayareahelper;
+
+import android.view.SurfaceControl;
+
+import com.android.wm.shell.RootDisplayAreaOrganizer;
+
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+public class DisplayAreaHelperController implements DisplayAreaHelper {
+
+ private final Executor mExecutor;
+ private final RootDisplayAreaOrganizer mRootDisplayAreaOrganizer;
+
+ public DisplayAreaHelperController(Executor executor,
+ RootDisplayAreaOrganizer rootDisplayAreaOrganizer) {
+ mExecutor = executor;
+ mRootDisplayAreaOrganizer = rootDisplayAreaOrganizer;
+ }
+
+ @Override
+ public void attachToRootDisplayArea(int displayId, SurfaceControl.Builder builder,
+ Consumer<SurfaceControl.Builder> onUpdated) {
+ mExecutor.execute(() -> {
+ mRootDisplayAreaOrganizer.attachToDisplayArea(displayId, builder);
+ onUpdated.accept(builder);
+ });
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 96867761cc7e..291cbb3676dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -282,6 +282,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mMainExecutor.execute(() -> {
mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_PIP);
});
+ mPipTransitionController.setPipOrganizer(this);
displayController.addDisplayWindowListener(this);
}
@@ -349,6 +350,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
+ public ActivityManager.RunningTaskInfo getTaskInfo() {
+ return mTaskInfo;
+ }
+
public SurfaceControl getSurfaceControl() {
return mLeash;
}
@@ -716,6 +721,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
}
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mPipTransitionController.forceFinishTransition();
+ }
final PipAnimationController.PipTransitionAnimator<?> animator =
mPipAnimationController.getCurrentAnimator();
if (animator != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 6fec1fbda7b0..328f3ed73f2e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -32,17 +32,18 @@ import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
+import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.IBinder;
+import android.util.Log;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -57,11 +58,14 @@ import com.android.wm.shell.transition.Transitions;
*/
public class PipTransition extends PipTransitionController {
+ private static final String TAG = PipTransition.class.getSimpleName();
+
private final PipTransitionState mPipTransitionState;
private final int mEnterExitAnimationDuration;
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
private Transitions.TransitionFinishCallback mFinishCallback;
private Rect mExitDestinationBounds = new Rect();
+ private IBinder mExitTransition = null;
public PipTransition(Context context,
PipBoundsState pipBoundsState,
@@ -96,7 +100,7 @@ public class PipTransition extends PipTransitionController {
public void startTransition(Rect destinationBounds, WindowContainerTransaction out) {
if (destinationBounds != null) {
mExitDestinationBounds.set(destinationBounds);
- mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
+ mExitTransition = mTransitions.startTransition(TRANSIT_EXIT_PIP, out, this);
} else {
mTransitions.startTransition(TRANSIT_REMOVE_PIP, out, this);
}
@@ -109,14 +113,19 @@ public class PipTransition extends PipTransitionController {
@android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
@android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (info.getType() == TRANSIT_EXIT_PIP && info.getChanges().size() == 1) {
- final TransitionInfo.Change change = info.getChanges().get(0);
- mFinishCallback = finishCallback;
- startTransaction.apply();
- boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(),
- new Rect(mExitDestinationBounds));
- mExitDestinationBounds.setEmpty();
- return success;
+ if (mExitTransition == transition || info.getType() == TRANSIT_EXIT_PIP) {
+ mExitTransition = null;
+ if (info.getChanges().size() == 1) {
+ final TransitionInfo.Change change = info.getChanges().get(0);
+ mFinishCallback = finishCallback;
+ startTransaction.apply();
+ boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(),
+ new Rect(mExitDestinationBounds));
+ mExitDestinationBounds.setEmpty();
+ return success;
+ } else {
+ Log.e(TAG, "Got an exit-pip transition with unexpected change-list");
+ }
}
if (info.getType() == TRANSIT_REMOVE_PIP) {
@@ -183,26 +192,58 @@ public class PipTransition extends PipTransitionController {
}
@Override
+ public void onTransitionMerged(@NonNull IBinder transition) {
+ if (transition != mExitTransition) {
+ return;
+ }
+ // This means an expand happened before enter-pip finished and we are now "merging" a
+ // no-op transition that happens to match our exit-pip.
+ boolean cancelled = false;
+ if (mPipAnimationController.getCurrentAnimator() != null) {
+ mPipAnimationController.getCurrentAnimator().cancel();
+ cancelled = true;
+ }
+ // Unset exitTransition AFTER cancel so that finishResize knows we are merging.
+ mExitTransition = null;
+ if (!cancelled) return;
+ final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo();
+ if (taskInfo != null) {
+ startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
+ new Rect(mExitDestinationBounds));
+ }
+ mExitDestinationBounds.setEmpty();
+ }
+
+ @Override
public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds,
@PipAnimationController.TransitionDirection int direction,
- SurfaceControl.Transaction tx) {
+ @Nullable SurfaceControl.Transaction tx) {
if (isInPipDirection(direction)) {
mPipTransitionState.setTransitionState(PipTransitionState.ENTERED_PIP);
}
- WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareFinishResizeTransaction(taskInfo, destinationBounds,
- direction, tx, wct);
- mFinishCallback.onTransitionFinished(wct, new WindowContainerTransactionCallback() {
- @Override
- public void onTransactionReady(int id, @NonNull SurfaceControl.Transaction t) {
- t.merge(tx);
- t.apply();
+ // If there is an expected exit transition, then the exit will be "merged" into this
+ // transition so don't fire the finish-callback in that case.
+ if (mExitTransition == null && mFinishCallback != null) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ prepareFinishResizeTransaction(taskInfo, destinationBounds,
+ direction, wct);
+ if (tx != null) {
+ wct.setBoundsChangeTransaction(taskInfo.token, tx);
}
- });
+ mFinishCallback.onTransitionFinished(wct, null /* wctCallback */);
+ mFinishCallback = null;
+ }
finishResizeForMenu(destinationBounds);
}
+ @Override
+ public void forceFinishTransition() {
+ if (mFinishCallback == null) return;
+ mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCallback */);
+ mFinishCallback = null;
+ }
+
private boolean startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
final Rect destinationBounds) {
PipAnimationController.PipTransitionAnimator animator =
@@ -243,7 +284,7 @@ public class PipTransition extends PipTransitionController {
startTransaction.merge(tx);
startTransaction.apply();
mPipBoundsState.setBounds(destinationBounds);
- onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, tx);
+ onFinishResize(taskInfo, destinationBounds, TRANSITION_DIRECTION_TO_PIP, null /* tx */);
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
mFinishCallback = null;
mPipTransitionState.setInSwipePipToHomeTransition(false);
@@ -292,7 +333,6 @@ public class PipTransition extends PipTransitionController {
private void prepareFinishResizeTransaction(TaskInfo taskInfo, Rect destinationBounds,
@PipAnimationController.TransitionDirection int direction,
- SurfaceControl.Transaction tx,
WindowContainerTransaction wct) {
Rect taskBounds = null;
if (isInPipDirection(direction)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index dbf603ca72d9..376f3298a83c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -49,6 +49,7 @@ public abstract class PipTransitionController implements Transitions.TransitionH
protected final Transitions mTransitions;
private final Handler mMainHandler;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
+ protected PipTaskOrganizer mPipOrganizer;
protected final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
new PipAnimationController.PipAnimationCallback() {
@@ -103,6 +104,13 @@ public abstract class PipTransitionController implements Transitions.TransitionH
// Default implementation does nothing.
}
+ /**
+ * Called when the transition animation can't continue (eg. task is removed during
+ * animation)
+ */
+ public void forceFinishTransition() {
+ }
+
public PipTransitionController(PipBoundsState pipBoundsState,
PipMenuController pipMenuController, PipBoundsAlgorithm pipBoundsAlgorithm,
PipAnimationController pipAnimationController, Transitions transitions,
@@ -119,6 +127,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH
}
}
+ void setPipOrganizer(PipTaskOrganizer pto) {
+ mPipOrganizer = pto;
+ }
+
/**
* Registers {@link PipTransitionCallback} to receive transition callbacks.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 7f82ebde77af..a47a15287dda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -49,25 +49,24 @@ class MainStage extends StageTaskListener {
return mIsActive;
}
- void activate(Rect rootBounds, WindowContainerTransaction wct) {
+ void activate(Rect rootBounds, WindowContainerTransaction wct, boolean includingTopTask) {
if (mIsActive) return;
final WindowContainerToken rootToken = mRootTaskInfo.token;
wct.setBounds(rootToken, rootBounds)
.setWindowingMode(rootToken, WINDOWING_MODE_MULTI_WINDOW)
- .setLaunchRoot(
- rootToken,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES)
- .reparentTasks(
- null /* currentParent */,
- rootToken,
- CONTROLLED_WINDOWING_MODES,
- CONTROLLED_ACTIVITY_TYPES,
- true /* onTop */)
// Moving the root task to top after the child tasks were re-parented , or the root
// task cannot be visible and focused.
.reorder(rootToken, true /* onTop */);
+ if (includingTopTask) {
+ wct.reparentTasks(
+ null /* currentParent */,
+ rootToken,
+ CONTROLLED_WINDOWING_MODES,
+ CONTROLLED_ACTIVITY_TYPES,
+ true /* onTop */,
+ true /* reparentTopOnly */);
+ }
mIsActive = true;
}
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 0d5271924375..ec71fbee9a29 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
@@ -16,6 +16,8 @@
package com.android.wm.shell.splitscreen;
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
@@ -213,7 +215,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
options = mStageCoordinator.resolveStartStage(stage, position, options, null /* wct */);
try {
- ActivityTaskManager.getService().startActivityFromRecents(taskId, options);
+ final int result =
+ ActivityTaskManager.getService().startActivityFromRecents(taskId, options);
+ if (result == START_SUCCESS || result == START_TASK_TO_FRONT) {
+ mStageCoordinator.evictOccludedChildren(position);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Failed to launch task", e);
}
@@ -229,6 +235,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mContext.getSystemService(LauncherApps.class);
launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
options, user);
+ mStageCoordinator.evictOccludedChildren(position);
} catch (ActivityNotFoundException e) {
Slog.e(TAG, "Failed to launch shortcut", e);
}
@@ -272,6 +279,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
Slog.e(TAG, "Error finishing legacy transition: ", e);
}
}
+
+ // Launching a new app into a specific split evicts tasks previously in the same
+ // split.
+ mStageCoordinator.evictOccludedChildren(position);
}
};
WindowContainerTransaction wct = new WindowContainerTransaction();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 414b4e48efdd..0cff18e2ba85 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -263,7 +263,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@SplitPosition int sideStagePosition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
setSideStagePosition(sideStagePosition, wct);
- mMainStage.activate(getMainStageBounds(), wct);
+ mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
mSideStage.addTask(task, getSideStageBounds(), wct);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> updateSurfaceBounds(null /* layout */, t));
@@ -299,7 +299,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct);
+ mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
mSideStage.setBounds(getSideStageBounds(), wct);
// Make sure the launch options will put tasks in the corresponding split roots
@@ -368,7 +368,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct);
+ mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
mSideStage.setBounds(getSideStageBounds(), wct);
// Make sure the launch options will put tasks in the corresponding split roots
@@ -394,6 +394,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, remoteTransition, this);
}
+ void evictOccludedChildren(@SplitPosition int position) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ (position == mSideStagePosition ? mSideStage : mMainStage).evictOccludedChildren(wct);
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
Bundle resolveStartStage(@SplitScreen.StageType int stage,
@SplitPosition int position, @androidx.annotation.Nullable Bundle options,
@androidx.annotation.Nullable WindowContainerTransaction wct) {
@@ -471,7 +477,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSideStageListener.mVisible && updateBounds) {
if (wct == null) {
// onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
- onLayoutChanged(mSplitLayout);
+ onLayoutSizeChanged(mSplitLayout);
} else {
updateWindowBounds(mSplitLayout, wct);
updateUnfoldBounds();
@@ -756,7 +762,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} else if (isSideStage) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
// Make sure the main stage is active.
- mMainStage.activate(getMainStageBounds(), wct);
+ mMainStage.activate(getMainStageBounds(), wct, true /* reparent */);
mSideStage.setBounds(getSideStageBounds(), wct);
mTaskOrganizer.applyTransaction(wct);
}
@@ -799,13 +805,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onLayoutChanging(SplitLayout layout) {
+ public void onLayoutPositionChanging(SplitLayout layout) {
+ mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
+ }
+
+ @Override
+ public void onLayoutSizeChanging(SplitLayout layout) {
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
mSideStage.setOutlineVisibility(false);
}
@Override
- public void onLayoutChanged(SplitLayout layout) {
+ public void onLayoutSizeChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateWindowBounds(layout, wct);
updateUnfoldBounds();
@@ -859,13 +870,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
final StageTaskListener topLeftStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
final StageTaskListener bottomRightStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
+ layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
bottomRightStage.mRootTaskInfo);
mTaskOrganizer.applyTransaction(wct);
}
@@ -897,7 +908,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
&& mMainStage.isActive()) {
- onLayoutChanged(mSplitLayout);
+ onLayoutSizeChanged(mSplitLayout);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 84d570f4be44..071badf2bc23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -68,6 +68,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
void onRootTaskVanished();
+
void onNoLongerSupportMultiWindow();
}
@@ -247,6 +248,15 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */);
}
+ void evictOccludedChildren(WindowContainerTransaction wct) {
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ if (!taskInfo.isVisible) {
+ wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
+ }
+ }
+ }
+
void setVisibility(boolean visible, WindowContainerTransaction wct) {
wct.reorder(mRootTaskInfo.token, visible /* onTop */);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
index 2f75f8bdc64c..574e379921b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/StageCoordinator.java
@@ -470,8 +470,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSideStageListener.mVisible && updateBounds) {
if (wct == null) {
- // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds.
- onLayoutChanged(mSplitLayout);
+ // onLayoutSizeChanged builds/applies a wct with the contents of updateWindowBounds.
+ onLayoutSizeChanged(mSplitLayout);
} else {
updateWindowBounds(mSplitLayout, wct);
updateUnfoldBounds();
@@ -800,13 +800,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onLayoutChanging(SplitLayout layout) {
+ public void onLayoutPositionChanging(SplitLayout layout) {
+ mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
+ }
+
+ @Override
+ public void onLayoutSizeChanging(SplitLayout layout) {
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
mSideStage.setOutlineVisibility(false);
}
@Override
- public void onLayoutChanged(SplitLayout layout) {
+ public void onLayoutSizeChanged(SplitLayout layout) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateWindowBounds(layout, wct);
updateUnfoldBounds();
@@ -860,13 +865,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
@Override
- public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
+ public void setLayoutOffsetTarget(int offsetX, int offsetY, SplitLayout layout) {
final StageTaskListener topLeftStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
final StageTaskListener bottomRightStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
+ layout.applyLayoutOffsetTarget(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
bottomRightStage.mRootTaskInfo);
mTaskOrganizer.applyTransaction(wct);
}
@@ -898,7 +903,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
&& mMainStage.isActive()) {
- onLayoutChanged(mSplitLayout);
+ onLayoutSizeChanged(mSplitLayout);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index f0685a81d25f..38122ffc032b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -38,6 +38,7 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Trace;
+import android.util.Log;
import android.util.PathParser;
import android.window.SplashScreenView;
@@ -50,6 +51,8 @@ import com.android.internal.R;
*/
public class SplashscreenIconDrawableFactory {
+ private static final String TAG = "SplashscreenIconDrawableFactory";
+
/**
* @return An array containing the foreground drawable at index 0 and if needed a background
* drawable at index 1.
@@ -282,7 +285,12 @@ public class SplashscreenIconDrawableFactory {
if (startListener != null) {
startListener.run();
}
- mAnimatableIcon.start();
+ try {
+ mAnimatableIcon.start();
+ } catch (Exception ex) {
+ Log.e(TAG, "Error while running the splash screen animated icon", ex);
+ animation.cancel();
+ }
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 663d6477c3fe..7abda994bb5e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -70,6 +70,7 @@ import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.window.TransitionInfo;
+import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -362,6 +363,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
}
startTransaction.apply();
+ TransitionMetrics.getInstance().reportAnimationStart(transition);
// run finish now in-case there are no animations
onAnimFinish.run();
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 27201572d3e8..c36983189a71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -44,6 +44,7 @@ import android.window.ITransitionPlayer;
import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
+import android.window.TransitionMetrics;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import android.window.WindowContainerTransactionCallback;
@@ -192,6 +193,8 @@ public class Transitions implements RemoteCallable<Transitions> {
public void register(ShellTaskOrganizer taskOrganizer) {
if (mPlayerImpl == null) return;
taskOrganizer.registerTransitionPlayer(mPlayerImpl);
+ // Pre-load the instance.
+ TransitionMetrics.getInstance();
}
/**
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 091022a139f3..bc701d0c70bc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -131,7 +131,7 @@ public class BubbleDataTest extends ShellTestCase {
NotificationListenerService.Ranking ranking =
mock(NotificationListenerService.Ranking.class);
- when(ranking.visuallyInterruptive()).thenReturn(true);
+ when(ranking.isTextChanged()).thenReturn(true);
mEntryInterruptive = createBubbleEntry(1, "interruptive", "package.d", ranking);
mBubbleInterruptive = new Bubble(mEntryInterruptive, mSuppressionListener, null,
mMainExecutor);
@@ -1014,15 +1014,15 @@ public class BubbleDataTest extends ShellTestCase {
}
private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime) {
- sendUpdatedEntryAtTime(entry, postTime, true /* visuallyInterruptive */);
+ sendUpdatedEntryAtTime(entry, postTime, true /* isTextChanged */);
}
private void sendUpdatedEntryAtTime(BubbleEntry entry, long postTime,
- boolean visuallyInterruptive) {
+ boolean textChanged) {
setPostTime(entry, postTime);
// BubbleController calls this:
Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */);
- b.setVisuallyInterruptiveForTest(visuallyInterruptive);
+ b.setTextChangedForTest(textChanged);
// And then this
mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/,
true /* showInShade */);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index defa58d7fe93..b4caeb5de4ec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -95,13 +95,13 @@ public class SplitLayoutTests extends ShellTestCase {
@Test
public void testUpdateDivideBounds() {
mSplitLayout.updateDivideBounds(anyInt());
- verify(mSplitLayoutHandler).onLayoutChanging(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class));
}
@Test
public void testSetDividePosition() {
mSplitLayout.setDividePosition(anyInt());
- verify(mSplitLayoutHandler).onLayoutChanged(any(SplitLayout.class));
+ verify(mSplitLayoutHandler).onLayoutSizeChanged(any(SplitLayout.class));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
index 12b547a765be..2bcc45e2587d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
@@ -62,7 +62,8 @@ public class MainStageTests {
@Test
public void testActiveDeactivate() {
- mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct);
+ mMainStage.activate(mRootTaskInfo.configuration.windowConfiguration.getBounds(), mWct,
+ true /* reparent */);
assertThat(mMainStage.isActive()).isTrue();
mMainStage.deactivate(mWct);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index be103863a0f2..05496b059030 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -316,7 +316,8 @@ public class SplitTransitionTests extends ShellTestCase {
mock(SurfaceControl.Transaction.class),
mock(SurfaceControl.Transaction.class),
mock(Transitions.TransitionFinishCallback.class));
- mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction());
+ mMainStage.activate(new Rect(0, 0, 100, 100), new WindowContainerTransaction(),
+ true /* includingTopTask */);
}
private boolean containsSplitExit(@NonNull WindowContainerTransaction wct) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index a39d331ca884..cd29220bb96a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -18,9 +18,11 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
@@ -111,7 +113,8 @@ public class StageCoordinatorTests extends ShellTestCase {
mStageCoordinator.moveToSideStage(task, SPLIT_POSITION_BOTTOM_OR_RIGHT);
- verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class));
+ verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class),
+ eq(true /* includingTopTask */));
verify(mSideStage).addTask(eq(task), any(Rect.class),
any(WindowContainerTransaction.class));
}
@@ -130,7 +133,7 @@ public class StageCoordinatorTests extends ShellTestCase {
mStageCoordinator.setSideStagePosition(SPLIT_POSITION_TOP_OR_LEFT, null);
clearInvocations(mMainUnfoldController, mSideUnfoldController);
- mStageCoordinator.onLayoutChanged(mSplitLayout);
+ mStageCoordinator.onLayoutSizeChanged(mSplitLayout);
verify(mMainUnfoldController).onLayoutChanged(mBounds2);
verify(mSideUnfoldController).onLayoutChanged(mBounds1);
@@ -142,7 +145,7 @@ public class StageCoordinatorTests extends ShellTestCase {
mStageCoordinator.setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null);
clearInvocations(mMainUnfoldController, mSideUnfoldController);
- mStageCoordinator.onLayoutChanged(mSplitLayout);
+ mStageCoordinator.onLayoutSizeChanged(mSplitLayout);
verify(mMainUnfoldController).onLayoutChanged(mBounds1);
verify(mSideUnfoldController).onLayoutChanged(mBounds2);