summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl11
-rw-r--r--core/java/android/content/pm/LauncherApps.java6
-rw-r--r--core/java/android/content/pm/ShortcutQueryWrapper.aidl20
-rw-r--r--core/java/android/content/pm/ShortcutQueryWrapper.java190
-rw-r--r--core/java/android/net/LinkProperties.java30
-rw-r--r--core/java/android/net/RouteInfo.java26
-rw-r--r--core/java/android/provider/DeviceConfig.java7
-rw-r--r--core/tests/coretests/src/android/content/pm/ShortcutQueryWrapperTest.java77
-rw-r--r--packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml162
-rw-r--r--packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml162
-rw-r--r--packages/SystemUI/res/layout/bubble_overflow_activity.xml8
-rw-r--r--packages/SystemUI/res/layout/qs_media_panel.xml41
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt86
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt152
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java94
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java145
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt130
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt375
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt77
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java108
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java3
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java25
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java35
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java131
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java12
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java3
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java8
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java7
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java3
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java34
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java11
-rw-r--r--services/core/java/com/android/server/wm/ResetTargetTaskHelper.java11
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java85
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java71
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java2
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java75
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java233
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java84
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java4
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java25
-rw-r--r--tests/net/common/java/android/net/RouteInfoTest.java58
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java5
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java21
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java2
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java4
96 files changed, 2711 insertions, 642 deletions
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 27c9cfcdd05b..aa290404c001 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -25,6 +25,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IOnAppsChangedListener;
import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutQueryWrapper;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IShortcutChangeCallback;
import android.content.pm.PackageInstaller;
@@ -67,9 +68,8 @@ interface ILauncherApps {
LauncherApps.AppUsageLimit getAppUsageLimit(String callingPackage, String packageName,
in UserHandle user);
- ParceledListSlice getShortcuts(String callingPackage, long changedSince, String packageName,
- in List shortcutIds, in List<LocusId> locusIds, in ComponentName componentName,
- int flags, in UserHandle user);
+ ParceledListSlice getShortcuts(String callingPackage, in ShortcutQueryWrapper query,
+ in UserHandle user);
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
boolean startShortcut(String callingPackage, String packageName, String featureId, String id,
@@ -93,9 +93,8 @@ interface ILauncherApps {
in IPackageInstallerCallback callback);
ParceledListSlice getAllSessions(String callingPackage);
- void registerShortcutChangeCallback(String callingPackage, long changedSince,
- String packageName, in List shortcutIds, in List<LocusId> locusIds,
- in ComponentName componentName, int flags, in IShortcutChangeCallback callback);
+ void registerShortcutChangeCallback(String callingPackage, in ShortcutQueryWrapper query,
+ in IShortcutChangeCallback callback);
void unregisterShortcutChangeCallback(String callingPackage,
in IShortcutChangeCallback callback);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6c161fcb8646..87dc0a17f41c 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1046,8 +1046,7 @@ public class LauncherApps {
// changed callback, but that only returns shortcuts with the "key" information, so
// that won't return disabled message.
return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
- query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
- query.mActivity, query.mQueryFlags, user)
+ new ShortcutQueryWrapper(query), user)
.getList());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1826,8 +1825,7 @@ public class LauncherApps {
mShortcutChangeCallbacks.put(callback, new Pair<>(executor, proxy));
try {
mService.registerShortcutChangeCallback(mContext.getPackageName(),
- query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
- query.mActivity, query.mQueryFlags, proxy);
+ new ShortcutQueryWrapper(query), proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/ShortcutQueryWrapper.aidl b/core/java/android/content/pm/ShortcutQueryWrapper.aidl
new file mode 100644
index 000000000000..d02600acf232
--- /dev/null
+++ b/core/java/android/content/pm/ShortcutQueryWrapper.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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 android.content.pm;
+
+parcelable ShortcutQueryWrapper;
+
diff --git a/core/java/android/content/pm/ShortcutQueryWrapper.java b/core/java/android/content/pm/ShortcutQueryWrapper.java
new file mode 100644
index 000000000000..c6134416adbc
--- /dev/null
+++ b/core/java/android/content/pm/ShortcutQueryWrapper.java
@@ -0,0 +1,190 @@
+/*
+ * 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 android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.LocusId;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+@DataClass(genParcelable = true, genToString = true)
+public final class ShortcutQueryWrapper extends LauncherApps.ShortcutQuery implements Parcelable {
+
+ public ShortcutQueryWrapper(LauncherApps.ShortcutQuery query) {
+ this();
+ mChangedSince = query.mChangedSince;
+ mPackage = query.mPackage;
+ mLocusIds = query.mLocusIds;
+ mShortcutIds = query.mShortcutIds;
+ mActivity = query.mActivity;
+ mQueryFlags = query.mQueryFlags;
+ }
+
+ public long getChangedSince() {
+ return mChangedSince;
+ }
+
+ @Nullable
+ public String getPackage() {
+ return mPackage;
+ }
+
+ @Nullable
+ public List<LocusId> getLocusIds() {
+ return mLocusIds;
+ }
+
+ @Nullable
+ public List<String> getShortcutIds() {
+ return mShortcutIds;
+ }
+
+ @Nullable
+ public ComponentName getActivity() {
+ return mActivity;
+ }
+
+ public int getQueryFlags() {
+ return mQueryFlags;
+ }
+
+ // Code below generated by codegen v1.0.14.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ShortcutQueryWrapper.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @DataClass.Generated.Member
+ public ShortcutQueryWrapper() {
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "ShortcutQueryWrapper { " +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mPackage != null) flg |= 0x2;
+ if (mShortcutIds != null) flg |= 0x4;
+ if (mLocusIds != null) flg |= 0x8;
+ if (mActivity != null) flg |= 0x10;
+ dest.writeByte(flg);
+ dest.writeLong(mChangedSince);
+ if (mPackage != null) dest.writeString(mPackage);
+ if (mShortcutIds != null) dest.writeStringList(mShortcutIds);
+ if (mLocusIds != null) dest.writeParcelableList(mLocusIds, flags);
+ if (mActivity != null) dest.writeTypedObject(mActivity, flags);
+ dest.writeInt(mQueryFlags);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ ShortcutQueryWrapper(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ long changedSince = in.readLong();
+ String pkg = (flg & 0x2) == 0 ? null : in.readString();
+ List<String> shortcutIds = null;
+ if ((flg & 0x4) != 0) {
+ shortcutIds = new ArrayList<>();
+ in.readStringList(shortcutIds);
+ }
+ List<LocusId> locusIds = null;
+ if ((flg & 0x8) != 0) {
+ locusIds = new ArrayList<>();
+ in.readParcelableList(locusIds, LocusId.class.getClassLoader());
+ }
+ ComponentName activity = (flg & 0x10) == 0 ? null
+ : (ComponentName) in.readTypedObject(ComponentName.CREATOR);
+ int queryFlags = in.readInt();
+
+ this.mChangedSince = changedSince;
+ this.mPackage = pkg;
+ this.mShortcutIds = shortcutIds;
+ this.mLocusIds = locusIds;
+ this.mActivity = activity;
+ this.mQueryFlags = queryFlags;
+ com.android.internal.util.AnnotationValidations.validate(
+ QueryFlags.class, null, mQueryFlags);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ShortcutQueryWrapper> CREATOR
+ = new Parcelable.Creator<ShortcutQueryWrapper>() {
+ @Override
+ public ShortcutQueryWrapper[] newArray(int size) {
+ return new ShortcutQueryWrapper[size];
+ }
+
+ @Override
+ public ShortcutQueryWrapper createFromParcel(@NonNull Parcel in) {
+ return new ShortcutQueryWrapper(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1582049937960L,
+ codegenVersion = "1.0.14",
+ sourceFile = "frameworks/base/core/java/android/content/pm/ShortcutQueryWrapper.java",
+ inputSignatures = "public long getChangedSince()\npublic @android.annotation.Nullable java.lang.String getPackage()\npublic @android.annotation.Nullable java.util.List<android.content.LocusId> getLocusIds()\npublic @android.annotation.Nullable java.util.List<java.lang.String> getShortcutIds()\npublic @android.annotation.Nullable android.content.ComponentName getActivity()\npublic int getQueryFlags()\nclass ShortcutQueryWrapper extends android.content.pm.LauncherApps.ShortcutQuery implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genToString=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 7ff954bdc1d2..651494d1c99c 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -1074,6 +1074,21 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Returns true if this link has an IPv4 unreachable default route.
+ *
+ * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
+ * @hide
+ */
+ public boolean hasIpv4UnreachableDefaultRoute() {
+ for (RouteInfo r : mRoutes) {
+ if (r.isIPv4UnreachableDefault()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* For backward compatibility.
* This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
* just yet.
@@ -1102,6 +1117,21 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Returns true if this link has an IPv6 unreachable default route.
+ *
+ * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
+ * @hide
+ */
+ public boolean hasIpv6UnreachableDefaultRoute() {
+ for (RouteInfo r : mRoutes) {
+ if (r.isIPv6UnreachableDefault()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* For backward compatibility.
* This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
* just yet.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index dbdaa4c2da67..e550f85e6b9a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -426,6 +426,16 @@ public final class RouteInfo implements Parcelable {
}
/**
+ * Indicates if this route is an unreachable default route.
+ *
+ * @return {@code true} if it's an unreachable route with prefix length of 0.
+ * @hide
+ */
+ private boolean isUnreachableDefaultRoute() {
+ return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0;
+ }
+
+ /**
* Indicates if this route is an IPv4 default route.
* @hide
*/
@@ -434,6 +444,14 @@ public final class RouteInfo implements Parcelable {
}
/**
+ * Indicates if this route is an IPv4 unreachable default route.
+ * @hide
+ */
+ public boolean isIPv4UnreachableDefault() {
+ return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
+ }
+
+ /**
* Indicates if this route is an IPv6 default route.
* @hide
*/
@@ -442,6 +460,14 @@ public final class RouteInfo implements Parcelable {
}
/**
+ * Indicates if this route is an IPv6 unreachable default route.
+ * @hide
+ */
+ public boolean isIPv6UnreachableDefault() {
+ return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
+ }
+
+ /**
* Indicates if this route is a host route (ie, matches only a single host address).
*
* @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index fb81d675939c..e86aa62d00bc 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -266,6 +266,13 @@ public final class DeviceConfig {
public static final String NAMESPACE_SCHEDULER = "scheduler";
/**
+ * Namespace for settings statistics features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_SETTINGS_STATS = "settings_stats";
+
+ /**
* Namespace for storage-related features.
*
* @deprecated Replace storage namespace with storage_native_boot.
diff --git a/core/tests/coretests/src/android/content/pm/ShortcutQueryWrapperTest.java b/core/tests/coretests/src/android/content/pm/ShortcutQueryWrapperTest.java
new file mode 100644
index 000000000000..8f8488f8b287
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/ShortcutQueryWrapperTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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 android.content.pm;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.ComponentName;
+import android.content.LocusId;
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class ShortcutQueryWrapperTest {
+
+ private static final long CHANGED_SINCE = TimeUnit.SECONDS.toMillis(1);
+ private static final String PACKAGE_NAME = "com.android.test";
+ private static final List<String> SHORTCUT_IDS = Lists.newArrayList("s1", "s2", "s3");
+ private static final List<LocusId> LOCUS_IDS = Lists.newArrayList(
+ new LocusId("id1"), new LocusId("id2"), new LocusId("id3"));
+ private static final ComponentName COMPONENT_NAME = new ComponentName(
+ PACKAGE_NAME, "ShortcutQueryTest");
+ private static final int QUERY_FLAG = LauncherApps.ShortcutQuery.FLAG_MATCH_ALL_KINDS;
+
+ private ShortcutQueryWrapper mShortcutQuery;
+
+ @Before
+ public void setUp() throws Exception {
+ mShortcutQuery = new ShortcutQueryWrapper(new LauncherApps.ShortcutQuery()
+ .setChangedSince(CHANGED_SINCE)
+ .setPackage(PACKAGE_NAME)
+ .setShortcutIds(SHORTCUT_IDS)
+ .setLocusIds(LOCUS_IDS)
+ .setActivity(COMPONENT_NAME)
+ .setQueryFlags(QUERY_FLAG));
+ }
+
+ @Test
+ public void testWriteAndReadFromParcel() {
+ Parcel p = Parcel.obtain();
+ mShortcutQuery.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ ShortcutQueryWrapper q = ShortcutQueryWrapper.CREATOR.createFromParcel(p);
+ assertEquals("Changed since doesn't match!", CHANGED_SINCE, q.getChangedSince());
+ assertEquals("Package name doesn't match!", PACKAGE_NAME, q.getPackage());
+ assertEquals("Shortcut ids doesn't match", SHORTCUT_IDS, q.getShortcutIds());
+ assertEquals("Locus ids doesn't match", LOCUS_IDS, q.getLocusIds());
+ assertEquals("Component name doesn't match", COMPONENT_NAME, q.getActivity());
+ assertEquals("Query flag doesn't match", QUERY_FLAG, q.getQueryFlags());
+ p.recycle();
+ }
+}
diff --git a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml b/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml
new file mode 100644
index 000000000000..8f8f1b664692
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml
@@ -0,0 +1,162 @@
+<!--
+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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M206,150m-150,0a150,150 0,1 1,300 0a150,150 0,1 1,-300 0"/>
+ <path
+ android:pathData="M296,105.2h-9.6l-3.1,-2.5l-3.1,2.5H116c-1.7,0 -3,1.3 -3,3v111.7c0,1.7 1.3,3 3,3h180c1.7,0 3,-1.3 3,-3V108.2C299,106.6 297.7,105.2 296,105.2C296,105.2 296,105.2 296,105.2z"
+ android:fillColor="#3C4043"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M252.4,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#D2E3FC"
+ android:strokeColor="#4285F4"/>
+ <path
+ android:pathData="M261.9,95.7m-4.5,0a4.5,4.5 0,1 1,9 0a4.5,4.5 0,1 1,-9 0"
+ android:fillColor="#4285F4"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M160.6,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#FAD2CF"
+ android:strokeColor="#EA4335"/>
+ <path
+ android:pathData="M170.1,95.7m-4.6,0a4.6,4.6 0,1 1,9.2 0a4.6,4.6 0,1 1,-9.2 0"
+ android:fillColor="#EA4335"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M192.1,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#FEEFC3"
+ android:strokeColor="#FBBC04"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M221.8,85.4m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#CEEAD6"
+ android:strokeColor="#34A853"/>
+ <path
+ android:pathData="M201.6,95.7m-4.6,0a4.6,4.6 0,1 1,9.2 0a4.6,4.6 0,1 1,-9.2 0"
+ android:fillColor="#FBBC04"/>
+ <path
+ android:pathData="M231.4,95.7m-4.6,0a4.6,4.6 0,1 1,9.2 0a4.6,4.6 0,1 1,-9.2 0"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M282.8,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#3C4043"/>
+ <path
+ android:pathData="M278.7,85.7m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M282.8,85.7m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M286.9,85.7m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M129.2,72.9h-3.4l0.3,1c1,-0.3 2.1,-0.4 3.2,-0.4v-1V72.9zM122.6,74.8c-0.5,0.3 -1,0.6 -1.4,1l0,0l0,0l0,0l0,0h-0.6l0,0l0,0l0,0l0,0l0,0l0,0c-0.2,0.2 -0.3,0.3 -0.4,0.5l0.8,0.7c0.7,-0.8 1.5,-1.5 2.4,-2.1l-0.5,-0.8L122.6,74.8zM118,80L118,80L118,80L118,80L118,80L118,80L118,80L118,80c-0.5,1 -0.8,2 -1,3l1,0.2c0.2,-1 0.5,-2 1,-3L118,80zM117.8,86.7l-1,0.1c0.1,0.6 0.2,1.1 0.3,1.7l0,0l0,0h0.1l0,0l0,0l0,0l0,0c0.1,0.5 0.3,0.9 0.5,1.4l0.9,-0.4c-0.4,-1 -0.7,-2 -0.8,-3.1L117.8,86.7zM120.2,92.5l-0.8,0.6l0.2,0.3l0,0l0,0l0,0l0,0h0.3l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0.4,0.4l0,0l0,0l0,0l0,0h0.1l0,0l0,0l0,0l0,0l0,0h0.5l0,0l0,0l0,0l0,0l0,0l0,0l0.6,0.4l0.6,-0.8c-0.9,-0.6 -1.7,-1.4 -2.3,-2.2L120.2,92.5zM125.4,96.2l-0.3,0.9c1.1,0.4 2.2,0.6 3.4,0.7l0.1,-1C127.5,96.7 126.4,96.5 125.4,96.2zM134.7,95.4c-0.9,0.5 -2,0.9 -3,1.1l0.2,1h0.4c1,-0.3 2,-0.6 2.9,-1.2l-0.5,-0.9L134.7,95.4zM139.2,90.9c-0.5,0.9 -1.2,1.8 -1.9,2.5l0.7,0.7v-0.1h0.2l0,0l0,0c0.7,-0.7 1.3,-1.6 1.8,-2.4l-0.9,-0.5L139.2,90.9zM141.6,84.7h-1c0,0.2 0,0.4 0,0.6c0,0.9 -0.1,1.7 -0.3,2.6l1,0.2c0.1,-0.4 0.2,-0.8 0.2,-1.2l0,0v-0.1l0,0v-0.1l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0c0,-0.2 0,-0.3 0,-0.5l0,0L141.6,84.7zM139.3,78.2l-0.8,0.6c0.6,0.9 1.1,1.8 1.5,2.8l0.9,-0.3c-0.1,-0.2 -0.2,-0.4 -0.2,-0.7l0,0l0,0h-0.1l0,0l0,0l0,0l0,0l0,0l0,0c-0.3,-0.7 -0.7,-1.4 -1.1,-2l0,0l0,0l0,0l0,0l0,0l0,0l0,0L139.3,78.2zM134,73.9l-0.4,0.9c1,0.4 1.9,1 2.7,1.6l0.6,-0.8l0,0l0,0l0,0l0,0l0,0c-0.3,-0.3 -0.7,-0.5 -1,-0.7l0,0h-0.1h-0.6c-0.4,-0.2 -0.8,-0.4 -1.2,-0.6L134,73.9zM129.2,72.9v1c0.4,0 0.9,0 1.3,0.1l0.1,-1l-0.9,-0.1L129.2,72.9L129.2,72.9z"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M206,252m-11.7,0a11.7,11.7 0,1 1,23.4 0a11.7,11.7 0,1 1,-23.4 0"
+ android:fillColor="#F1F3F4"/>
+ <path
+ android:pathData="M201.7,247.7L210.3,256.3"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#202124"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M210.3,247.7L201.7,256.3"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#202124"
+ android:strokeLineCap="round"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M205.3,221.9m-10.4,0a10.4,10.4 0,1 1,20.8 0a10.4,10.4 0,1 1,-20.8 0"
+ android:fillColor="#CEEAD6"
+ android:strokeColor="#34A853"/>
+ <path
+ android:pathData="M481.4,292.2c48,58.3 119.8,125.8 58.6,162.9c-38.7,23.5 -53.9,24 -98.3,33.2c-43.8,9.1 -93.6,-89.8 -101.1,-134.5C329.6,288.6 452.6,257.2 481.4,292.2z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M458.2,320.7l-21.1,-71.4L400.5,193c-2.7,-5.1 -1.2,-11.4 3.5,-14.7l0,0c2.8,-2 6.6,-1.5 8.8,1.1c0,0 40.6,38.4 53.2,61.1l81.5,134.8l-69.9,-39.1L458.2,320.7z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M403.8,184.8l5.4,6.9c1.2,1.5 3.3,1.9 4.9,0.9l3,-1.8"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M420.9,325.8l-37.8,-88.6l-58.4,-37.8c-5.7,-5.4 -7.4,-13.8 -4.2,-21l0,0c2,-4.6 7.4,-6.7 12,-4.6c0.2,0.1 0.4,0.2 0.7,0.3c0,0 70.7,36.3 81.5,48.3l59.8,95.5l-49.9,24.9L420.9,325.8z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M324.6,183.9l8,6.2c2.1,1.7 5.2,1.4 7,-0.6l2.9,-3.3"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M392.4,231c3.8,-5.1 9.1,-8.9 15.1,-10.9"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ <path
+ android:pathData="M401.3,283.8L405.8,292.6"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ <path
+ android:pathData="M378.2,346.9l-34.7,-75.6l-60,-61.2c-6.3,-4.7 -9,-12.8 -6.7,-20.4l0,0c1.5,-4.8 6.5,-7.5 11.3,-6c0.2,0.1 0.4,0.1 0.7,0.2c0,0 73.5,48.2 82.6,61.7l64.1,95.7l-40.3,23.5L378.2,346.9z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M280.8,196.6l7.6,4.6c2.6,1.6 5.9,1.1 7.9,-1.1l4.1,-4.5"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M347.5,251c3.8,-5.1 9.1,-8.9 15.1,-10.9"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ <path
+ android:pathData="M207.2,234.1c-8.8,-11 4.7,-31.5 19.8,-19c17.7,14.7 74.7,64.3 74.7,64.3l103.8,101.8c0,0 -36.4,53.8 -44.5,42.3C287.8,319.3 234.4,267.9 207.2,234.1z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M209.6,226.2l9.3,9.5c1,0.8 3,0.4 3.1,-1c0.2,-2.2 4.6,-6.2 7,-6.6c1.1,-0.3 1.7,-1.4 1.4,-2.4c-0.1,-0.2 -0.2,-0.4 -0.3,-0.6l-4.4,-3.9"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M284.1,296.2c3.1,-5.5 7.8,-10 13.5,-12.8"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ </group>
+ <path
+ android:pathData="M206,4c80.6,0 146,65.4 146,146c0,38.7 -15.4,75.9 -42.8,103.2c-57,57 -149.5,57 -206.5,0s-57,-149.5 0,-206.5C130.1,19.3 167.3,3.9 206,4M206,0C123.2,0 56,67.2 56,150s67.2,150 150,150s150,-67.2 150,-150S288.8,0 206,0z"
+ android:fillColor="#D2E3FC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml b/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml
new file mode 100644
index 000000000000..5e02f67700e7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml
@@ -0,0 +1,162 @@
+<!--
+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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="412dp"
+ android:height="300dp"
+ android:viewportWidth="412"
+ android:viewportHeight="300">
+ <group>
+ <clip-path
+ android:pathData="M206,150m-150,0a150,150 0,1 1,300 0a150,150 0,1 1,-300 0"/>
+ <path
+ android:pathData="M296,105.2h-9.6l-3.1,-2.5l-3.1,2.5H116c-1.7,0 -3,1.3 -3,3v111.7c0,1.7 1.3,3 3,3h180c1.7,0 3,-1.3 3,-3V108.2C299,106.6 297.7,105.2 296,105.2L296,105.2z"
+ android:fillColor="#F1F3F4"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M252.4,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#D2E3FC"
+ android:strokeColor="#4285F4"/>
+ <path
+ android:pathData="M261.9,95.7m-4.5,0a4.5,4.5 0,1 1,9 0a4.5,4.5 0,1 1,-9 0"
+ android:fillColor="#4285F4"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M160.6,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#FAD2CF"
+ android:strokeColor="#EA4335"/>
+ <path
+ android:pathData="M170.1,95.7m-4.6,0a4.6,4.6 0,1 1,9.2 0a4.6,4.6 0,1 1,-9.2 0"
+ android:fillColor="#EA4335"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M192.1,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#FEEFC3"
+ android:strokeColor="#FBBC04"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M221.8,85.4m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#CEEAD6"
+ android:strokeColor="#34A853"/>
+ <path
+ android:pathData="M201.6,95.7m-4.6,0a4.6,4.6 0,1 1,9.2 0a4.6,4.6 0,1 1,-9.2 0"
+ android:fillColor="#FBBC04"/>
+ <path
+ android:pathData="M231.4,95.7m-4.6,0a4.6,4.6 0,1 1,9.2 0a4.6,4.6 0,1 1,-9.2 0"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M282.8,85.3m-12.4,0a12.4,12.4 0,1 1,24.8 0a12.4,12.4 0,1 1,-24.8 0"
+ android:fillColor="#F1F3F4"/>
+ <path
+ android:pathData="M278.7,85.7m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0"
+ android:fillColor="#3474E0"/>
+ <path
+ android:pathData="M282.8,85.7m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0"
+ android:fillColor="#3474E0"/>
+ <path
+ android:pathData="M286.9,85.7m-1.2,0a1.2,1.2 0,1 1,2.4 0a1.2,1.2 0,1 1,-2.4 0"
+ android:fillColor="#3474E0"/>
+ <path
+ android:pathData="M129.2,72.9h-3.4l0.3,1c1,-0.3 2.1,-0.4 3.2,-0.4v-1v0.4H129.2zM122.6,74.8c-0.5,0.3 -1,0.6 -1.4,1l0,0l0,0l0,0l0,0h-0.6l0,0l0,0l0,0l0,0l0,0l0,0c-0.2,0.2 -0.3,0.3 -0.4,0.5L121,77c0.7,-0.8 1.5,-1.5 2.4,-2.1l-0.5,-0.8L122.6,74.8zM118,80L118,80L118,80L118,80L118,80L118,80L118,80L118,80c-0.5,1 -0.8,2 -1,3l1,0.2c0.2,-1 0.5,-2 1,-3L118,80zM117.8,86.7l-1,0.1c0.1,0.6 0.2,1.1 0.3,1.7l0,0l0,0h0.1l0,0l0,0l0,0l0,0c0.1,0.5 0.3,0.9 0.5,1.4l0.9,-0.4c-0.4,-1 -0.7,-2 -0.8,-3.1V86.7zM120.2,92.5l-0.8,0.6l0.2,0.3l0,0l0,0l0,0l0,0h0.3l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0.4,0.4l0,0l0,0l0,0l0,0h0.1l0,0l0,0l0,0l0,0l0,0h0.5l0,0l0,0l0,0l0,0l0,0l0,0l0.6,0.4l0.6,-0.8c-0.9,-0.6 -1.7,-1.4 -2.3,-2.2L120.2,92.5zM125.4,96.2l-0.3,0.9c1.1,0.4 2.2,0.6 3.4,0.7l0.1,-1C127.5,96.7 126.4,96.5 125.4,96.2zM134.7,95.4c-0.9,0.5 -2,0.9 -3,1.1l0.2,1h0.4c1,-0.3 2,-0.6 2.9,-1.2L134.7,95.4L134.7,95.4zM139.2,90.9c-0.5,0.9 -1.2,1.8 -1.9,2.5l0.7,0.7V94h0.2l0,0l0,0c0.7,-0.7 1.3,-1.6 1.8,-2.4l-0.9,-0.5L139.2,90.9zM141.6,84.7h-1c0,0.2 0,0.4 0,0.6c0,0.9 -0.1,1.7 -0.3,2.6l1,0.2c0.1,-0.4 0.2,-0.8 0.2,-1.2l0,0v-0.1l0,0v-0.1l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0l0,0c0,-0.2 0,-0.3 0,-0.5l0,0L141.6,84.7zM139.3,78.2l-0.8,0.6c0.6,0.9 1.1,1.8 1.5,2.8l0.9,-0.3c-0.1,-0.2 -0.2,-0.4 -0.2,-0.7l0,0l0,0h-0.1l0,0l0,0l0,0l0,0l0,0l0,0c-0.3,-0.7 -0.7,-1.4 -1.1,-2l0,0l0,0l0,0l0,0l0,0l0,0l0,0L139.3,78.2zM134,73.9l-0.4,0.9c1,0.4 1.9,1 2.7,1.6l0.6,-0.8l0,0l0,0l0,0l0,0l0,0c-0.3,-0.3 -0.7,-0.5 -1,-0.7l0,0h-0.1h-0.6c-0.4,-0.2 -0.8,-0.4 -1.2,-0.6V73.9zM129.2,72.9v1c0.4,0 0.9,0 1.3,0.1l0.1,-1l-0.9,-0.1H129.2L129.2,72.9z"
+ android:fillColor="#34A853"/>
+ <path
+ android:pathData="M206,252m-11.7,0a11.7,11.7 0,1 1,23.4 0a11.7,11.7 0,1 1,-23.4 0"
+ android:fillColor="#9AA0A6"/>
+ <path
+ android:pathData="M201.7,247.7L210.3,256.3"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#F1F3F4"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M210.3,247.7L201.7,256.3"
+ android:strokeWidth="2"
+ android:fillColor="#00000000"
+ android:strokeColor="#F1F3F4"
+ android:strokeLineCap="round"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M205.3,221.9m-10.4,0a10.4,10.4 0,1 1,20.8 0a10.4,10.4 0,1 1,-20.8 0"
+ android:fillColor="#CEEAD6"
+ android:strokeColor="#34A853"/>
+ <path
+ android:pathData="M481.4,292.2c48,58.3 119.8,125.8 58.6,162.9c-38.7,23.5 -53.9,24 -98.3,33.2c-43.8,9.1 -93.6,-89.8 -101.1,-134.5C329.6,288.6 452.6,257.2 481.4,292.2z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M458.2,320.7l-21.1,-71.4L400.5,193c-2.7,-5.1 -1.2,-11.4 3.5,-14.7l0,0c2.8,-2 6.6,-1.5 8.8,1.1c0,0 40.6,38.4 53.2,61.1l81.5,134.8l-69.9,-39.1L458.2,320.7z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M403.8,184.8l5.4,6.9c1.2,1.5 3.3,1.9 4.9,0.9l3,-1.8"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M420.9,325.8l-37.8,-88.6l-58.4,-37.8c-5.7,-5.4 -7.4,-13.8 -4.2,-21l0,0c2,-4.6 7.4,-6.7 12,-4.6c0.2,0.1 0.4,0.2 0.7,0.3c0,0 70.7,36.3 81.5,48.3l59.8,95.5l-49.9,24.9L420.9,325.8z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M324.6,183.9l8,6.2c2.1,1.7 5.2,1.4 7,-0.6l2.9,-3.3"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M392.4,231c3.8,-5.1 9.1,-8.9 15.1,-10.9"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ <path
+ android:pathData="M401.3,283.8L405.8,292.6"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ <path
+ android:pathData="M378.2,346.9l-34.7,-75.6l-60,-61.2c-6.3,-4.7 -9,-12.8 -6.7,-20.4l0,0c1.5,-4.8 6.5,-7.5 11.3,-6c0.2,0.1 0.4,0.1 0.7,0.2c0,0 73.5,48.2 82.6,61.7l64.1,95.7l-40.3,23.5L378.2,346.9z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M280.8,196.6l7.6,4.6c2.6,1.6 5.9,1.1 7.9,-1.1l4.1,-4.5"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M347.5,251c3.8,-5.1 9.1,-8.9 15.1,-10.9"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ <path
+ android:pathData="M207.2,234.1c-8.8,-11 4.7,-31.5 19.8,-19c17.7,14.7 74.7,64.3 74.7,64.3l103.8,101.8c0,0 -36.4,53.8 -44.5,42.3C287.8,319.3 234.4,267.9 207.2,234.1z"
+ android:fillColor="#D2E3FC"/>
+ <path
+ android:pathData="M209.6,226.2l9.3,9.5c1,0.8 3,0.4 3.1,-1c0.2,-2.2 4.6,-6.2 7,-6.6c1.1,-0.3 1.7,-1.4 1.4,-2.4c-0.1,-0.2 -0.2,-0.4 -0.3,-0.6l-4.4,-3.9"
+ android:strokeLineJoin="bevel"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"
+ android:strokeLineCap="square"/>
+ <path
+ android:pathData="M284.1,296.2c3.1,-5.5 7.8,-10 13.5,-12.8"
+ android:strokeWidth="1.75"
+ android:fillColor="#00000000"
+ android:strokeColor="#A0C2F9"/>
+ </group>
+ <path
+ android:pathData="M206,4c80.6,0 146,65.4 146,146c0,38.7 -15.4,75.9 -42.8,103.2c-57,57 -149.5,57 -206.5,0s-57,-149.5 0,-206.5C130.1,19.3 167.3,3.9 206,4M206,0C123.2,0 56,67.2 56,150s67.2,150 150,150s150,-67.2 150,-150S288.8,0 206,0z"
+ android:fillColor="#D2E3FC"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
index b3c7cf74941a..306061911f8d 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_activity.xml
+++ b/packages/SystemUI/res/layout/bubble_overflow_activity.xml
@@ -41,6 +41,13 @@
android:orientation="vertical"
android:gravity="center">
+ <ImageView
+ android:layout_width="@dimen/bubble_empty_overflow_image_height"
+ android:layout_height="@dimen/bubble_empty_overflow_image_height"
+ android:id="@+id/bubble_overflow_empty_state_image"
+ android:scaleType="fitCenter"
+ android:layout_gravity="center"/>
+
<TextView
android:id="@+id/bubble_overflow_empty_title"
android:text="@string/bubble_overflow_empty_title"
@@ -59,6 +66,7 @@
android:text="@string/bubble_overflow_empty_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/bubble_empty_overflow_subtitle_padding"
android:gravity="center"/>
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_media_panel.xml b/packages/SystemUI/res/layout/qs_media_panel.xml
index fe8557bfcce4..fc3bf941b27a 100644
--- a/packages/SystemUI/res/layout/qs_media_panel.xml
+++ b/packages/SystemUI/res/layout/qs_media_panel.xml
@@ -136,6 +136,47 @@
</LinearLayout>
</LinearLayout>
+ <!-- Seek Bar -->
+ <SeekBar
+ android:id="@+id/media_progress_bar"
+ android:clickable="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:maxHeight="3dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp"
+ android:layout_marginBottom="-24dp"
+ android:layout_marginTop="-24dp"
+ android:splitTrack="false"
+ />
+
+ <FrameLayout
+ android:id="@+id/notification_media_progress_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ >
+ <!-- width is set to "match_parent" to avoid extra layout calls -->
+ <TextView
+ android:id="@+id/media_elapsed_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:textSize="14sp"
+ android:gravity="left"
+ />
+ <TextView
+ android:id="@+id/media_total_time"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_bodyFontFamily"
+ android:layout_alignParentRight="true"
+ android:textSize="14sp"
+ android:gravity="right"
+ />
+ </FrameLayout>
+
<!-- Controls -->
<LinearLayout
android:id="@+id/media_actions"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9074dad608ce..5b213edd5f0f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1155,6 +1155,10 @@
<dimen name="bubble_overflow_padding">15dp</dimen>
<!-- Padding of label for bubble overflow view -->
<dimen name="bubble_overflow_text_padding">7dp</dimen>
+ <!-- Height of bubble overflow empty state illustration -->
+ <dimen name="bubble_empty_overflow_image_height">200dp</dimen>
+ <!-- Padding of bubble overflow empty state subtitle -->
+ <dimen name="bubble_empty_overflow_subtitle_padding">50dp</dimen>
<!-- Height of the triangle that points to the expanded bubble -->
<dimen name="bubble_pointer_height">4dp</dimen>
<!-- Width of the triangle that points to the expanded bubble -->
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index 3f985ef37746..37841f24a3cf 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -21,18 +21,17 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.Activity;
-import android.app.Notification;
-import android.app.Person;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Bundle;
-import android.os.Parcelable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -55,6 +54,7 @@ public class BubbleOverflowActivity extends Activity {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleOverflowActivity" : TAG_BUBBLES;
private LinearLayout mEmptyState;
+ private ImageView mEmptyStateImage;
private BubbleController mBubbleController;
private BubbleOverflowAdapter mAdapter;
private RecyclerView mRecyclerView;
@@ -73,6 +73,7 @@ public class BubbleOverflowActivity extends Activity {
mEmptyState = findViewById(R.id.bubble_overflow_empty_state);
mRecyclerView = findViewById(R.id.bubble_overflow_recycler);
+ mEmptyStateImage = findViewById(R.id.bubble_overflow_empty_state_image);
Resources res = getResources();
final int columns = res.getInteger(R.integer.bubbles_overflow_columns);
@@ -98,6 +99,31 @@ public class BubbleOverflowActivity extends Activity {
mBubbleController.setOverflowCallback(() -> {
onDataChanged(mBubbleController.getOverflowBubbles());
});
+ onThemeChanged();
+ }
+
+ /**
+ * Handle theme changes.
+ */
+ void onThemeChanged() {
+ final int mode =
+ getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ switch (mode) {
+ case Configuration.UI_MODE_NIGHT_NO:
+ if (DEBUG_OVERFLOW) {
+ Log.d(TAG, "Set overflow UI to light mode");
+ }
+ mEmptyStateImage.setImageDrawable(
+ getResources().getDrawable(R.drawable.ic_empty_bubble_overflow_light));
+ break;
+ case Configuration.UI_MODE_NIGHT_YES:
+ if (DEBUG_OVERFLOW) {
+ Log.d(TAG, "Set overflow UI to dark mode");
+ }
+ mEmptyStateImage.setImageDrawable(
+ getResources().getDrawable(R.drawable.ic_empty_bubble_overflow_dark));
+ break;
+ }
}
void setBackgroundColor() {
@@ -138,6 +164,7 @@ public class BubbleOverflowActivity extends Activity {
@Override
public void onResume() {
super.onResume();
+ onThemeChanged();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 6a7b0da0d8d8..eff693436451 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -713,7 +713,7 @@ public class BubbleStackView extends FrameLayout {
} else {
mBubbleContainer.removeView(mBubbleOverflow.getBtn());
mBubbleOverflow.updateIcon(mContext, this);
- overflowBtnIndex = mBubbleContainer.getChildCount() - 1;
+ overflowBtnIndex = mBubbleContainer.getChildCount();
}
mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 6d99ef1829b2..fdd859373685 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -78,10 +78,13 @@ import android.widget.ImageView.ScaleType;
import android.widget.TextView;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.EmergencyAffordanceManager;
@@ -171,6 +174,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final IActivityManager mIActivityManager;
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
+ private final UiEventLogger mUiEventLogger;
private final NotificationShadeDepthController mDepthController;
private final BlurUtils mBlurUtils;
@@ -203,6 +207,23 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final ControlsListingController mControlsListingController;
private boolean mAnyControlsProviders = false;
+ @VisibleForTesting
+ public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The global actions / power menu surface became visible on the screen.")
+ GA_POWER_MENU_OPEN(337);
+
+ private final int mId;
+
+ GlobalActionsEvent(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+
/**
* @param context everything needs a context :(
*/
@@ -223,7 +244,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
ControlsUiController controlsUiController, IWindowManager iWindowManager,
@Background Executor backgroundExecutor,
ControlsListingController controlsListingController,
- ControlsController controlsController) {
+ ControlsController controlsController, UiEventLogger uiEventLogger) {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -240,6 +261,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mIActivityManager = iActivityManager;
mTelecomManager = telecomManager;
mMetricsLogger = metricsLogger;
+ mUiEventLogger = uiEventLogger;
mDepthController = depthController;
mSysuiColorExtractor = colorExtractor;
mStatusBarService = statusBarService;
@@ -997,6 +1019,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
*/
public void onShow(DialogInterface dialog) {
mMetricsLogger.visible(MetricsEvent.POWER_MENU);
+ mUiEventLogger.log(GlobalActionsEvent.GA_POWER_MENU_OPEN);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
new file mode 100644
index 000000000000..aa5ebaa22f2d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.systemui.media
+
+import android.content.res.ColorStateList
+import android.text.format.DateUtils
+import android.view.View
+import android.widget.SeekBar
+import android.widget.TextView
+import androidx.annotation.UiThread
+import androidx.lifecycle.Observer
+
+import com.android.systemui.R
+
+/**
+ * Observer for changes from SeekBarViewModel.
+ *
+ * <p>Updates the seek bar views in response to changes to the model.
+ */
+class SeekBarObserver(view: View) : Observer<SeekBarViewModel.Progress> {
+
+ private val seekBarView: SeekBar
+ private val elapsedTimeView: TextView
+ private val totalTimeView: TextView
+
+ init {
+ seekBarView = view.findViewById(R.id.media_progress_bar)
+ elapsedTimeView = view.findViewById(R.id.media_elapsed_time)
+ totalTimeView = view.findViewById(R.id.media_total_time)
+ }
+
+ /** Updates seek bar views when the data model changes. */
+ @UiThread
+ override fun onChanged(data: SeekBarViewModel.Progress) {
+ if (data.enabled && seekBarView.visibility == View.GONE) {
+ seekBarView.visibility = View.VISIBLE
+ elapsedTimeView.visibility = View.VISIBLE
+ totalTimeView.visibility = View.VISIBLE
+ } else if (!data.enabled && seekBarView.visibility == View.VISIBLE) {
+ seekBarView.visibility = View.GONE
+ elapsedTimeView.visibility = View.GONE
+ totalTimeView.visibility = View.GONE
+ return
+ }
+
+ // TODO: update the style of the disabled progress bar
+ seekBarView.setEnabled(data.seekAvailable)
+
+ data.color?.let {
+ var tintList = ColorStateList.valueOf(it)
+ seekBarView.setThumbTintList(tintList)
+ tintList = tintList.withAlpha(192) // 75%
+ seekBarView.setProgressTintList(tintList)
+ tintList = tintList.withAlpha(128) // 50%
+ seekBarView.setProgressBackgroundTintList(tintList)
+ elapsedTimeView.setTextColor(it)
+ totalTimeView.setTextColor(it)
+ }
+
+ data.elapsedTime?.let {
+ seekBarView.setProgress(it)
+ elapsedTimeView.setText(DateUtils.formatElapsedTime(
+ it / DateUtils.SECOND_IN_MILLIS))
+ }
+
+ data.duration?.let {
+ seekBarView.setMax(it)
+ totalTimeView.setText(DateUtils.formatElapsedTime(
+ it / DateUtils.SECOND_IN_MILLIS))
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
new file mode 100644
index 000000000000..cf8f26841cf9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -0,0 +1,152 @@
+/*
+ * 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.systemui.media
+
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.PlaybackState
+import android.view.MotionEvent
+import android.view.View
+import android.widget.SeekBar
+import androidx.annotation.AnyThread
+import androidx.annotation.WorkerThread
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.LiveData
+
+import com.android.systemui.util.concurrency.DelayableExecutor
+
+private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
+
+/** ViewModel for seek bar in QS media player. */
+class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
+
+ private val _progress = MutableLiveData<Progress>().apply {
+ postValue(Progress(false, false, null, null, null))
+ }
+ val progress: LiveData<Progress>
+ get() = _progress
+ private var controller: MediaController? = null
+ private var playbackState: PlaybackState? = null
+
+ /** Listening state (QS open or closed) is used to control polling of progress. */
+ var listening = true
+ set(value) {
+ if (value) {
+ checkPlaybackPosition()
+ }
+ }
+
+ /**
+ * Handle request to change the current position in the media track.
+ * @param position Place to seek to in the track.
+ */
+ @WorkerThread
+ fun onSeek(position: Long) {
+ controller?.transportControls?.seekTo(position)
+ }
+
+ /**
+ * Updates media information.
+ * @param mediaController controller for media session
+ * @param color foreground color for UI elements
+ */
+ @WorkerThread
+ fun updateController(mediaController: MediaController?, color: Int) {
+ controller = mediaController
+ playbackState = controller?.playbackState
+ val mediaMetadata = controller?.metadata
+ val seekAvailable = ((playbackState?.actions ?: 0L) and PlaybackState.ACTION_SEEK_TO) != 0L
+ val position = playbackState?.position?.toInt()
+ val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt()
+ val enabled = if (duration != null && duration <= 0) false else true
+ _progress.postValue(Progress(enabled, seekAvailable, position, duration, color))
+ if (shouldPollPlaybackPosition()) {
+ checkPlaybackPosition()
+ }
+ }
+
+ @AnyThread
+ private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({
+ val currentPosition = controller?.playbackState?.position?.toInt()
+ if (currentPosition != null && _progress.value!!.elapsedTime != currentPosition) {
+ _progress.postValue(_progress.value!!.copy(elapsedTime = currentPosition))
+ }
+ if (shouldPollPlaybackPosition()) {
+ checkPlaybackPosition()
+ }
+ }, POSITION_UPDATE_INTERVAL_MILLIS)
+
+ @WorkerThread
+ private fun shouldPollPlaybackPosition(): Boolean {
+ val state = playbackState?.state
+ val moving = if (state == null) false else
+ state == PlaybackState.STATE_PLAYING ||
+ state == PlaybackState.STATE_BUFFERING ||
+ state == PlaybackState.STATE_FAST_FORWARDING ||
+ state == PlaybackState.STATE_REWINDING
+ return moving && listening
+ }
+
+ /** Gets a listener to attach to the seek bar to handle seeking. */
+ val seekBarListener: SeekBar.OnSeekBarChangeListener
+ get() {
+ return SeekBarChangeListener(this, bgExecutor)
+ }
+
+ /** Gets a listener to attach to the seek bar to disable touch intercepting. */
+ val seekBarTouchListener: View.OnTouchListener
+ get() {
+ return SeekBarTouchListener()
+ }
+
+ private class SeekBarChangeListener(
+ val viewModel: SeekBarViewModel,
+ val bgExecutor: DelayableExecutor
+ ) : SeekBar.OnSeekBarChangeListener {
+ override fun onProgressChanged(bar: SeekBar, progress: Int, fromUser: Boolean) {
+ if (fromUser) {
+ bgExecutor.execute {
+ viewModel.onSeek(progress.toLong())
+ }
+ }
+ }
+ override fun onStartTrackingTouch(bar: SeekBar) {
+ }
+ override fun onStopTrackingTouch(bar: SeekBar) {
+ val pos = bar.progress.toLong()
+ bgExecutor.execute {
+ viewModel.onSeek(pos)
+ }
+ }
+ }
+
+ private class SeekBarTouchListener : View.OnTouchListener {
+ override fun onTouch(view: View, event: MotionEvent): Boolean {
+ view.parent.requestDisallowInterceptTouchEvent(true)
+ return view.onTouchEvent(event)
+ }
+ }
+
+ /** State seen by seek bar UI. */
+ data class Progress(
+ val enabled: Boolean,
+ val seekAvailable: Boolean,
+ val elapsedTime: Int?,
+ val duration: Int?,
+ val color: Int?
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 8922e146cc50..339a408d501a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -16,11 +16,14 @@
package com.android.systemui.qs;
+import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
+
import android.app.Notification;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.util.Log;
import android.view.View;
@@ -28,12 +31,16 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.SeekBar;
import android.widget.TextView;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.media.MediaControlPanel;
+import com.android.systemui.media.SeekBarObserver;
+import com.android.systemui.media.SeekBarViewModel;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.concurrent.Executor;
@@ -54,6 +61,9 @@ public class QSMediaPlayer extends MediaControlPanel {
};
private final QSPanel mParent;
+ private final DelayableExecutor mBackgroundExecutor;
+ private final SeekBarViewModel mSeekBarViewModel;
+ private final SeekBarObserver mSeekBarObserver;
/**
* Initialize quick shade version of player
@@ -64,10 +74,20 @@ public class QSMediaPlayer extends MediaControlPanel {
* @param backgroundExecutor
*/
public QSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager,
- Executor foregroundExecutor, Executor backgroundExecutor) {
+ Executor foregroundExecutor, DelayableExecutor backgroundExecutor) {
super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, foregroundExecutor,
backgroundExecutor);
mParent = (QSPanel) parent;
+ mBackgroundExecutor = backgroundExecutor;
+ mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor);
+ mSeekBarObserver = new SeekBarObserver(getView());
+ // Can't use the viewAttachLifecycle of media player because remove/add is used to adjust
+ // priority of players. As soon as it is removed, the lifecycle will end and the seek bar
+ // will stop updating. So, use the lifecycle of the parent instead.
+ mSeekBarViewModel.getProgress().observe(viewAttachLifecycle(parent), mSeekBarObserver);
+ SeekBar bar = getView().findViewById(R.id.media_progress_bar);
+ bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener());
+ bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener());
}
/**
@@ -115,6 +135,11 @@ public class QSMediaPlayer extends MediaControlPanel {
thisBtn.setVisibility(View.GONE);
}
+ // Seek Bar
+ final MediaController controller = new MediaController(getContext(), token);
+ mBackgroundExecutor.execute(
+ () -> mSeekBarViewModel.updateController(controller, iconColor));
+
// Set up long press menu
View guts = mMediaNotifView.findViewById(R.id.media_guts);
View options = mMediaNotifView.findViewById(R.id.qs_media_controls_options);
@@ -155,4 +180,16 @@ public class QSMediaPlayer extends MediaControlPanel {
return true; // consumed click
});
}
+
+ /**
+ * Sets the listening state of the player.
+ *
+ * Should be set to true when the QS panel is open. Otherwise, false. This is a signal to avoid
+ * unnecessary work when the QS panel is closed.
+ *
+ * @param listening True when player should be active. Otherwise, false.
+ */
+ public void setListening(boolean listening) {
+ mSeekBarViewModel.setListening(listening);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 33cc086a8d9f..c8412fffd143 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -69,6 +69,7 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -103,7 +104,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final NotificationMediaManager mNotificationMediaManager;
private final LocalBluetoothManager mLocalBluetoothManager;
private final Executor mForegroundExecutor;
- private final Executor mBackgroundExecutor;
+ private final DelayableExecutor mBackgroundExecutor;
private LocalMediaManager mLocalMediaManager;
private MediaDevice mDevice;
private boolean mUpdateCarousel = false;
@@ -166,7 +167,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
QSLogger qsLogger,
NotificationMediaManager notificationMediaManager,
@Main Executor foregroundExecutor,
- @Background Executor backgroundExecutor,
+ @Background DelayableExecutor backgroundExecutor,
@Nullable LocalBluetoothManager localBluetoothManager
) {
super(context, attrs);
@@ -278,7 +279,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
Log.d(TAG, "creating new player");
player = new QSMediaPlayer(mContext, this, mNotificationMediaManager,
mForegroundExecutor, mBackgroundExecutor);
-
+ player.setListening(mListening);
if (player.isPlaying()) {
mMediaCarousel.addView(player.getView(), 0, lp); // add in front
} else {
@@ -584,6 +585,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
if (mListening) {
refreshAllTiles();
}
+ for (QSMediaPlayer player : mMediaPlayers) {
+ player.setListening(mListening);
+ }
}
private String getTilesSpecs() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index be01d75552de..8fa64d3aaf0c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.Utils;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.ArrayList;
import java.util.Collection;
@@ -81,7 +82,7 @@ public class QuickQSPanel extends QSPanel {
QSLogger qsLogger,
NotificationMediaManager notificationMediaManager,
@Main Executor foregroundExecutor,
- @Background Executor backgroundExecutor,
+ @Background DelayableExecutor backgroundExecutor,
@Nullable LocalBluetoothManager localBluetoothManager
) {
super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, notificationMediaManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index fe2f1f3eefc5..1297f996b743 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -177,12 +177,32 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
currentUserId);
ent.setSensitive(sensitive, deviceSensitive);
ent.getRow().setNeedsRedaction(needsRedaction);
- if (mGroupManager.isChildInGroupWithSummary(ent.getSbn())) {
- NotificationEntry summary = mGroupManager.getGroupSummary(ent.getSbn());
- List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(summary);
+ boolean isChildInGroup = mGroupManager.isChildInGroupWithSummary(ent.getSbn());
+
+ boolean groupChangesAllowed = mVisualStabilityManager.areGroupChangesAllowed()
+ || !ent.hasFinishedInitialization();
+ NotificationEntry parent = mGroupManager.getGroupSummary(ent.getSbn());
+ if (!groupChangesAllowed) {
+ // We don't to change groups while the user is looking at them
+ boolean wasChildInGroup = ent.isChildInGroup();
+ if (isChildInGroup && !wasChildInGroup) {
+ isChildInGroup = wasChildInGroup;
+ mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
+ } else if (!isChildInGroup && wasChildInGroup) {
+ // We allow grouping changes if the group was collapsed
+ if (mGroupManager.isLogicalGroupExpanded(ent.getSbn())) {
+ isChildInGroup = wasChildInGroup;
+ parent = ent.getRow().getNotificationParent().getEntry();
+ mVisualStabilityManager.addGroupChangesAllowedCallback(mEntryManager);
+ }
+ }
+ }
+
+ if (isChildInGroup) {
+ List<NotificationEntry> orderedChildren = mTmpChildOrderMap.get(parent);
if (orderedChildren == null) {
orderedChildren = new ArrayList<>();
- mTmpChildOrderMap.put(summary, orderedChildren);
+ mTmpChildOrderMap.put(parent, orderedChildren);
}
orderedChildren.add(ent);
} else {
@@ -205,7 +225,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
}
for (ExpandableNotificationRow viewToRemove : viewsToRemove) {
- if (mGroupManager.isChildInGroupWithSummary(viewToRemove.getEntry().getSbn())) {
+ if (mEntryManager.getPendingOrActiveNotif(viewToRemove.getEntry().getKey()) != null) {
// we are only transferring this notification to its parent, don't generate an
// animation
mListContainer.setChildTransferInProgress(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 7ef1d0eba3f1..1696f0715865 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -26,6 +26,7 @@ import com.android.internal.widget.ConversationLayout
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.NotificationContentView
+import com.android.systemui.statusbar.phone.NotificationGroupManager
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
import javax.inject.Singleton
@@ -60,6 +61,7 @@ class ConversationNotificationProcessor @Inject constructor(
@Singleton
class ConversationNotificationManager @Inject constructor(
private val notificationEntryManager: NotificationEntryManager,
+ private val notificationGroupManager: NotificationGroupManager,
private val context: Context
) {
// Need this state to be thread safe, since it's accessed from the ui thread
@@ -81,10 +83,19 @@ class ConversationNotificationManager @Inject constructor(
if (rankingMap.getRanking(entry.sbn.key, ranking) &&
ranking.isConversation) {
val important = ranking.channel.isImportantConversation
+ var changed = false
entry.row?.layouts?.asSequence()
?.flatMap(::getLayouts)
?.mapNotNull { it as? ConversationLayout }
- ?.forEach { it.setIsImportantConversation(important) }
+ ?.forEach {
+ if (important != it.isImportantConversation) {
+ it.setIsImportantConversation(important)
+ changed = true
+ }
+ }
+ if (changed) {
+ notificationGroupManager.updateIsolation(entry)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 77376e595819..295adae9c9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -252,7 +252,7 @@ public class NotificationEntryManager implements
}
@Override
- public void onReorderingAllowed() {
+ public void onChangeAllowed() {
updateNotifications("reordering is now allowed");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index b357ada7bcf1..7ac59954cb57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -42,12 +42,14 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
private static final long TEMPORARY_REORDERING_ALLOWED_DURATION = 1000;
- private final ArrayList<Callback> mCallbacks = new ArrayList<>();
+ private final ArrayList<Callback> mReorderingAllowedCallbacks = new ArrayList<>();
+ private final ArrayList<Callback> mGroupChangesAllowedCallbacks = new ArrayList<>();
private final Handler mHandler;
private boolean mPanelExpanded;
private boolean mScreenOn;
private boolean mReorderingAllowed;
+ private boolean mGroupChangedAllowed;
private boolean mIsTemporaryReorderingAllowed;
private long mTemporaryReorderingStart;
private VisibilityLocationProvider mVisibilityLocationProvider;
@@ -83,13 +85,22 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
/**
* Add a callback to invoke when reordering is allowed again.
- * @param callback
*/
public void addReorderingAllowedCallback(Callback callback) {
- if (mCallbacks.contains(callback)) {
+ if (mReorderingAllowedCallbacks.contains(callback)) {
return;
}
- mCallbacks.add(callback);
+ mReorderingAllowedCallbacks.add(callback);
+ }
+
+ /**
+ * Add a callback to invoke when group changes are allowed again.
+ */
+ public void addGroupChangesAllowedCallback(Callback callback) {
+ if (mGroupChangesAllowedCallbacks.contains(callback)) {
+ return;
+ }
+ mGroupChangesAllowedCallbacks.add(callback);
}
/**
@@ -97,7 +108,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
*/
public void setPanelExpanded(boolean expanded) {
mPanelExpanded = expanded;
- updateReorderingAllowed();
+ updateAllowedStates();
}
/**
@@ -105,7 +116,7 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
*/
public void setScreenOn(boolean screenOn) {
mScreenOn = screenOn;
- updateReorderingAllowed();
+ updateAllowedStates();
}
/**
@@ -116,25 +127,30 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
return;
}
mPulsing = pulsing;
- updateReorderingAllowed();
+ updateAllowedStates();
}
- private void updateReorderingAllowed() {
+ private void updateAllowedStates() {
boolean reorderingAllowed =
(!mScreenOn || !mPanelExpanded || mIsTemporaryReorderingAllowed) && !mPulsing;
boolean changedToTrue = reorderingAllowed && !mReorderingAllowed;
mReorderingAllowed = reorderingAllowed;
if (changedToTrue) {
- notifyCallbacks();
+ notifyChangeAllowed(mReorderingAllowedCallbacks);
+ }
+ boolean groupChangesAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
+ changedToTrue = groupChangesAllowed && !mGroupChangedAllowed;
+ mGroupChangedAllowed = groupChangesAllowed;
+ if (changedToTrue) {
+ notifyChangeAllowed(mGroupChangesAllowedCallbacks);
}
}
- private void notifyCallbacks() {
- for (int i = 0; i < mCallbacks.size(); i++) {
- Callback callback = mCallbacks.get(i);
- callback.onReorderingAllowed();
+ private void notifyChangeAllowed(ArrayList<Callback> callbacks) {
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).onChangeAllowed();
}
- mCallbacks.clear();
+ callbacks.clear();
}
/**
@@ -145,6 +161,13 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
}
/**
+ * @return whether changes in the grouping should be allowed right now.
+ */
+ public boolean areGroupChangesAllowed() {
+ return mGroupChangedAllowed;
+ }
+
+ /**
* @return whether a specific notification is allowed to reorder. Certain notifications are
* allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added
* notifications or heads-up notifications that are out of view.
@@ -197,12 +220,12 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
mTemporaryReorderingStart = SystemClock.elapsedRealtime();
}
mIsTemporaryReorderingAllowed = true;
- updateReorderingAllowed();
+ updateAllowedStates();
}
private final Runnable mOnTemporaryReorderingExpired = () -> {
mIsTemporaryReorderingAllowed = false;
- updateReorderingAllowed();
+ updateAllowedStates();
};
/**
@@ -229,9 +252,9 @@ public class VisualStabilityManager implements OnHeadsUpChangedListener, Dumpabl
public interface Callback {
/**
- * Called when reordering is allowed again.
+ * Called when changing is allowed again.
*/
- void onReorderingAllowed();
+ void onChangeAllowed();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index d22564b2a811..dd7be2775209 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -136,7 +136,6 @@ public final class NotificationEntry extends ListEntry {
*/
public EditedSuggestionInfo editedSuggestionInfo;
- private NotificationEntry parent; // our parent (if we're in a group)
private ExpandableNotificationRow row; // the outer expanded view
private ExpandableNotificationRowController mRowController;
@@ -710,7 +709,7 @@ public final class NotificationEntry extends ListEntry {
}
public boolean isChildInGroup() {
- return parent == null;
+ return row != null && row.isChildInGroup();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
new file mode 100644
index 000000000000..1bac938a9fca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * A coordinator that elevates important conversation notifications
+ */
+@Singleton
+class ConversationCoordinator @Inject constructor() : Coordinator {
+
+ private val notificationPromoter = object : NotifPromoter(TAG) {
+ override fun shouldPromoteToTopLevel(entry: NotificationEntry): Boolean {
+ return entry.channel?.isImportantConversation == true
+ }
+ }
+
+ override fun attach(pipeline: NotifPipeline) {
+ pipeline.addPromoter(notificationPromoter)
+ }
+
+ companion object {
+ private const val TAG = "ConversationCoordinator"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 03c0ae6fde50..2b279bbd553a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -56,6 +56,7 @@ public class NotifCoordinators implements Dumpable {
DeviceProvisionedCoordinator deviceProvisionedCoordinator,
BubbleCoordinator bubbleCoordinator,
HeadsUpCoordinator headsUpCoordinator,
+ ConversationCoordinator conversationCoordinator,
PreparationCoordinator preparationCoordinator) {
dumpManager.registerDumpable(TAG, this);
mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
@@ -66,6 +67,7 @@ public class NotifCoordinators implements Dumpable {
mCoordinators.add(deviceProvisionedCoordinator);
mCoordinators.add(bubbleCoordinator);
if (featureFlags.isNewNotifPipelineRenderingEnabled()) {
+ mCoordinators.add(conversationCoordinator);
mCoordinators.add(headsUpCoordinator);
mCoordinators.add(preparationCoordinator);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index be3873a5fd77..88cca43fd1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -96,7 +96,7 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
return TYPE_NON_PERSON
}
- val childTypes = groupManager.getLogicalChildren(statusBarNotification)
+ val childTypes = groupManager.getChildren(statusBarNotification)
?.asSequence()
?.map { getPeopleNotificationType(it.sbn, it.ranking) }
?: return TYPE_NON_PERSON
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 8e2bfb84e2dd..6fc1264d69e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -20,7 +20,6 @@ import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS;
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
@@ -44,7 +43,6 @@ import android.os.Handler;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.transition.ChangeBounds;
@@ -56,15 +54,12 @@ import android.util.Log;
import android.util.Slog;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import android.widget.Button;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.notification.ConversationIconFactory;
-import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
@@ -517,7 +512,6 @@ public class NotificationConversationInfo extends LinearLayout implements
bgHandler.post(
new UpdateChannelRunnable(mINotificationManager, mPackageName,
mAppUid, mSelectedAction, mNotificationChannel));
- mVisualStabilityManager.temporarilyAllowReordering();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 63fe7005e703..6b0df95f54dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -337,7 +337,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
// VisualStabilityManager.Callback overrides:
@Override
- public void onReorderingAllowed() {
+ public void onChangeAllowed() {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
for (NotificationEntry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (isAlerting(entry.getKey())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index ccf670708e44..84dd48b6eb6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.annotation.Nullable;
+import android.app.NotificationChannel;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
@@ -85,6 +86,17 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return group.expanded;
}
+ /**
+ * @return if the group that this notification is associated with logically is expanded
+ */
+ public boolean isLogicalGroupExpanded(StatusBarNotification sbn) {
+ NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+ if (group == null) {
+ return false;
+ }
+ return group.expanded;
+ }
+
public void setGroupExpanded(StatusBarNotification sbn, boolean expanded) {
NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
if (group == null) {
@@ -147,7 +159,15 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
}
+ /**
+ * Notify the group manager that a new entry was added
+ */
public void onEntryAdded(final NotificationEntry added) {
+ updateIsolation(added);
+ onEntryAddedInternal(added);
+ }
+
+ private void onEntryAddedInternal(final NotificationEntry added) {
if (added.isRowRemoved()) {
added.setDebugThrowable(new Throwable());
}
@@ -193,9 +213,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
private void onEntryBecomingChild(NotificationEntry entry) {
- if (shouldIsolate(entry)) {
- isolateNotification(entry);
- }
+ updateIsolation(entry);
}
private void updateSuppression(NotificationGroup group) {
@@ -242,15 +260,6 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return count;
}
- private NotificationEntry getIsolatedChild(String groupKey) {
- for (StatusBarNotification sbn : mIsolatedEntries.values()) {
- if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn.getKey())) {
- return mGroupMap.get(sbn.getKey()).summary;
- }
- }
- return null;
- }
-
/**
* Update an entry's group information
* @param entry notification entry to update
@@ -278,7 +287,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
if (mGroupMap.get(getGroupKey(entry.getKey(), oldGroupKey)) != null) {
onEntryRemovedInternal(entry, oldGroupKey, oldIsGroup, oldIsGroupSummary);
}
- onEntryAdded(entry);
+ onEntryAddedInternal(entry);
mIsUpdatingUnchangedGroup = false;
if (isIsolated(entry.getSbn().getKey())) {
mIsolatedEntries.put(entry.getKey(), entry.getSbn());
@@ -413,14 +422,29 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
return null;
}
ArrayList<NotificationEntry> children = new ArrayList<>(group.children.values());
- NotificationEntry isolatedChild = getIsolatedChild(summary.getGroupKey());
- if (isolatedChild != null) {
- children.add(isolatedChild);
+ for (StatusBarNotification sbn : mIsolatedEntries.values()) {
+ if (sbn.getGroupKey().equals(summary.getGroupKey())) {
+ children.add(mGroupMap.get(sbn.getKey()).summary);
+ }
}
return children;
}
/**
+ * Get the children that are in the summary's group, not including those isolated.
+ *
+ * @param summary summary of a group
+ * @return list of the children
+ */
+ public @Nullable ArrayList<NotificationEntry> getChildren(StatusBarNotification summary) {
+ NotificationGroup group = mGroupMap.get(summary.getGroupKey());
+ if (group == null) {
+ return null;
+ }
+ return new ArrayList<>(group.children.values());
+ }
+
+ /**
* If there is a {@link NotificationGroup} associated with the provided entry, this method
* will update the suppression of that group.
*/
@@ -495,17 +519,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- onAlertStateChanged(entry, isHeadsUp);
- }
-
- private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting) {
- if (isAlerting) {
- if (shouldIsolate(entry)) {
- isolateNotification(entry);
- }
- } else {
- stopIsolatingNotification(entry);
- }
+ updateIsolation(entry);
}
/**
@@ -519,13 +533,17 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
private boolean shouldIsolate(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
return false;
}
+ NotificationChannel channel = entry.getChannel();
+ if (channel != null && channel.isImportantConversation()) {
+ return true;
+ }
if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) {
return false;
}
+ NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
return (sbn.getNotification().fullScreenIntent != null
|| notificationGroup == null
|| !notificationGroup.expanded
@@ -545,7 +563,7 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
mIsolatedEntries.put(sbn.getKey(), sbn);
- onEntryAdded(entry);
+ onEntryAddedInternal(entry);
// We also need to update the suppression of the old group, because this call comes
// even before the groupManager knows about the notification at all.
// When the notification gets added afterwards it is already isolated and therefore
@@ -557,17 +575,31 @@ public class NotificationGroupManager implements OnHeadsUpChangedListener, State
}
/**
+ * Update the isolation of an entry, splitting it from the group.
+ */
+ public void updateIsolation(NotificationEntry entry) {
+ boolean isIsolated = isIsolated(entry.getSbn().getKey());
+ if (shouldIsolate(entry)) {
+ if (!isIsolated) {
+ isolateNotification(entry);
+ }
+ } else if (isIsolated) {
+ stopIsolatingNotification(entry);
+ }
+ }
+
+ /**
* Stop isolating a notification and re-group it with its original logical group.
*
* @param entry the notification to un-isolate
*/
private void stopIsolatingNotification(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- if (mIsolatedEntries.containsKey(sbn.getKey())) {
+ if (isIsolated(sbn.getKey())) {
// not isolated anymore, we need to update the groups
onEntryRemovedInternal(entry, entry.getSbn());
mIsolatedEntries.remove(sbn.getKey());
- onEntryAdded(entry);
+ onEntryAddedInternal(entry);
for (OnGroupChangeListener listener : mListeners) {
listener.onGroupsChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java b/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java
index 711a0dfe1931..d73175310802 100644
--- a/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java
+++ b/packages/SystemUI/src/com/android/systemui/util/SysuiLifecycle.java
@@ -48,6 +48,9 @@ public class SysuiLifecycle {
ViewLifecycle(View v) {
v.addOnAttachStateChangeListener(this);
+ if (v.isAttachedToWindow()) {
+ mLifecycle.markState(RESUMED);
+ }
}
@NonNull
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
new file mode 100644
index 000000000000..137a126f539d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.systemui.globalactions;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.content.ContentResolver;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.net.ConnectivityManager;
+import android.os.UserManager;
+import android.service.dreams.IDreamManager;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.IWindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.controls.controller.ControlsController;
+import com.android.systemui.controls.management.ControlsListingController;
+import com.android.systemui.controls.ui.ControlsUiController;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
+import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class GlobalActionsDialogTest extends SysuiTestCase {
+ private GlobalActionsDialog mGlobalActionsDialog;
+
+ @Mock private GlobalActions.GlobalActionsManager mWindowManagerFuncs;
+ @Mock private AudioManager mAudioManager;
+ @Mock private IDreamManager mDreamManager;
+ @Mock private DevicePolicyManager mDevicePolicyManager;
+ @Mock private LockPatternUtils mLockPatternUtils;
+ @Mock private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock private ConnectivityManager mConnectivityManager;
+ @Mock private TelephonyManager mTelephonyManager;
+ @Mock private ContentResolver mContentResolver;
+ @Mock private Resources mResources;
+ @Mock private ConfigurationController mConfigurationController;
+ @Mock private ActivityStarter mActivityStarter;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private UserManager mUserManager;
+ @Mock private TrustManager mTrustManager;
+ @Mock private IActivityManager mActivityManager;
+ @Mock private MetricsLogger mMetricsLogger;
+ @Mock private NotificationShadeDepthController mDepthController;
+ @Mock private SysuiColorExtractor mColorExtractor;
+ @Mock private IStatusBarService mStatusBarService;
+ @Mock private BlurUtils mBlurUtils;
+ @Mock private NotificationShadeWindowController mNotificationShadeWindowController;
+ @Mock private ControlsUiController mControlsUiController;
+ @Mock private IWindowManager mWindowManager;
+ @Mock private Executor mBackgroundExecutor;
+ @Mock private ControlsListingController mControlsListingController;
+ @Mock private ControlsController mControlsController;
+ @Mock private UiEventLogger mUiEventLogger;
+
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+ allowTestableLooperAsMainThread();
+ mGlobalActionsDialog = new GlobalActionsDialog(mContext,
+ mWindowManagerFuncs,
+ mAudioManager,
+ mDreamManager,
+ mDevicePolicyManager,
+ mLockPatternUtils,
+ mBroadcastDispatcher,
+ mConnectivityManager,
+ mTelephonyManager,
+ mContentResolver,
+ null,
+ mResources,
+ mConfigurationController,
+ mActivityStarter,
+ mKeyguardStateController,
+ mUserManager,
+ mTrustManager,
+ mActivityManager,
+ null,
+ mMetricsLogger,
+ mDepthController,
+ mColorExtractor,
+ mStatusBarService,
+ mBlurUtils,
+ mNotificationShadeWindowController,
+ mControlsUiController,
+ mWindowManager,
+ mBackgroundExecutor,
+ mControlsListingController,
+ mControlsController,
+ mUiEventLogger
+ );
+ }
+ @Test
+ public void testShouldLogVisibility() {
+ mGlobalActionsDialog.onShow(null);
+ verify(mUiEventLogger, times(1))
+ .log(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
new file mode 100644
index 000000000000..260f52070a70
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -0,0 +1,130 @@
+/*
+ * 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.systemui.media
+
+import android.graphics.Color
+import android.content.res.ColorStateList
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.widget.SeekBar
+import android.widget.TextView
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+public class SeekBarObserverTest : SysuiTestCase() {
+
+ private lateinit var observer: SeekBarObserver
+ @Mock private lateinit var mockView: View
+ private lateinit var seekBarView: SeekBar
+ private lateinit var elapsedTimeView: TextView
+ private lateinit var totalTimeView: TextView
+
+ @Before
+ fun setUp() {
+ mockView = mock(View::class.java)
+ seekBarView = SeekBar(context)
+ elapsedTimeView = TextView(context)
+ totalTimeView = TextView(context)
+ whenever<SeekBar>(
+ mockView.findViewById(R.id.media_progress_bar)).thenReturn(seekBarView)
+ whenever<TextView>(
+ mockView.findViewById(R.id.media_elapsed_time)).thenReturn(elapsedTimeView)
+ whenever<TextView>(mockView.findViewById(R.id.media_total_time)).thenReturn(totalTimeView)
+ observer = SeekBarObserver(mockView)
+ }
+
+ @Test
+ fun seekBarGone() {
+ // WHEN seek bar is disabled
+ val isEnabled = false
+ val data = SeekBarViewModel.Progress(isEnabled, false, null, null, null)
+ observer.onChanged(data)
+ // THEN seek bar visibility is set to GONE
+ assertThat(seekBarView.getVisibility()).isEqualTo(View.GONE)
+ assertThat(elapsedTimeView.getVisibility()).isEqualTo(View.GONE)
+ assertThat(totalTimeView.getVisibility()).isEqualTo(View.GONE)
+ }
+
+ @Test
+ fun seekBarVisible() {
+ // WHEN seek bar is enabled
+ val isEnabled = true
+ val data = SeekBarViewModel.Progress(isEnabled, true, 3000, 12000, -1)
+ observer.onChanged(data)
+ // THEN seek bar is visible
+ assertThat(seekBarView.getVisibility()).isEqualTo(View.VISIBLE)
+ assertThat(elapsedTimeView.getVisibility()).isEqualTo(View.VISIBLE)
+ assertThat(totalTimeView.getVisibility()).isEqualTo(View.VISIBLE)
+ }
+
+ @Test
+ fun seekBarProgress() {
+ // WHEN seek bar progress is about half
+ val data = SeekBarViewModel.Progress(true, true, 3000, 120000, -1)
+ observer.onChanged(data)
+ // THEN seek bar is visible
+ assertThat(seekBarView.progress).isEqualTo(100)
+ assertThat(seekBarView.max).isEqualTo(120000)
+ assertThat(elapsedTimeView.getText()).isEqualTo("00:03")
+ assertThat(totalTimeView.getText()).isEqualTo("02:00")
+ }
+
+ @Test
+ fun seekBarDisabledWhenSeekNotAvailable() {
+ // WHEN seek is not available
+ val isSeekAvailable = false
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000, -1)
+ observer.onChanged(data)
+ // THEN seek bar is not enabled
+ assertThat(seekBarView.isEnabled()).isFalse()
+ }
+
+ @Test
+ fun seekBarEnabledWhenSeekNotAvailable() {
+ // WHEN seek is available
+ val isSeekAvailable = true
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000, -1)
+ observer.onChanged(data)
+ // THEN seek bar is not enabled
+ assertThat(seekBarView.isEnabled()).isTrue()
+ }
+
+ @Test
+ fun seekBarColor() {
+ // WHEN data included color
+ val data = SeekBarViewModel.Progress(true, true, 3000, 120000, Color.RED)
+ observer.onChanged(data)
+ // THEN seek bar is colored
+ val red = ColorStateList.valueOf(Color.RED)
+ assertThat(elapsedTimeView.getTextColors()).isEqualTo(red)
+ assertThat(totalTimeView.getTextColors()).isEqualTo(red)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
new file mode 100644
index 000000000000..f316d0480fac
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -0,0 +1,375 @@
+/*
+ * 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.systemui.media
+
+import android.graphics.Color
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.PlaybackState
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.widget.SeekBar
+import androidx.arch.core.executor.ArchTaskExecutor
+import androidx.arch.core.executor.TaskExecutor
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+public class SeekBarViewModelTest : SysuiTestCase() {
+
+ private lateinit var viewModel: SeekBarViewModel
+ private lateinit var fakeExecutor: FakeExecutor
+ private val taskExecutor: TaskExecutor = object : TaskExecutor() {
+ override fun executeOnDiskIO(runnable: Runnable) {
+ runnable.run()
+ }
+ override fun postToMainThread(runnable: Runnable) {
+ runnable.run()
+ }
+ override fun isMainThread(): Boolean {
+ return true
+ }
+ }
+ @Mock private lateinit var mockController: MediaController
+ @Mock private lateinit var mockTransport: MediaController.TransportControls
+
+ @Before
+ fun setUp() {
+ fakeExecutor = FakeExecutor(FakeSystemClock())
+ viewModel = SeekBarViewModel(fakeExecutor)
+ mockController = mock(MediaController::class.java)
+ mockTransport = mock(MediaController.TransportControls::class.java)
+
+ // LiveData to run synchronously
+ ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
+ }
+
+ @After
+ fun tearDown() {
+ ArchTaskExecutor.getInstance().setDelegate(null)
+ }
+
+ @Test
+ fun updateColor() {
+ viewModel.updateController(mockController, Color.RED)
+ assertThat(viewModel.progress.value!!.color).isEqualTo(Color.RED)
+ }
+
+ @Test
+ fun updateDuration() {
+ // GIVEN that the duration is contained within the metadata
+ val duration = 12000L
+ val metadata = MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
+ whenever(mockController.getMetadata()).thenReturn(metadata)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN the duration is extracted
+ assertThat(viewModel.progress.value!!.duration).isEqualTo(duration)
+ assertThat(viewModel.progress.value!!.enabled).isTrue()
+ }
+
+ @Test
+ fun updateDurationNegative() {
+ // GIVEN that the duration is negative
+ val duration = -1L
+ val metadata = MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
+ whenever(mockController.getMetadata()).thenReturn(metadata)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN the seek bar is disabled
+ assertThat(viewModel.progress.value!!.enabled).isFalse()
+ }
+
+ @Test
+ fun updateDurationZero() {
+ // GIVEN that the duration is zero
+ val duration = 0L
+ val metadata = MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
+ whenever(mockController.getMetadata()).thenReturn(metadata)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN the seek bar is disabled
+ assertThat(viewModel.progress.value!!.enabled).isFalse()
+ }
+
+ @Test
+ fun updateElapsedTime() {
+ // GIVEN that the PlaybackState contins the current position
+ val position = 200L
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, position, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN elapsed time is captured
+ assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(200.toInt())
+ }
+
+ @Test
+ fun updateSeekAvailable() {
+ // GIVEN that seek is included in actions
+ val state = PlaybackState.Builder().run {
+ setActions(PlaybackState.ACTION_SEEK_TO)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN seek is available
+ assertThat(viewModel.progress.value!!.seekAvailable).isTrue()
+ }
+
+ @Test
+ fun updateSeekNotAvailable() {
+ // GIVEN that seek is not included in actions
+ val state = PlaybackState.Builder().run {
+ setActions(PlaybackState.ACTION_PLAY)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN seek is not available
+ assertThat(viewModel.progress.value!!.seekAvailable).isFalse()
+ }
+
+ @Test
+ fun handleSeek() {
+ whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN user input is dispatched
+ val pos = 42L
+ viewModel.onSeek(pos)
+ fakeExecutor.runAllReady()
+ // THEN transport controls should be used
+ verify(mockTransport).seekTo(pos)
+ }
+
+ @Test
+ fun handleProgressChangedUser() {
+ whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN user starts dragging the seek bar
+ val pos = 42
+ viewModel.seekBarListener.onProgressChanged(SeekBar(context), pos, true)
+ fakeExecutor.runAllReady()
+ // THEN transport controls should be used
+ verify(mockTransport).seekTo(pos.toLong())
+ }
+
+ @Test
+ fun handleProgressChangedOther() {
+ whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN user starts dragging the seek bar
+ val pos = 42
+ viewModel.seekBarListener.onProgressChanged(SeekBar(context), pos, false)
+ fakeExecutor.runAllReady()
+ // THEN transport controls should be used
+ verify(mockTransport, never()).seekTo(pos.toLong())
+ }
+
+ @Test
+ fun handleStartTrackingTouch() {
+ whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN user starts dragging the seek bar
+ val pos = 42
+ val bar = SeekBar(context).apply {
+ progress = pos
+ }
+ viewModel.seekBarListener.onStartTrackingTouch(bar)
+ fakeExecutor.runAllReady()
+ // THEN transport controls should be used
+ verify(mockTransport, never()).seekTo(pos.toLong())
+ }
+
+ @Test
+ fun handleStopTrackingTouch() {
+ whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN user ends drag
+ val pos = 42
+ val bar = SeekBar(context).apply {
+ progress = pos
+ }
+ viewModel.seekBarListener.onStopTrackingTouch(bar)
+ fakeExecutor.runAllReady()
+ // THEN transport controls should be used
+ verify(mockTransport).seekTo(pos.toLong())
+ }
+
+ @Test
+ fun queuePollTaskWhenPlaying() {
+ // GIVEN that the track is playing
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 100L, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN the controller is updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN a task is queued
+ assertThat(fakeExecutor.numPending()).isEqualTo(1)
+ }
+
+ @Test
+ fun noQueuePollTaskWhenStopped() {
+ // GIVEN that the playback state is stopped
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_STOPPED, 200L, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN an update task is not queued
+ assertThat(fakeExecutor.numPending()).isEqualTo(0)
+ }
+
+ @Test
+ fun queuePollTaskWhenListening() {
+ // GIVEN listening
+ viewModel.listening = true
+ with(fakeExecutor) {
+ advanceClockToNext()
+ runAllReady()
+ }
+ // AND the playback state is playing
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN an update task is queued
+ assertThat(fakeExecutor.numPending()).isEqualTo(1)
+ }
+
+ @Test
+ fun noQueuePollTaskWhenNotListening() {
+ // GIVEN not listening
+ viewModel.listening = false
+ with(fakeExecutor) {
+ advanceClockToNext()
+ runAllReady()
+ }
+ // AND the playback state is playing
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_STOPPED, 200L, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ // WHEN updated
+ viewModel.updateController(mockController, Color.RED)
+ // THEN an update task is not queued
+ assertThat(fakeExecutor.numPending()).isEqualTo(0)
+ }
+
+ @Test
+ fun pollTaskQueuesAnotherPollTaskWhenPlaying() {
+ // GIVEN that the track is playing
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 100L, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN the next task runs
+ with(fakeExecutor) {
+ advanceClockToNext()
+ runAllReady()
+ }
+ // THEN another task is queued
+ assertThat(fakeExecutor.numPending()).isEqualTo(1)
+ }
+
+ @Test
+ fun taskUpdatesProgress() {
+ // GIVEN that the PlaybackState contins the current position
+ val position = 200L
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, position, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ viewModel.updateController(mockController, Color.RED)
+ // AND the playback state advances
+ val nextPosition = 300L
+ val nextState = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, nextPosition, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(nextState)
+ // WHEN the task runs
+ with(fakeExecutor) {
+ advanceClockToNext()
+ runAllReady()
+ }
+ // THEN elapsed time is captured
+ assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(nextPosition.toInt())
+ }
+
+ @Test
+ fun startListeningQueuesPollTask() {
+ // GIVEN not listening
+ viewModel.listening = false
+ with(fakeExecutor) {
+ advanceClockToNext()
+ runAllReady()
+ }
+ // AND the playback state is playing
+ val state = PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_STOPPED, 200L, 1f)
+ build()
+ }
+ whenever(mockController.getPlaybackState()).thenReturn(state)
+ viewModel.updateController(mockController, Color.RED)
+ // WHEN start listening
+ viewModel.listening = true
+ // THEN an update task is queued
+ assertThat(fakeExecutor.numPending()).isEqualTo(1)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index dbbbaac66554..862ebe13bd93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -44,6 +44,7 @@ import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import org.junit.Before;
import org.junit.Test;
@@ -87,7 +88,7 @@ public class QSPanelTest extends SysuiTestCase {
@Mock
private Executor mForegroundExecutor;
@Mock
- private Executor mBackgroundExecutor;
+ private DelayableExecutor mBackgroundExecutor;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index ea68516e639c..e55ea41d94e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -98,6 +98,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mLockscreenUserManager);
mDependency.injectTestDependency(NotificationGroupManager.class, mGroupManager);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
+ when(mVisualStabilityManager.areGroupChangesAllowed()).thenReturn(true);
+ when(mVisualStabilityManager.isReorderingAllowed()).thenReturn(true);
mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
index 9079223649ff..3d06c57cac37 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/VisualStabilityManagerTest.java
@@ -110,7 +110,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
mVisualStabilityManager.setScreenOn(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -119,7 +119,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
mVisualStabilityManager.setPanelExpanded(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -130,7 +130,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setScreenOn(false);
mVisualStabilityManager.setScreenOn(true);
mVisualStabilityManager.setScreenOn(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -190,7 +190,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.setPulsing(true);
mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
mVisualStabilityManager.setPulsing(false);
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
}
@Test
@@ -204,7 +204,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.temporarilyAllowReordering();
// THEN callbacks are notified that reordering is allowed
- verify(mCallback).onReorderingAllowed();
+ verify(mCallback).onChangeAllowed();
assertTrue(mVisualStabilityManager.isReorderingAllowed());
}
@@ -218,7 +218,7 @@ public class VisualStabilityManagerTest extends SysuiTestCase {
mVisualStabilityManager.temporarilyAllowReordering();
// THEN reordering is still not allowed
- verify(mCallback, never()).onReorderingAllowed();
+ verify(mCallback, never()).onChangeAllowed();
assertFalse(mVisualStabilityManager.isReorderingAllowed());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
new file mode 100644
index 000000000000..dfc627e14d8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.systemui.statusbar.notification.collection.coordinator
+
+import android.app.NotificationChannel
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ConversationCoordinatorTest : SysuiTestCase() {
+
+ private var coordinator: ConversationCoordinator = ConversationCoordinator()
+
+ // captured listeners and pluggables:
+ private var promoter: NotifPromoter? = null
+
+ @Mock
+ private val pipeline: NotifPipeline? = null
+ @Mock
+ private val channel: NotificationChannel? = null
+ private var entry: NotificationEntry? = null
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(channel!!.isImportantConversation).thenReturn(true)
+
+ coordinator.attach(pipeline!!)
+
+ // capture arguments:
+ val notifPromoterCaptor = ArgumentCaptor.forClass(NotifPromoter::class.java)
+ verify(pipeline).addPromoter(notifPromoterCaptor.capture())
+ promoter = notifPromoterCaptor.value
+
+ entry = NotificationEntryBuilder().setChannel(channel).build()
+ }
+
+ @Test
+ fun testPromotesCurrentHUN() {
+
+ // only promote important conversations
+ assertTrue(promoter!!.shouldPromoteToTopLevel(entry))
+ assertFalse(promoter!!.shouldPromoteToTopLevel(NotificationEntryBuilder().build()))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 6998edda3127..b6bd5e213dd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -816,29 +816,4 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
}
-
- @Test
- public void testAdjustImportanceTemporarilyAllowsReordering() {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mConversationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(
- mShortcutManager,
- mMockPackageManager,
- mMockINotificationManager,
- mVisualStabilityManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mEntry,
- null,
- null,
- mIconFactory,
- true);
-
- mNotificationInfo.findViewById(R.id.silence).performClick();
- mNotificationInfo.findViewById(R.id.done).performClick();
-
- mTestableLooper.processAllMessages();
-
- verify(mVisualStabilityManager).temporarilyAllowReordering();
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
index ce8085aa4862..486939d1f08e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
@@ -25,6 +25,8 @@ import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import static com.android.systemui.util.SysuiLifecycle.viewAttachLifecycle;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -35,12 +37,15 @@ import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
import android.view.View;
+import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,39 +54,122 @@ import org.junit.runner.RunWith;
@SmallTest
public class SysuiLifecycleTest extends SysuiTestCase {
+ private View mView;
+
+ @Before
+ public void setUp() {
+ mView = new View(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ if (mView.isAttachedToWindow()) {
+ ViewUtils.detachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ }
+ }
+
@Test
public void testAttach() {
- View v = new View(mContext);
LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
- LifecycleOwner lifecycle = viewAttachLifecycle(v);
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
lifecycle.getLifecycle().addObserver(observer);
- ViewUtils.attachView(v);
+ ViewUtils.attachView(mView);
TestableLooper.get(this).processAllMessages();
verify(observer).onStateChanged(eq(lifecycle), eq(ON_CREATE));
verify(observer).onStateChanged(eq(lifecycle), eq(ON_START));
verify(observer).onStateChanged(eq(lifecycle), eq(ON_RESUME));
-
- ViewUtils.detachView(v);
- TestableLooper.get(this).processAllMessages();
}
@Test
public void testDetach() {
- View v = new View(mContext);
LifecycleEventObserver observer = mock(LifecycleEventObserver.class);
- LifecycleOwner lifecycle = viewAttachLifecycle(v);
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
lifecycle.getLifecycle().addObserver(observer);
- ViewUtils.attachView(v);
+ ViewUtils.attachView(mView);
TestableLooper.get(this).processAllMessages();
- ViewUtils.detachView(v);
+ ViewUtils.detachView(mView);
TestableLooper.get(this).processAllMessages();
verify(observer).onStateChanged(eq(lifecycle), eq(ON_PAUSE));
verify(observer).onStateChanged(eq(lifecycle), eq(ON_STOP));
verify(observer).onStateChanged(eq(lifecycle), eq(ON_DESTROY));
}
+
+ @Test
+ public void testStateBeforeAttach() {
+ // WHEN a lifecycle is obtained from a view
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
+ // THEN the lifecycle state should be INITIAZED
+ assertThat(lifecycle.getLifecycle().getCurrentState()).isEqualTo(
+ Lifecycle.State.INITIALIZED);
+ }
+
+ @Test
+ public void testStateAfterAttach() {
+ // WHEN a lifecycle is obtained from a view
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
+ // AND the view is attached
+ ViewUtils.attachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ // THEN the lifecycle state should be RESUMED
+ assertThat(lifecycle.getLifecycle().getCurrentState()).isEqualTo(Lifecycle.State.RESUMED);
+ }
+
+ @Test
+ public void testStateAfterDetach() {
+ // WHEN a lifecycle is obtained from a view
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
+ // AND the view is detached
+ ViewUtils.attachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ ViewUtils.detachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ // THEN the lifecycle state should be DESTROYED
+ assertThat(lifecycle.getLifecycle().getCurrentState()).isEqualTo(Lifecycle.State.DESTROYED);
+ }
+
+ @Test
+ public void testStateAfterReattach() {
+ // WHEN a lifecycle is obtained from a view
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
+ // AND the view is re-attached
+ ViewUtils.attachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ ViewUtils.detachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ ViewUtils.attachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ // THEN the lifecycle state should still be DESTROYED, err RESUMED?
+ assertThat(lifecycle.getLifecycle().getCurrentState()).isEqualTo(Lifecycle.State.RESUMED);
+ }
+
+ @Test
+ public void testStateWhenViewAlreadyAttached() {
+ // GIVEN that a view is already attached
+ ViewUtils.attachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ // WHEN a lifecycle is obtained from a view
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
+ // THEN the lifecycle state should be RESUMED
+ assertThat(lifecycle.getLifecycle().getCurrentState()).isEqualTo(Lifecycle.State.RESUMED);
+ }
+
+ @Test
+ public void testStateWhenViewAlreadyDetached() {
+ // GIVEN that a view is already detached
+ ViewUtils.attachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ ViewUtils.detachView(mView);
+ TestableLooper.get(this).processAllMessages();
+ // WHEN a lifecycle is obtained from a view
+ LifecycleOwner lifecycle = viewAttachLifecycle(mView);
+ // THEN the lifecycle state should be INITIALIZED
+ assertThat(lifecycle.getLifecycle().getCurrentState()).isEqualTo(
+ Lifecycle.State.INITIALIZED);
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4ab035e7f44f..2eaa766ad32d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6313,7 +6313,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
&& !nai.networkAgentConfig.allowBypass
&& nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
- && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
+ && (lp.hasIPv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
+ && (lp.hasIPv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
}
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e8d8ed7a462d..ed3b9f1fc265 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6227,7 +6227,7 @@ public class NotificationManagerService extends SystemService {
cancelNotificationLocked(
r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
- mSendDelete, childrenFlagChecker);
+ mSendDelete, childrenFlagChecker, mReason);
updateLightsLocked();
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
@@ -6687,7 +6687,7 @@ public class NotificationManagerService extends SystemService {
// notification was a summary and its group key changed.
if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
- null);
+ null, REASON_APP_CANCEL);
}
}
@@ -7892,7 +7892,7 @@ public class NotificationManagerService extends SystemService {
final int M = canceledNotifications.size();
for (int i = 0; i < M; i++) {
cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
- listenerName, false /* sendDelete */, flagChecker);
+ listenerName, false /* sendDelete */, flagChecker, reason);
}
updateLightsLocked();
}
@@ -7963,7 +7963,7 @@ public class NotificationManagerService extends SystemService {
// Warning: The caller is responsible for invoking updateLightsLocked().
@GuardedBy("mNotificationLock")
private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
- String listenerName, boolean sendDelete, FlagChecker flagChecker) {
+ String listenerName, boolean sendDelete, FlagChecker flagChecker, int reason) {
Notification n = r.getNotification();
if (!n.isGroupSummary()) {
return;
@@ -7977,30 +7977,33 @@ public class NotificationManagerService extends SystemService {
}
cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
- sendDelete, true, flagChecker);
+ sendDelete, true, flagChecker, reason);
cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
- listenerName, sendDelete, false, flagChecker);
+ listenerName, sendDelete, false, flagChecker, reason);
}
@GuardedBy("mNotificationLock")
private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
NotificationRecord parentNotification, int callingUid, int callingPid,
- String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
+ String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker,
+ int reason) {
final String pkg = parentNotification.getSbn().getPackageName();
final int userId = parentNotification.getUserId();
- final int reason = REASON_GROUP_SUMMARY_CANCELED;
+ final int childReason = REASON_GROUP_SUMMARY_CANCELED;
for (int i = notificationList.size() - 1; i >= 0; i--) {
final NotificationRecord childR = notificationList.get(i);
final StatusBarNotification childSbn = childR.getSbn();
if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
childR.getGroupKey().equals(parentNotification.getGroupKey())
&& (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
- && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
+ && (flagChecker == null || flagChecker.apply(childR.getFlags()))
+ && (!childR.getChannel().isImportantConversation()
+ || reason != REASON_CANCEL)) {
EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
- childSbn.getTag(), userId, 0, 0, reason, listenerName);
+ childSbn.getTag(), userId, 0, 0, childReason, listenerName);
notificationList.remove(i);
mNotificationsByKey.remove(childR.getKey());
- cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
+ cancelNotificationLocked(childR, sendDelete, childReason, wasPosted, listenerName);
}
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 1b271a739777..1d5c30438870 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -47,6 +47,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutQueryWrapper;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
import android.content.pm.UserInfo;
@@ -698,13 +699,19 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public ParceledListSlice getShortcuts(String callingPackage, long changedSince,
- String packageName, List shortcutIds, List<LocusId> locusIds,
- ComponentName componentName, int flags, UserHandle targetUser) {
+ public ParceledListSlice getShortcuts(@NonNull final String callingPackage,
+ @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser) {
ensureShortcutPermission(callingPackage);
if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) {
return new ParceledListSlice<>(Collections.EMPTY_LIST);
}
+
+ final long changedSince = query.getChangedSince();
+ final String packageName = query.getPackage();
+ final List<String> shortcutIds = query.getShortcutIds();
+ final List<LocusId> locusIds = query.getLocusIds();
+ final ComponentName componentName = query.getActivity();
+ final int flags = query.getQueryFlags();
if (shortcutIds != null && packageName == null) {
throw new IllegalArgumentException(
"To query by shortcut ID, package name must also be set");
@@ -723,16 +730,17 @@ public class LauncherAppsService extends SystemService {
}
@Override
- public void registerShortcutChangeCallback(String callingPackage, long changedSince,
- String packageName, List shortcutIds, List<LocusId> locusIds,
- ComponentName componentName, int flags, IShortcutChangeCallback callback) {
+ public void registerShortcutChangeCallback(@NonNull final String callingPackage,
+ @NonNull final ShortcutQueryWrapper query,
+ @NonNull final IShortcutChangeCallback callback) {
+
ensureShortcutPermission(callingPackage);
- if (shortcutIds != null && packageName == null) {
+ if (query.getShortcutIds() != null && query.getPackage() == null) {
throw new IllegalArgumentException(
"To query by shortcut ID, package name must also be set");
}
- if (locusIds != null && packageName == null) {
+ if (query.getLocusIds() != null && query.getPackage() == null) {
throw new IllegalArgumentException(
"To query by locus ID, package name must also be set");
}
@@ -744,10 +752,7 @@ public class LauncherAppsService extends SystemService {
user = null;
}
- // TODO: When ShortcutQueryWrapper (ag/10323729) is available, pass that directly.
- ShortcutChangeHandler.QueryInfo query = new ShortcutChangeHandler.QueryInfo(
- changedSince, packageName, shortcutIds, locusIds, componentName, flags, user);
- mShortcutChangeHandler.addShortcutChangeCallback(callback, query);
+ mShortcutChangeHandler.addShortcutChangeCallback(callback, query, user);
}
@Override
@@ -1081,9 +1086,11 @@ public class LauncherAppsService extends SystemService {
new RemoteCallbackList<>();
public synchronized void addShortcutChangeCallback(IShortcutChangeCallback callback,
- QueryInfo query) {
+ ShortcutQueryWrapper query, UserHandle user) {
mCallbacks.unregister(callback);
- mCallbacks.register(callback, query);
+ mCallbacks.register(callback, new QueryInfo(query.getChangedSince(),
+ query.getPackage(), query.getShortcutIds(), query.getLocusIds(),
+ query.getActivity(), query.getQueryFlags(), user));
}
public synchronized void removeShortcutChangeCallback(
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 10b335e583b0..a446720c1c39 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3553,9 +3553,8 @@ class ActivityStack extends Task {
}
}
- void reparent(DisplayContent newParent, boolean onTop) {
- // Real parent of stack is within display object, so we have to delegate re-parenting there.
- newParent.moveStackToDisplay(this, onTop);
+ void reparent(TaskDisplayArea newParent, boolean onTop) {
+ reparent(newParent, onTop ? POSITION_TOP : POSITION_BOTTOM);
}
private void updateSurfaceBounds() {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 2c7ce9104c3c..8af862473386 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -412,7 +412,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final ActivityStack stack = (ActivityStack) task;
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (mToDisplay.getDisplayId() != stack.getDisplayId()) {
- mToDisplay.moveStackToDisplay(stack, mOnTop);
+ stack.reparent(mToDisplay.getDefaultTaskDisplayArea(), mOnTop);
} else if (mOnTop) {
mToDisplay.mTaskContainers.positionStackAtTop(stack,
false /* includingParents */);
@@ -566,8 +566,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
void moveRecentsStackToFront(String reason) {
- final ActivityStack recentsStack = mRootWindowContainer.getDefaultDisplay().getStack(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
+ final ActivityStack recentsStack = mRootWindowContainer.getDefaultTaskDisplayArea()
+ .getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
if (recentsStack != null) {
recentsStack.moveToFront(reason);
}
@@ -2613,7 +2613,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// from whatever is started from the recents activity, so move the home stack
// forward.
// TODO (b/115289124): Multi-display supports for recents.
- mRootWindowContainer.getDefaultDisplay().mTaskContainers.moveHomeStackToFront(
+ mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeStackToFront(
"startActivityFromRecents");
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7803c7370dac..0b1968765300 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4283,9 +4283,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
- final Task primary = dc.getRootSplitScreenPrimaryTask();
- final Task secondary = dc.getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
+ final TaskDisplayArea tc = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final Task primary = tc.getRootSplitScreenPrimaryTask();
+ final Task secondary = tc.getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
&& t.inSplitScreenSecondaryWindowingMode());
if (primary == null || secondary == null) {
return;
@@ -4301,7 +4301,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (otherRect == null) {
// Temporary estimation... again this is just for tests.
otherRect = new Rect(secondary.getBounds());
- if (dc.getBounds().width() > dc.getBounds().height()) {
+ if (tc.getBounds().width() > tc.getBounds().height()) {
otherRect.left = primaryRect.right + 6;
} else {
otherRect.top = primaryRect.bottom + 6;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 682a14220dff..e8becfa27fac 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -54,7 +54,7 @@ import java.util.Map;
* - DisplayArea.Root
* - Magnification
* - DisplayArea.Tokens (Wallpapers are attached here)
- * - TaskContainers
+ * - TaskDisplayArea
* - DisplayArea.Tokens (windows above Tasks up to IME are attached here)
* - ImeContainers
* - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY attached here)
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 55b7be779690..85517a44d656 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -575,13 +575,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private RootWindowContainer mRootWindowContainer;
- /**
- * All of the stacks on this display. Order matters, topmost stack is in front of all other
- * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
- * changing the list should also call {@link #onStackOrderChanged()}.
- */
- private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
-
/** Array of all UIDs that are present on the display. */
private IntArray mDisplayAccessUIDs = new IntArray();
@@ -2062,23 +2055,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
}
- ActivityStack getRootHomeTask() {
- return mTaskContainers.getRootHomeTask();
- }
-
- /** @return The primary split-screen task, and {@code null} otherwise. */
- @Nullable ActivityStack getRootSplitScreenPrimaryTask() {
- return mTaskContainers.getRootSplitScreenPrimaryTask();
- }
-
- ActivityStack getRootPinnedTask() {
- return mTaskContainers.getRootPinnedTask();
- }
-
- boolean hasPinnedTask() {
- return mTaskContainers.getRootPinnedTask() != null;
- }
-
/**
* Returns the topmost stack on the display that is compatible with the input windowing mode and
* activity type. Null is no compatible stack on the display.
@@ -2095,32 +2071,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mTaskContainers.mChildren.get(index);
}
- int getIndexOf(ActivityStack stack) {
- return mTaskContainers.getIndexOf(stack);
- }
-
- void removeStack(ActivityStack stack) {
- mTaskContainers.removeChild(stack);
- }
-
- @VisibleForTesting
- WindowList<ActivityStack> getStacks() {
- return mTaskContainers.mChildren;
- }
-
@VisibleForTesting
ActivityStack getTopStack() {
return mTaskContainers.getTopStack();
}
- ArrayList<Task> getVisibleTasks() {
- return mTaskContainers.getVisibleTasks();
- }
-
- SurfaceControl getSplitScreenDividerAnchor() {
- return mTaskContainers.getSplitScreenDividerAnchor();
- }
-
/**
* The value is only valid in the scope {@link #onRequestedOverrideConfigurationChanged} of the
* changing hierarchy and the {@link #onConfigurationChanged} of its children.
@@ -2409,8 +2364,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
out.set(mDisplayFrames.mStable);
}
- void moveStackToDisplay(ActivityStack stack, boolean onTop) {
- stack.reparent(mTaskContainers, onTop ? POSITION_TOP: POSITION_BOTTOM);
+ /**
+ * Get the default display area on the display dedicated to app windows. This one should be used
+ * only as a fallback location for activity launches when no target display area is specified,
+ * or for cases when multi-instance is not supported yet (like Split-screen, PiP or Recents).
+ */
+ TaskDisplayArea getDefaultTaskDisplayArea() {
+ return mTaskContainers;
}
@Override
@@ -2473,7 +2433,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
*/
Task findTaskForResizePoint(int x, int y) {
final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
- return mTmpTaskForResizePointSearchResult.process(mTaskContainers, x, y, delta);
+ return mTmpTaskForResizePointSearchResult.process(getDefaultTaskDisplayArea(), x, y, delta);
}
void updateTouchExcludeRegion() {
@@ -2512,8 +2472,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
amendWindowTapExcludeRegion(mTouchExcludeRegion);
- // TODO(multi-display): Support docked stacks on secondary displays.
- if (mDisplayId == DEFAULT_DISPLAY && mTaskContainers.isSplitScreenModeActivated()) {
+ // TODO(multi-display): Support docked stacks on secondary displays & task containers.
+ if (mDisplayId == DEFAULT_DISPLAY
+ && getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
mTmpRegion.set(mTmpRect);
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -2908,20 +2869,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
pw.println();
// Dump stack references
- final ActivityStack homeStack = getRootHomeTask();
+ final ActivityStack homeStack = getDefaultTaskDisplayArea().getRootHomeTask();
if (homeStack != null) {
pw.println(prefix + "homeStack=" + homeStack.getName());
}
- final ActivityStack pinnedStack = getRootPinnedTask();
+ final ActivityStack pinnedStack = getDefaultTaskDisplayArea().getRootPinnedTask();
if (pinnedStack != null) {
pw.println(prefix + "pinnedStack=" + pinnedStack.getName());
}
- final ActivityStack splitScreenPrimaryStack = getRootSplitScreenPrimaryTask();
+ final ActivityStack splitScreenPrimaryStack = getDefaultTaskDisplayArea()
+ .getRootSplitScreenPrimaryTask();
if (splitScreenPrimaryStack != null) {
pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
}
- final ActivityStack recentsStack =
- getStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
+ // TODO: Support recents on non-default task containers
+ final ActivityStack recentsStack = getDefaultTaskDisplayArea().getStack(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
if (recentsStack != null) {
pw.println(prefix + "recentsStack=" + recentsStack.getName());
}
@@ -2955,12 +2918,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
}
- /** Returns true if the stack in the windowing mode is visible. */
- boolean isStackVisible(int windowingMode) {
- final ActivityStack stack = mTaskContainers.getTopStackInWindowingMode(windowingMode);
- return stack != null && stack.isVisible();
- }
-
/** Find the visible, touch-deliverable window under the given point */
WindowState getTouchableWinAtPointLocked(float xf, float yf) {
final int x = (int) xf;
@@ -4367,7 +4324,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// We skip IME windows so they're processed just above their target, except
// in split-screen mode where we process the IME containers above the docked divider.
return dc.mInputMethodTarget != null
- && !dc.mTaskContainers.isSplitScreenModeActivated();
+ && !dc.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
}
/** Like {@link #forAllWindows}, but ignores {@link #skipImeWindowsDuringTraversal} */
@@ -5262,7 +5219,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// released (no more ActivityStack). But, we cannot release it at that moment or the
// related WindowContainer will also be removed. So, we set display as removed after
// reparenting stack finished.
- final DisplayContent toDisplay = mRootWindowContainer.getDefaultDisplay();
+ final TaskDisplayArea toTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
mRootWindowContainer.mStackSupervisor.beginDeferResume();
try {
int numStacks = getStackCount();
@@ -5276,10 +5233,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// If default display is in split-window mode, set windowing mode of the stack
// to split-screen secondary. Otherwise, set the windowing mode to undefined by
// default to let stack inherited the windowing mode from the new display.
- final int windowingMode = toDisplay.mTaskContainers.isSplitScreenModeActivated()
+ final int windowingMode = toTaskDisplayArea.isSplitScreenModeActivated()
? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_UNDEFINED;
- stack.reparent(toDisplay, true /* onTop */);
+ stack.reparent(toTaskDisplayArea, true /* onTop */);
stack.setWindowingMode(windowingMode);
lastReparentedStack = stack;
}
@@ -5392,34 +5349,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mSleeping = asleep;
}
- /**
- * Adds a listener to be notified whenever the stack order in the display changes. Currently
- * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
- * current animation when the system state changes.
- */
- void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
- if (!mStackOrderChangedCallbacks.contains(listener)) {
- mStackOrderChangedCallbacks.add(listener);
- }
- }
-
- /**
- * Removes a previously registered stack order change listener.
- */
- void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
- mStackOrderChangedCallbacks.remove(listener);
- }
-
- /**
- * Notifies of a stack order change
- * @param stack The stack which triggered the order change
- */
- void onStackOrderChanged(ActivityStack stack) {
- for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
- mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
- }
- }
-
void setDisplayToSingleTaskInstance() {
final int childCount = getStackCount();
if (childCount > 1) {
@@ -5448,22 +5377,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
/**
- * Callback for when the order of the stacks in the display changes.
- */
- interface OnStackOrderChangedListener {
- void onStackOrderChanged(ActivityStack stack);
- }
-
- public void dumpStacks(PrintWriter pw) {
- for (int i = getStackCount() - 1; i >= 0; --i) {
- pw.print(getStackAt(i).getRootTaskId());
- if (i > 0) {
- pw.print(",");
- }
- }
- }
-
- /**
* Similar to {@link RootWindowContainer#isAnyNonToastWindowVisibleForUid(int)}, but
* used for pid.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 221258e94cb2..264da9fc681b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2653,8 +2653,8 @@ public class DisplayPolicy {
if (mStatusBarController.setBarShowingLw(true)) {
changes |= FINISH_LAYOUT_REDO_LAYOUT;
}
- } else if (topIsFullscreen
- && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
+ } else if (topIsFullscreen && !mDisplayContent.getDefaultTaskDisplayArea()
+ .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
if (mStatusBarController.setBarShowingLw(false)) {
changes |= FINISH_LAYOUT_REDO_LAYOUT;
@@ -3462,10 +3462,10 @@ public class DisplayPolicy {
}
private Pair<Integer, WindowState> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
- final boolean dockedStackVisible =
- mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- final boolean freeformStackVisible =
- mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
+ final boolean dockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
+ .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ final boolean freeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
+ .isStackVisible(WINDOWING_MODE_FREEFORM);
final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
// We need to force system bars when the docked stack is visible, when the freeform stack
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index af89a05bfa62..bef80f0a230a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -594,7 +594,8 @@ public class DisplayRotation {
// In the presence of the PINNED stack or System Alert windows we unfortunately can not
// seamlessly rotate.
- if (mDisplayContent.hasPinnedTask() || mDisplayContent.hasAlertWindowSurfaces()) {
+ if (mDisplayContent.getDefaultTaskDisplayArea().hasPinnedTask()
+ || mDisplayContent.hasAlertWindowSurfaces()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 007af249c580..e4e57168efe7 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -295,10 +295,10 @@ class InsetsPolicy {
}
private boolean forceShowsSystemBarsForWindowingMode() {
- final boolean isDockedStackVisible =
- mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- final boolean isFreeformStackVisible =
- mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
+ final boolean isDockedStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
+ .isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ final boolean isFreeformStackVisible = mDisplayContent.getDefaultTaskDisplayArea()
+ .isStackVisible(WINDOWING_MODE_FREEFORM);
final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing();
// We need to force system bars when the docked stack is visible, when the freeform stack
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index a936e74bf694..57a54d0e84ef 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -406,11 +406,12 @@ class KeyguardController {
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
// of the lock screen in the right fullscreen configuration.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- if (!display.mTaskContainers.isSplitScreenModeActivated()) {
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ if (!taskDisplayArea.isSplitScreenModeActivated()) {
return;
}
- display.mTaskContainers.onSplitScreenModeDismissed();
+ taskDisplayArea.onSplitScreenModeDismissed();
}
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 66dbfd5f2a84..02a27410dc38 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -286,7 +286,8 @@ class PinnedStackController {
}
try {
final Rect animatingBounds = new Rect();
- final ActivityStack pinnedStack = mDisplayContent.getRootPinnedTask();
+ final ActivityStack pinnedStack = mDisplayContent.getDefaultTaskDisplayArea()
+ .getRootPinnedTask();
if (pinnedStack != null) {
pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 08b0abf5e9be..a031fe82d48b 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -52,14 +52,14 @@ import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallback
* cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
*/
class RecentsAnimation implements RecentsAnimationCallbacks,
- DisplayContent.OnStackOrderChangedListener {
+ TaskDisplayArea.OnStackOrderChangedListener {
private static final String TAG = RecentsAnimation.class.getSimpleName();
private final ActivityTaskManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private final ActivityStartController mActivityStartController;
private final WindowManagerService mWindowManager;
- private final DisplayContent mDefaultDisplay;
+ private final TaskDisplayArea mDefaultTaskDisplayArea;
private final Intent mTargetIntent;
private final ComponentName mRecentsComponent;
private final @Nullable String mRecentsFeatureId;
@@ -84,7 +84,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
int recentsUid, @Nullable WindowProcessController caller) {
mService = atm;
mStackSupervisor = stackSupervisor;
- mDefaultDisplay = mService.mRootWindowContainer.getDefaultDisplay();
+ mDefaultTaskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
mActivityStartController = activityStartController;
mWindowManager = wm;
mTargetIntent = targetIntent;
@@ -107,7 +107,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
void preloadRecentsActivity() {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s",
mTargetIntent);
- ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
+ ActivityStack targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
ActivityRecord targetActivity = getTargetActivity(targetStack);
if (targetActivity != null) {
@@ -128,7 +128,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// Create the activity record. Because the activity is invisible, this doesn't really
// start the client.
startRecentsActivityInBackground("preloadRecents");
- targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED, mTargetActivityType);
+ targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
+ mTargetActivityType);
targetActivity = getTargetActivity(targetStack);
if (targetActivity == null) {
Slog.w(TAG, "Cannot start " + mTargetIntent);
@@ -176,12 +177,11 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
}
// If the activity is associated with the recents stack, then try and get that first
- ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
+ ActivityStack targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
ActivityRecord targetActivity = getTargetActivity(targetStack);
final boolean hasExistingActivity = targetActivity != null;
if (hasExistingActivity) {
- final TaskDisplayArea taskDisplayArea = targetActivity.getDisplayArea();
mRestoreTargetBehindStack = getStackAbove(targetStack);
if (mRestoreTargetBehindStack == null) {
notifyAnimationCancelBeforeStart(recentsAnimationRunner);
@@ -209,7 +209,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
try {
if (hasExistingActivity) {
// Move the recents activity into place for the animation if it is not top most
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(targetStack);
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(targetStack);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
targetStack, getStackAbove(targetStack));
@@ -225,10 +225,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
startRecentsActivityInBackground("startRecentsActivity_noTargetActivity");
// Move the recents activity into place for the animation
- targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
+ targetStack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
targetActivity = getTargetActivity(targetStack);
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(targetStack);
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(targetStack);
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
targetStack, getStackAbove(targetStack));
@@ -251,7 +251,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mWindowManager.cancelRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION,
"startRecentsActivity");
mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
- this, mDefaultDisplay.getDisplayId(),
+ this, mDefaultTaskDisplayArea.getDisplayId(),
mStackSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity);
// If we updated the launch-behind state, update the visibility of the activities after
@@ -262,7 +262,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
START_TASK_TO_FRONT, targetActivity);
// Register for stack order changes
- mDefaultDisplay.registerStackOrderChangedListener(this);
+ mDefaultTaskDisplayArea.registerStackOrderChangedListener(this);
} catch (Exception e) {
Slog.e(TAG, "Failed to start recents activity", e);
throw e;
@@ -280,7 +280,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mWindowManager.getRecentsAnimationController(), reorderMode);
// Unregister for stack order changes
- mDefaultDisplay.unregisterStackOrderChangedListener(this);
+ mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(this);
final RecentsAnimationController controller =
mWindowManager.getRecentsAnimationController();
@@ -308,7 +308,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
try {
mWindowManager.cleanupRecentsAnimation(reorderMode);
- final ActivityStack targetStack = mDefaultDisplay.getStack(
+ final ActivityStack targetStack = mDefaultTaskDisplayArea.getStack(
WINDOWING_MODE_UNDEFINED, mTargetActivityType);
// Prefer to use the original target activity instead of top activity because
// we may have moved another task to top (starting 3p launcher).
@@ -422,7 +422,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
@Override
public void onStackOrderChanged(ActivityStack stack) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", stack);
- if (mDefaultDisplay.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) {
+ if (mDefaultTaskDisplayArea.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) {
// The stack is not visible, so ignore this change
return;
}
@@ -480,8 +480,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
* @return The top stack that is not always-on-top.
*/
private ActivityStack getTopNonAlwaysOnTopStack() {
- for (int i = mDefaultDisplay.getStackCount() - 1; i >= 0; i--) {
- final ActivityStack s = mDefaultDisplay.getStackAt(i);
+ for (int i = mDefaultTaskDisplayArea.getStackCount() - 1; i >= 0; i--) {
+ final ActivityStack s = mDefaultTaskDisplayArea.getStackAt(i);
if (s.getWindowConfiguration().isAlwaysOnTop()) {
continue;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index a30b70de267d..84229f003032 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -340,9 +340,11 @@ public class RecentsAnimationController implements DeathRecipient {
// Make leashes for each of the visible/target tasks and add it to the recents animation to
// be started
- final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
- final ActivityStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
- targetActivityType);
+ // TODO(multi-display-area): Support Recents on multiple task display areas
+ final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea()
+ .getVisibleTasks();
+ final ActivityStack targetStack = mDisplayContent.getDefaultTaskDisplayArea()
+ .getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
if (targetStack != null) {
final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
{ if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
@@ -385,7 +387,8 @@ public class RecentsAnimationController implements DeathRecipient {
}
// Save the minimized home height
- mMinimizedHomeBounds = mDisplayContent.getRootHomeTask().getBounds();
+ mMinimizedHomeBounds = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask()
+ .getBounds();
mService.mWindowPlacerLocked.performSurfacePlacement();
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 770c08889ab9..32de699eaae9 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -232,10 +232,11 @@ class ResetTargetTaskHelper {
}
final ActivityTaskManagerService atmService = mTargetStack.mAtmService;
- DisplayContent display = mTargetStack.getDisplay();
- final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance();
+ TaskDisplayArea taskDisplayArea = mTargetStack.getDisplayArea();
+ final boolean singleTaskInstanceDisplay =
+ taskDisplayArea.mDisplayContent.isSingleTaskInstance();
if (singleTaskInstanceDisplay) {
- display = atmService.mRootWindowContainer.getDefaultDisplay();
+ taskDisplayArea = atmService.mRootWindowContainer.getDefaultTaskDisplayArea();
}
final int windowingMode = mTargetStack.getWindowingMode();
@@ -246,7 +247,7 @@ class ResetTargetTaskHelper {
final boolean alwaysCreateTask = DisplayContent.alwaysCreateStack(windowingMode,
activityType);
final Task task = alwaysCreateTask
- ? display.getBottomMostTask() : mTargetStack.getBottomMostTask();
+ ? taskDisplayArea.getBottomMostTask() : mTargetStack.getBottomMostTask();
Task targetTask = null;
if (task != null && r.taskAffinity.equals(task.affinity)) {
// If the activity currently at the bottom has the same task affinity as
@@ -257,7 +258,7 @@ class ResetTargetTaskHelper {
}
if (targetTask == null) {
if (alwaysCreateTask) {
- targetTask = display.mTaskContainers.getOrCreateStack(windowingMode,
+ targetTask = taskDisplayArea.getOrCreateStack(windowingMode,
activityType, false /* onTop */);
} else {
targetTask = mTargetStack.reuseOrCreateTask(r.info, null /*intent*/,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2764b121cc00..2eeda4dcfeed 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1369,11 +1369,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
calculateDefaultMinimalSizeOfResizeableTasks();
- final DisplayContent defaultDisplay = getDefaultDisplay();
-
- defaultDisplay.mTaskContainers.getOrCreateStack(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_HOME, ON_TOP);
- positionChildAt(POSITION_TOP, defaultDisplay, false /* includingParents */);
+ final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();
+ defaultTaskDisplayArea.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME,
+ ON_TOP);
+ positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,
+ false /* includingParents */);
}
// TODO(multi-display): Look at all callpoints to make sure they make sense in multi-display.
@@ -1382,6 +1382,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
/**
+ * Get the default display area on the device dedicated to app windows. This one should be used
+ * only as a fallback location for activity launches when no target display area is specified,
+ * or for cases when multi-instance is not supported yet (like Split-screen, Freeform, PiP or
+ * Recents).
+ */
+ TaskDisplayArea getDefaultTaskDisplayArea() {
+ return mDefaultDisplay.getDefaultTaskDisplayArea();
+ }
+
+ /**
* Get an existing instance of {@link DisplayContent} that has the given uniqueId. Unique ID is
* defined in {@link DisplayInfo#uniqueId}.
*
@@ -1436,12 +1446,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return displayContent;
}
- ActivityRecord getDefaultDisplayHomeActivity() {
- return getDefaultDisplayHomeActivityForUser(mCurrentUser);
- }
-
ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) {
- return getDisplayContent(DEFAULT_DISPLAY).mTaskContainers.getHomeActivityForUser(userId);
+ return getDefaultTaskDisplayArea().getHomeActivityForUser(userId);
}
boolean startHomeOnAllDisplays(int userId, String reason) {
@@ -1972,8 +1978,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final int focusStackId = topFocusedStack != null
? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
// We dismiss the docked stack whenever we switch users.
- if (getDefaultDisplay().mTaskContainers.isSplitScreenModeActivated()) {
- getDefaultDisplay().mTaskContainers.onSplitScreenModeDismissed();
+ if (getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
+ getDefaultTaskDisplayArea().onSplitScreenModeDismissed();
}
// Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
// also cause all tasks to be moved to the fullscreen stack at a position that is
@@ -1995,7 +2001,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final int restoreStackId = mUserStackInFront.get(userId);
ActivityStack stack = getStack(restoreStackId);
if (stack == null) {
- stack = getDefaultDisplay().mTaskContainers.getOrCreateRootHomeTask();
+ stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
}
final boolean homeInFront = stack.isActivityTypeHome();
if (stack.isOnHomeDisplay()) {
@@ -2018,7 +2024,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void updateUserStack(int userId, ActivityStack stack) {
if (userId != mCurrentUser) {
if (stack == null) {
- stack = getDefaultDisplay().mTaskContainers.getOrCreateRootHomeTask();
+ stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
}
mUserStackInFront.put(userId, stack.getRootTaskId());
@@ -2061,7 +2067,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return;
}
- stack.reparent(displayContent.mDisplayContent, onTop);
+ stack.reparent(displayContent.getDefaultTaskDisplayArea(), onTop);
// TODO(multi-display): resize stacks properly if moved from split-screen.
}
@@ -2155,8 +2161,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Looking up task on preferred display first
final DisplayContent preferredDisplay = getDisplayContent(preferredDisplayId);
if (preferredDisplay != null) {
- preferredDisplay.mTaskContainers.findTaskLocked(r, true /* isPreferredDisplay */,
- mTmpFindTaskResult);
+ preferredDisplay.getDefaultTaskDisplayArea().findTaskLocked(r,
+ true /* isPreferredDisplay */, mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
return mTmpFindTaskResult.mRecord;
}
@@ -2168,7 +2174,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
continue;
}
- display.mTaskContainers.findTaskLocked(r, false /* isPreferredDisplay */,
+ display.getDefaultTaskDisplayArea().findTaskLocked(r, false /* isPreferredDisplay */,
mTmpFindTaskResult);
if (mTmpFindTaskResult.mIdealMatch) {
return mTmpFindTaskResult.mRecord;
@@ -2788,8 +2794,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
final DisplayContent display = getDisplayContentOrCreate(displayId);
if (display != null) {
- stack = display.mTaskContainers.getOrCreateStack(r, options, candidateTask,
- activityType, onTop);
+ // Falling back to default task container
+ final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
+ stack = taskDisplayArea.getOrCreateStack(r, options, candidateTask, activityType,
+ onTop);
if (stack != null) {
return stack;
}
@@ -2835,7 +2843,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (container == null
|| !canLaunchOnDisplay(r, container.mDisplayContent.mDisplayId)) {
- container = getDefaultDisplay().mTaskContainers;
+ container = getDefaultTaskDisplayArea();
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
windowingMode = container.resolveWindowingMode(r, options, candidateTask,
activityType);
@@ -2887,7 +2895,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// it to the target display.
if (candidateTask.isRootTask()) {
final ActivityStack stack = candidateTask.getStack();
- displayContent.moveStackToDisplay(stack, true /* onTop */);
+ stack.reparent(displayContent.getDefaultTaskDisplayArea(), true /* onTop */);
return stack;
}
}
@@ -2918,7 +2926,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final int activityType =
options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
? options.getLaunchActivityType() : r.getActivityType();
- return displayContent.createStack(windowingMode, activityType, true /*onTop*/);
+ final TaskDisplayArea taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
+ return taskDisplayArea.createStack(windowingMode, activityType, true /*onTop*/);
}
return null;
@@ -2989,7 +2998,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
if (preferredDisplayArea == null) {
// Stack is currently detached because it is being removed. Use the previous display it
// was on.
- preferredDisplayArea = getDisplayContent(currentFocus.mPrevDisplayId).mTaskContainers;
+ preferredDisplayArea = getDisplayContent(currentFocus.mPrevDisplayId)
+ .getDefaultTaskDisplayArea();
}
final ActivityStack preferredFocusableStack = preferredDisplayArea.getNextFocusableStack(
currentFocus, ignoreCurrent);
@@ -3010,7 +3020,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// We've already checked this one
continue;
}
- final ActivityStack nextFocusableStack = display.mTaskContainers
+ final ActivityStack nextFocusableStack = display.getDefaultTaskDisplayArea()
.getNextFocusableStack(currentFocus, ignoreCurrent);
if (nextFocusableStack != null) {
return nextFocusableStack;
@@ -3020,31 +3030,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return null;
}
- /**
- * Get next valid stack for launching provided activity in the system. This will search across
- * displays and stacks in last-focused order for a focusable and visible stack, except those
- * that are on a currently focused display.
- *
- * @param r The activity that is being launched.
- * @param currentFocus The display that previously had focus and thus needs to be ignored when
- * searching for the next candidate.
- * @return Next valid {@link ActivityStack}, null if not found.
- */
- ActivityStack getNextValidLaunchStack(@NonNull ActivityRecord r, int currentFocus) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final DisplayContent display = getChildAt(i);
- if (display.mDisplayId == currentFocus) {
- continue;
- }
- final ActivityStack stack = getValidLaunchStackOnDisplay(display.mDisplayId, r,
- null /* options */, null /* launchParams */);
- if (stack != null) {
- return stack;
- }
- }
- return null;
- }
-
boolean handleAppDied(WindowProcessController app) {
boolean hasVisibleActivities = false;
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 77ef01134292..13e4d8b038b1 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -127,6 +127,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
* the new stack becomes resumed after which it will be set to current focused stack.
*/
ActivityStack mLastFocusedStack;
+ /**
+ * All of the stacks on this display. Order matters, topmost stack is in front of all other
+ * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
+ * changing the list should also call {@link #onStackOrderChanged()}.
+ */
+ private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) {
super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
@@ -336,9 +342,9 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
// Since a stack could be repositioned while being one of the child, return
// current index if that's the same stack we are positioning and it is always on
// top.
- final boolean sameStack = mDisplayContent.getStacks().get(i) == stack;
+ final boolean sameStack = mChildren.get(i) == stack;
if ((sameStack && stack.isAlwaysOnTop())
- || (!sameStack && !mDisplayContent.getStacks().get(i).isAlwaysOnTop())) {
+ || (!sameStack && !mChildren.get(i).isAlwaysOnTop())) {
belowAlwaysOnTopPosition = i;
break;
}
@@ -352,7 +358,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
if (stack.isAlwaysOnTop()) {
if (hasPinnedTask()) {
// Always-on-top stacks go below the pinned stack.
- maxPosition = mDisplayContent.getStacks().indexOf(mRootPinnedTask) - 1;
+ maxPosition = mChildren.indexOf(mRootPinnedTask) - 1;
}
// Always-on-top stacks need to be above all other stacks.
minPosition = belowAlwaysOnTopPosition
@@ -375,7 +381,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
targetPosition = Math.min(targetPosition, maxPosition);
targetPosition = Math.max(targetPosition, minPosition);
- int prevPosition = mDisplayContent.getStacks().indexOf(stack);
+ int prevPosition = mChildren.indexOf(stack);
// The positions we calculated above (maxPosition, minPosition) do not take into
// consideration the following edge cases.
// 1) We need to adjust the position depending on the value "adding".
@@ -471,7 +477,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
@Override
int getOrientation(int candidate) {
- if (mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
+ if (isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
// Apps and their containers are not allowed to specify an orientation while using
// root tasks...except for the home stack if it is not resizable and currently
// visible (top of) its root task.
@@ -637,7 +643,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
mPreferredTopFocusableStack = null;
}
mDisplayContent.releaseSelfIfNeeded();
- mDisplayContent.onStackOrderChanged(stack);
+ onStackOrderChanged(stack);
}
void positionStackAt(int position, ActivityStack child, boolean includingParents) {
@@ -716,7 +722,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
}
}
- mDisplayContent.onStackOrderChanged(stack);
+ onStackOrderChanged(stack);
}
ActivityStack getStack(int rootTaskId) {
@@ -765,11 +771,11 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
} else if (stack.getParent() != launchRootTask) {
stack.reparent(launchRootTask, position);
}
- } else if (stack.getDisplay() != mDisplayContent || !stack.isRootTask()) {
+ } else if (stack.getDisplayArea() != this || !stack.isRootTask()) {
if (stack.getParent() == null) {
addStack(stack, position);
} else {
- stack.reparent(mDisplayContent, onTop);
+ stack.reparent(this, onTop);
}
}
// Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
@@ -832,7 +838,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
// Create stack on default display instead since this display can only contain 1 stack.
// TODO: Kinda a hack, but better that having the decision at each call point. Hoping
// this goes away once ActivityView is no longer using virtual displays.
- return mRootWindowContainer.getDefaultDisplay().mTaskContainers.createStack(
+ return mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
windowingMode, activityType, onTop, info, intent, createdByOrganizer);
}
@@ -1551,6 +1557,16 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
}
+ /** Returns true if the stack in the windowing mode is visible. */
+ boolean isStackVisible(int windowingMode) {
+ final ActivityStack stack = getTopStackInWindowingMode(windowingMode);
+ return stack != null && stack.isVisible();
+ }
+
+ void removeStack(ActivityStack stack) {
+ removeChild(stack);
+ }
+
int getDisplayId() {
return mDisplayContent.getDisplayId();
}
@@ -1558,4 +1574,39 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> {
boolean isRemoved() {
return mDisplayContent.isRemoved();
}
+
+ /**
+ * Adds a listener to be notified whenever the stack order in the display changes. Currently
+ * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
+ * current animation when the system state changes.
+ */
+ void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
+ if (!mStackOrderChangedCallbacks.contains(listener)) {
+ mStackOrderChangedCallbacks.add(listener);
+ }
+ }
+
+ /**
+ * Removes a previously registered stack order change listener.
+ */
+ void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
+ mStackOrderChangedCallbacks.remove(listener);
+ }
+
+ /**
+ * Notifies of a stack order change
+ * @param stack The stack which triggered the order change
+ */
+ void onStackOrderChanged(ActivityStack stack) {
+ for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
+ mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
+ }
+ }
+
+ /**
+ * Callback for when the order of the stacks in the display changes.
+ */
+ interface OnStackOrderChangedListener {
+ void onStackOrderChanged(ActivityStack stack);
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index b641e4c391ce..9ffd8d244c75 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -277,7 +277,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return null;
}
- final Task task = display.mTaskContainers.createStack(windowingMode,
+ final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */);
RunningTaskInfo out = task.getTaskInfo();
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index e43f4b485349..b9b6c0858031 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -510,7 +510,7 @@ class WallpaperController {
private void findWallpaperTarget() {
mFindResults.reset();
- if (mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)) {
+ if (mDisplayContent.getDefaultTaskDisplayArea().isStackVisible(WINDOWING_MODE_FREEFORM)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible.
mFindResults.setUseTopWallpaperAsTarget(true);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dfaa0ec47155..687af64e9d4f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7318,8 +7318,9 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean isStackVisibleLw(int windowingMode) {
- final DisplayContent dc = getDefaultDisplayContentLocked();
- return dc.isStackVisible(windowingMode);
+ // TODO(multi-display-area): Support multiple task display areas & displays
+ final TaskDisplayArea tc = mRoot.getDefaultTaskDisplayArea();
+ return tc.isStackVisible(windowingMode);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index a332b6966291..3e2e9be24c4f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -234,7 +234,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (task.getParent() != newParent) {
if (newParent == null) {
// Re-parent task to display as a root task.
- dc.moveStackToDisplay(as, hop.getToTop());
+ as.reparent(dc.getDefaultTaskDisplayArea(), hop.getToTop());
} else if (newParent.inMultiWindowMode() && !task.isResizeable()
&& task.isLeafTask()) {
Slog.w(TAG, "Can't support task that doesn't support multi-window mode in"
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b87d18143fc7..8e7585ae4bfa 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1516,7 +1516,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Some system windows (e.g. "Power off" dialog) don't have a task, but we would still
// associate them with some stack to enable dimming.
final DisplayContent dc = getDisplayContent();
- return mAttrs.type >= FIRST_SYSTEM_WINDOW && dc != null ? dc.getRootHomeTask() : null;
+ return mAttrs.type >= FIRST_SYSTEM_WINDOW
+ && dc != null ? dc.getDefaultTaskDisplayArea().getRootHomeTask() : null;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 3c2b6ec9711d..7457a1d05335 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -397,7 +397,8 @@ class WindowToken extends WindowContainer<WindowState> {
void assignLayer(SurfaceControl.Transaction t, int layer) {
if (windowType == TYPE_DOCK_DIVIDER) {
// See {@link DisplayContent#mSplitScreenDividerAnchor}
- super.assignRelativeLayer(t, mDisplayContent.getSplitScreenDividerAnchor(), 1);
+ super.assignRelativeLayer(t,
+ mDisplayContent.getDefaultTaskDisplayArea().getSplitScreenDividerAnchor(), 1);
} else if (mRoundedCornerOverlay) {
super.assignLayer(t, WindowManagerPolicy.COLOR_FADE_LAYER + 1);
} else {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 05604b2b9aeb..1debd8c9ffb1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -61,19 +61,20 @@ public class ActivityDisplayTests extends ActivityTestsBase {
@Test
public void testLastFocusedStackIsUpdatedWhenMovingStack() {
// Create a stack at bottom.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+ final TaskDisplayArea taskDisplayAreas =
+ mRootWindowContainer.getDefaultDisplay().getDefaultTaskDisplayArea();
final ActivityStack stack =
new StackBuilder(mRootWindowContainer).setOnTop(!ON_TOP).build();
- final ActivityStack prevFocusedStack = display.getFocusedStack();
+ final ActivityStack prevFocusedStack = taskDisplayAreas.getFocusedStack();
stack.moveToFront("moveStackToFront");
// After moving the stack to front, the previous focused should be the last focused.
assertTrue(stack.isFocusedStackOnDisplay());
- assertEquals(prevFocusedStack, display.mTaskContainers.getLastFocusedStack());
+ assertEquals(prevFocusedStack, taskDisplayAreas.getLastFocusedStack());
stack.moveToBack("moveStackToBack", null /* task */);
// After moving the stack to back, the stack should be the last focused.
- assertEquals(stack, display.mTaskContainers.getLastFocusedStack());
+ assertEquals(stack, taskDisplayAreas.getLastFocusedStack());
}
/**
@@ -83,8 +84,8 @@ public class ActivityDisplayTests extends ActivityTestsBase {
@Test
public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() {
// Create a pinned stack and move to front.
- final ActivityStack pinnedStack = mRootWindowContainer.getDefaultDisplay().createStack(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
+ final ActivityStack pinnedStack = mRootWindowContainer.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task pinnedTask = new TaskBuilder(mService.mStackSupervisor)
.setStack(pinnedStack).build();
new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
@@ -104,8 +105,8 @@ public class ActivityDisplayTests extends ActivityTestsBase {
}
/**
- * Test {@link DisplayContent#mPreferredTopFocusableStack} will be cleared when the stack is
- * removed or moved to back, and the focused stack will be according to z-order.
+ * Test {@link TaskDisplayArea#mPreferredTopFocusableStack} will be cleared when
+ * the stack is removed or moved to back, and the focused stack will be according to z-order.
*/
@Test
public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() {
@@ -124,7 +125,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
assertTrue(stack1.isFocusedStackOnDisplay());
// Stack2 should be focused after removing stack1.
- display.removeStack(stack1);
+ stack1.getDisplayArea().removeStack(stack1);
assertTrue(stack2.isFocusedStackOnDisplay());
}
@@ -156,7 +157,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
}
private ActivityStack createFullscreenStackWithSimpleActivityAt(DisplayContent display) {
- final ActivityStack fullscreenStack = display.createStack(
+ final ActivityStack fullscreenStack = display.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
.setStack(fullscreenStack).build();
@@ -219,58 +220,56 @@ public class ActivityDisplayTests extends ActivityTestsBase {
*/
@Test
public void testAlwaysOnTopStackLocation() {
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityStack alwaysOnTopStack = display.createStack(WINDOWING_MODE_FREEFORM,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final ActivityStack alwaysOnTopStack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(alwaysOnTopStack).build();
alwaysOnTopStack.setAlwaysOnTop(true);
- display.mTaskContainers.positionStackAtTop(alwaysOnTopStack, false /* includingParents */);
+ taskDisplayArea.positionStackAtTop(alwaysOnTopStack, false /* includingParents */);
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
// Ensure always on top state is synced to the children of the stack.
assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop());
- assertEquals(alwaysOnTopStack, display.getTopStack());
+ assertEquals(alwaysOnTopStack, taskDisplayArea.getTopStack());
- final ActivityStack pinnedStack = display.createStack(
+ final ActivityStack pinnedStack = taskDisplayArea.createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(pinnedStack, display.getRootPinnedTask());
- assertEquals(pinnedStack, display.getTopStack());
+ assertEquals(pinnedStack, taskDisplayArea.getRootPinnedTask());
+ assertEquals(pinnedStack, taskDisplayArea.getTopStack());
- final ActivityStack anotherAlwaysOnTopStack = display.createStack(
+ final ActivityStack anotherAlwaysOnTopStack = taskDisplayArea.createStack(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
- display.mTaskContainers.positionStackAtTop(anotherAlwaysOnTopStack,
- false /* includingParents */);
+ taskDisplayArea.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- int topPosition = display.getStackCount() - 1;
+ int topPosition = taskDisplayArea.getStackCount() - 1;
// Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
// existing alwaysOnTop stack.
- assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 1));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1));
- final ActivityStack nonAlwaysOnTopStack = display.createStack(
+ final ActivityStack nonAlwaysOnTopStack = taskDisplayArea.createStack(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(display, nonAlwaysOnTopStack.getDisplay());
- topPosition = display.getStackCount() - 1;
+ assertEquals(taskDisplayArea, nonAlwaysOnTopStack.getDisplayArea());
+ topPosition = taskDisplayArea.getStackCount() - 1;
// Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
// existing other non-alwaysOnTop stacks.
- assertEquals(nonAlwaysOnTopStack, display.getStackAt(topPosition - 3));
+ assertEquals(nonAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 3));
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
- display.mTaskContainers.positionStackAtTop(anotherAlwaysOnTopStack,
- false /* includingParents */);
+ taskDisplayArea.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
- assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 2));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 2));
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
// Ensure always on top state changes properly when windowing mode changes.
anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 2));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 2));
anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
- assertEquals(anotherAlwaysOnTopStack, display.getStackAt(topPosition - 1));
+ assertEquals(anotherAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 1));
}
@Test
@@ -286,14 +285,14 @@ public class ActivityDisplayTests extends ActivityTestsBase {
}
private void removeStackTests(Runnable runnable) {
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final ActivityStack stack1 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final ActivityStack stack2 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final ActivityStack stack3 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final ActivityStack stack3 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final ActivityStack stack4 = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task task1 = new TaskBuilder(mService.mStackSupervisor).setStack(stack1).build();
final Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(stack2).build();
@@ -302,13 +301,13 @@ public class ActivityDisplayTests extends ActivityTestsBase {
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
- display.mTaskContainers.positionStackAtTop(stack3, false);
+ taskDisplayArea.positionStackAtTop(stack3, false);
return true;
}).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
// Removing stacks from the display while removing stacks.
doAnswer(invocation -> {
- display.removeStack(stack2);
+ taskDisplayArea.removeStack(stack2);
return true;
}).when(mSupervisor).removeTask(eq(task2), anyBoolean(), anyBoolean(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index cff93cf8ef1d..08f6409cb902 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1400,8 +1400,8 @@ public class ActivityRecordTests extends ActivityTestsBase {
display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
.setPosition(DisplayContent.POSITION_TOP).build();
}
- final ActivityStack stack = display.createStack(WINDOWING_MODE_UNDEFINED,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack stack = display.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index e8c0362c9f32..22d7fcbb4162 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -60,7 +60,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
@Before
public void setUp() throws Exception {
- mFullscreenStack = mRootWindowContainer.getDefaultDisplay().createStack(
+ mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index af5afff4bed1..3d15401cdfb9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -82,15 +82,15 @@ import org.junit.runner.RunWith;
@Presubmit
@RunWith(WindowTestRunner.class)
public class ActivityStackTests extends ActivityTestsBase {
- private DisplayContent mDefaultDisplay;
+ private TaskDisplayArea mDefaultTaskDisplayArea;
private ActivityStack mStack;
private Task mTask;
@Before
public void setUp() throws Exception {
- mDefaultDisplay = mRootWindowContainer.getDefaultDisplay();
- mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
+ mDefaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ mStack = mDefaultTaskDisplayArea.createStack(WINDOWING_MODE_UNDEFINED,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
spyOn(mStack);
mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
}
@@ -112,7 +112,7 @@ public class ActivityStackTests extends ActivityTestsBase {
r.setState(RESUMED, "testResumedActivityFromTaskReparenting");
assertEquals(r, mStack.getResumedActivity());
- final ActivityStack destStack = mRootWindowContainer.getDefaultDisplay().createStack(
+ final ActivityStack destStack = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_STACK_AT_FRONT,
@@ -130,7 +130,7 @@ public class ActivityStackTests extends ActivityTestsBase {
r.setState(RESUMED, "testResumedActivityFromActivityReparenting");
assertEquals(r, mStack.getResumedActivity());
- final ActivityStack destStack = mRootWindowContainer.getDefaultDisplay().createStack(
+ final ActivityStack destStack = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false,
"testResumedActivityFromActivityReparenting");
@@ -143,7 +143,7 @@ public class ActivityStackTests extends ActivityTestsBase {
public void testPrimarySplitScreenRestoresWhenMovedToBack() {
// Create primary splitscreen stack. This will create secondary stacks and places the
// existing fullscreen stack on the bottom.
- final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Assert windowing mode.
@@ -154,7 +154,7 @@ public class ActivityStackTests extends ActivityTestsBase {
null /* task */);
// Assert that stack is at the bottom.
- assertEquals(0, mDefaultDisplay.getIndexOf(primarySplitScreen));
+ assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen));
// Ensure no longer in splitscreen.
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
@@ -167,7 +167,7 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testPrimarySplitScreenRestoresPreviousWhenMovedToBack() {
// This time, start with a fullscreen activitystack
- final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
primarySplitScreen.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
@@ -180,7 +180,7 @@ public class ActivityStackTests extends ActivityTestsBase {
null /* task */);
// Assert that stack is at the bottom.
- assertEquals(0, mDefaultDisplay.getIndexOf(primarySplitScreen));
+ assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen));
// Ensure that the override mode is restored to what it was (fullscreen)
assertEquals(WINDOWING_MODE_FULLSCREEN,
@@ -189,14 +189,14 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testStackInheritsDisplayWindowingMode() {
- final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
assertEquals(WINDOWING_MODE_UNDEFINED,
primarySplitScreen.getRequestedOverrideWindowingMode());
- mDefaultDisplay.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mDefaultTaskDisplayArea.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(WINDOWING_MODE_FREEFORM, primarySplitScreen.getWindowingMode());
assertEquals(WINDOWING_MODE_UNDEFINED,
primarySplitScreen.getRequestedOverrideWindowingMode());
@@ -204,7 +204,7 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testStackOverridesDisplayWindowingMode() {
- final ActivityStack primarySplitScreen = mDefaultDisplay.createStack(
+ final ActivityStack primarySplitScreen = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
@@ -216,7 +216,7 @@ public class ActivityStackTests extends ActivityTestsBase {
assertEquals(WINDOWING_MODE_FULLSCREEN,
primarySplitScreen.getRequestedOverrideWindowingMode());
- mDefaultDisplay.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ mDefaultTaskDisplayArea.setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
}
@@ -283,10 +283,11 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testMoveStackToBackIncludingParent() {
- final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- final ActivityStack stack1 = createStackForShouldBeVisibleTest(display,
+ final TaskDisplayArea taskDisplayArea = addNewDisplayContentAt(DisplayContent.POSITION_TOP)
+ .getDefaultTaskDisplayArea();
+ final ActivityStack stack1 = createStackForShouldBeVisibleTest(taskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityStack stack2 = createStackForShouldBeVisibleTest(display,
+ final ActivityStack stack2 = createStackForShouldBeVisibleTest(taskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Do not move display to back because there is still another stack.
@@ -294,16 +295,16 @@ public class ActivityStackTests extends ActivityTestsBase {
verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */);
// Also move display to back because there is only one stack left.
- display.removeStack(stack1);
+ taskDisplayArea.removeStack(stack1);
stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.getTopMostTask());
verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */);
}
@Test
public void testShouldBeVisible_Fullscreen() {
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Add an activity to the pinned stack so it isn't considered empty for visibility check.
final ActivityRecord pinnedActivity = new ActivityBuilder(mService)
@@ -314,8 +315,9 @@ public class ActivityStackTests extends ActivityTestsBase {
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(pinnedStack.shouldBeVisible(null /* starting */));
- final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
// Home stack shouldn't be visible behind an opaque fullscreen stack, but pinned stack
// should be visible since it is always on-top.
doReturn(false).when(fullscreenStack).isTranslucent(any());
@@ -331,15 +333,15 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testShouldBeVisible_SplitScreen() {
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
// Home stack should always be fullscreen for this test.
doReturn(false).when(homeStack).supportsSplitScreenWindowingMode();
final ActivityStack splitScreenPrimary =
- createStackForShouldBeVisibleTest(mDefaultDisplay,
+ createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityStack splitScreenSecondary =
- createStackForShouldBeVisibleTest(mDefaultDisplay,
+ createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// Home stack shouldn't be visible if both halves of split-screen are opaque.
@@ -367,7 +369,7 @@ public class ActivityStackTests extends ActivityTestsBase {
splitScreenSecondary.getVisibility(null /* starting */));
final ActivityStack splitScreenSecondary2 =
- createStackForShouldBeVisibleTest(mDefaultDisplay,
+ createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// First split-screen secondary shouldn't be visible behind another opaque split-split
// secondary.
@@ -389,8 +391,9 @@ public class ActivityStackTests extends ActivityTestsBase {
assertEquals(STACK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
- final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
+ final ActivityStack assistantStack = createStackForShouldBeVisibleTest(
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT,
+ true /* onTop */);
// Split-screen stacks shouldn't be visible behind an opaque fullscreen stack.
doReturn(false).when(assistantStack).isTranslucent(any());
@@ -530,7 +533,7 @@ public class ActivityStackTests extends ActivityTestsBase {
final ActivityStack translucentStack =
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
@@ -547,7 +550,7 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testShouldBeVisible_Finishing() {
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
@@ -558,7 +561,7 @@ public class ActivityStackTests extends ActivityTestsBase {
}
final ActivityStack translucentStack = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
doReturn(true).when(translucentStack).isTranslucent(any());
@@ -580,7 +583,7 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testShouldBeVisible_FullscreenBehindTranslucentInHomeStack() {
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mService)
@@ -601,74 +604,77 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindFullscreen() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
doReturn(false).when(homeStack).isTranslucent(any());
doReturn(false).when(fullscreenStack).isTranslucent(any());
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
- int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
assertEquals(fullscreenStack, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
- assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@Test
public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeBehindTranslucent() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(
+ mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
doReturn(false).when(homeStack).isTranslucent(any());
doReturn(true).when(fullscreenStack).isTranslucent(any());
// Ensure that we don't move the home stack if it is already behind the top fullscreen stack
- int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
assertEquals(fullscreenStack, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
- assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@Test
public void testMoveHomeStackBehindBottomMostVisibleStack_NoMoveHomeOnTop() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
- final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack fullscreenStack = createStackForShouldBeVisibleTest(
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
doReturn(false).when(homeStack).isTranslucent(any());
doReturn(false).when(fullscreenStack).isTranslucent(any());
// Ensure we don't move the home stack if it is already on top
- int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
+ int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
assertNull(getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
- assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@Test
public void testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreen() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
doReturn(false).when(homeStack).isTranslucent(any());
@@ -678,22 +684,22 @@ public class ActivityStackTests extends ActivityTestsBase {
// Ensure that we move the home stack behind the bottom most fullscreen stack, ignoring the
// pinned stack
assertEquals(fullscreenStack1, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(fullscreenStack2, getStackAbove(homeStack));
}
@Test
public void
testMoveHomeStackBehindBottomMostVisibleStack_MoveHomeBehindFullscreenAndTranslucent() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
doReturn(false).when(homeStack).isTranslucent(any());
@@ -703,21 +709,21 @@ public class ActivityStackTests extends ActivityTestsBase {
// Ensure that we move the home stack behind the bottom most non-translucent fullscreen
// stack
assertEquals(fullscreenStack1, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindBottomMostVisibleStack(homeStack);
+ mDefaultTaskDisplayArea.moveStackBehindBottomMostVisibleStack(homeStack);
assertEquals(fullscreenStack1, getStackAbove(homeStack));
}
@Test
public void testMoveHomeStackBehindStack_BehindHomeStack() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
doReturn(false).when(homeStack).isTranslucent(any());
@@ -725,50 +731,50 @@ public class ActivityStackTests extends ActivityTestsBase {
doReturn(false).when(fullscreenStack2).isTranslucent(any());
// Ensure we don't move the home stack behind itself
- int homeStackIndex = mDefaultDisplay.getIndexOf(homeStack);
- mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, homeStack);
- assertEquals(homeStackIndex, mDefaultDisplay.getIndexOf(homeStack));
+ int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+ mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, homeStack);
+ assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
}
@Test
public void testMoveHomeStackBehindStack() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final ActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack1);
+ mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack1);
assertEquals(fullscreenStack1, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack2);
+ mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack2);
assertEquals(fullscreenStack2, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack4);
+ mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack4);
assertEquals(fullscreenStack4, getStackAbove(homeStack));
- mDefaultDisplay.mTaskContainers.moveStackBehindStack(homeStack, fullscreenStack2);
+ mDefaultTaskDisplayArea.moveStackBehindStack(homeStack, fullscreenStack2);
assertEquals(fullscreenStack2, getStackAbove(homeStack));
}
@Test
public void testSetAlwaysOnTop() {
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
- final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
assertEquals(pinnedStack, getStackAbove(homeStack));
final ActivityStack alwaysOnTopStack = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
alwaysOnTopStack.setAlwaysOnTop(true);
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
@@ -776,13 +782,13 @@ public class ActivityStackTests extends ActivityTestsBase {
assertEquals(pinnedStack, getStackAbove(alwaysOnTopStack));
final ActivityStack nonAlwaysOnTopStack = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
// Ensure non always on top stack is put below always on top stacks.
assertEquals(alwaysOnTopStack, getStackAbove(nonAlwaysOnTopStack));
final ActivityStack alwaysOnTopStack2 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
alwaysOnTopStack2.setAlwaysOnTop(true);
assertTrue(alwaysOnTopStack2.isAlwaysOnTop());
@@ -807,13 +813,14 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testSplitScreenMoveToFront() {
final ActivityStack splitScreenPrimary = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
+ mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityStack splitScreenSecondary = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack assistantStack = createStackForShouldBeVisibleTest(
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT,
true /* onTop */);
- final ActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
doReturn(false).when(splitScreenPrimary).isTranslucent(any());
doReturn(false).when(splitScreenSecondary).isTranslucent(any());
@@ -832,7 +839,7 @@ public class ActivityStackTests extends ActivityTestsBase {
private ActivityStack createStandardStackForVisibilityTest(int windowingMode,
boolean translucent) {
- final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack stack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */);
doReturn(translucent).when(stack).isTranslucent(any());
return stack;
@@ -840,20 +847,20 @@ public class ActivityStackTests extends ActivityTestsBase {
@SuppressWarnings("TypeParameterUnusedInFormals")
private ActivityStack createStackForShouldBeVisibleTest(
- DisplayContent display, int windowingMode, int activityType, boolean onTop) {
+ TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) {
final ActivityStack stack;
if (activityType == ACTIVITY_TYPE_HOME) {
// Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
- stack = mDefaultDisplay.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ stack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
if (onTop) {
- mDefaultDisplay.mTaskContainers.positionStackAtTop(stack,
+ mDefaultTaskDisplayArea.positionStackAtTop(stack,
false /* includingParents */);
} else {
- mDefaultDisplay.mTaskContainers.positionStackAtBottom(stack);
+ mDefaultTaskDisplayArea.positionStackAtBottom(stack);
}
} else {
stack = new StackBuilder(mRootWindowContainer)
- .setDisplay(display)
+ .setTaskDisplayArea(taskDisplayArea)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setOnTop(onTop)
@@ -1005,7 +1012,7 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testWontFinishHomeStackImmediately() {
- final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+ final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
ActivityRecord activity = homeStack.topRunningActivity();
@@ -1025,9 +1032,11 @@ public class ActivityStackTests extends ActivityTestsBase {
public void testFinishCurrentActivity() {
// Create 2 activities on a new display.
final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
- final ActivityStack stack1 = createStackForShouldBeVisibleTest(display,
+ final ActivityStack stack1 = createStackForShouldBeVisibleTest(
+ display.getDefaultTaskDisplayArea(),
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final ActivityStack stack2 = createStackForShouldBeVisibleTest(display,
+ final ActivityStack stack2 = createStackForShouldBeVisibleTest(
+ display.getDefaultTaskDisplayArea(),
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
// There is still an activity1 in stack1 so the activity2 should be added to finishing list
@@ -1075,26 +1084,26 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testStackOrderChangedOnRemoveStack() {
StackOrderChangedListener listener = new StackOrderChangedListener();
- mDefaultDisplay.registerStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
try {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
} finally {
- mDefaultDisplay.unregisterStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
}
assertTrue(listener.mChanged);
}
@Test
public void testStackOrderChangedOnAddPositionStack() {
- mDefaultDisplay.removeStack(mStack);
+ mDefaultTaskDisplayArea.removeStack(mStack);
StackOrderChangedListener listener = new StackOrderChangedListener();
- mDefaultDisplay.registerStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
try {
mStack.mReparenting = true;
- mDefaultDisplay.mTaskContainers.addStack(mStack, 0);
+ mDefaultTaskDisplayArea.addStack(mStack, 0);
} finally {
- mDefaultDisplay.unregisterStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
}
assertTrue(listener.mChanged);
}
@@ -1104,12 +1113,12 @@ public class ActivityStackTests extends ActivityTestsBase {
StackOrderChangedListener listener = new StackOrderChangedListener();
try {
final ActivityStack fullscreenStack1 = createStackForShouldBeVisibleTest(
- mDefaultDisplay, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- mDefaultDisplay.registerStackOrderChangedListener(listener);
- mDefaultDisplay.mTaskContainers.positionStackAtBottom(fullscreenStack1);
+ mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.positionStackAtBottom(fullscreenStack1);
} finally {
- mDefaultDisplay.unregisterStackOrderChangedListener(listener);
+ mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
}
assertTrue(listener.mChanged);
}
@@ -1189,7 +1198,7 @@ public class ActivityStackTests extends ActivityTestsBase {
@Test
public void testClearUnknownAppVisibilityBehindFullscreenActivity() {
final UnknownAppVisibilityController unknownAppVisibilityController =
- mDefaultDisplay.mDisplayContent.mUnknownAppVisibilityController;
+ mDefaultTaskDisplayArea.mDisplayContent.mUnknownAppVisibilityController;
final KeyguardController keyguardController = mSupervisor.getKeyguardController();
doReturn(true).when(keyguardController).isKeyguardLocked();
@@ -1254,7 +1263,7 @@ public class ActivityStackTests extends ActivityTestsBase {
}
private static class StackOrderChangedListener
- implements DisplayContent.OnStackOrderChangedListener {
+ implements TaskDisplayArea.OnStackOrderChangedListener {
public boolean mChanged = false;
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index 76a761ce0e10..27782f5b3683 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -77,8 +77,8 @@ public class ActivityStartControllerTests extends ActivityTestsBase {
.setCreateTask(true)
.build();
final int startFlags = random.nextInt();
- final ActivityStack stack = mService.mRootWindowContainer.getDefaultDisplay().createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack stack = mService.mRootWindowContainer.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final WindowProcessController wpc = new WindowProcessController(mService,
mService.mContext.getApplicationInfo(), "name", 12345,
UserHandle.getUserId(12345), mock(Object.class),
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 1d952bfcef2a..1cca207d5336 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -326,8 +326,9 @@ public class ActivityStarterTests extends ActivityTestsBase {
if (mockGetLaunchStack) {
// Instrument the stack and task used.
- final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack stack = mRootWindowContainer.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
+ true /* onTop */);
// Direct starter to use spy stack.
doReturn(stack).when(mRootWindowContainer)
@@ -742,7 +743,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
final TestDisplayContent secondaryDisplay =
new TestDisplayContent.Builder(mService, 1000, 1500)
.setPosition(POSITION_BOTTOM).build();
- final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.mTaskContainers;
+ final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
final ActivityStack stack = secondaryTaskContainer.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -783,7 +784,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
new TestDisplayContent.Builder(mService, 1000, 1500).build();
mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
false /* includingParents */);
- final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.mTaskContainers;
+ final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
@@ -835,7 +836,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
// Create a secondary display at bottom.
final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
- final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.mTaskContainers;
+ final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
@@ -951,7 +952,7 @@ public class ActivityStarterTests extends ActivityTestsBase {
final ActivityStarter starter = prepareStarter(0 /* flags */);
starter.mStartActivity = new ActivityBuilder(mService).build();
final Task task = new TaskBuilder(mService.mStackSupervisor)
- .setStack(mService.mRootWindowContainer.getDefaultDisplay().createStack(
+ .setStack(mService.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
.setUserId(10)
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 9240b2222cd6..67d4769522b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -372,7 +372,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
Task build() {
if (mStack == null && mCreateStack) {
- mStack = mSupervisor.mRootWindowContainer.getDefaultDisplay().createStack(
+ mStack = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
spyOn(mStack);
}
@@ -408,6 +408,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
static class StackBuilder {
private final RootWindowContainer mRootWindowContainer;
private DisplayContent mDisplay;
+ private TaskDisplayArea mTaskDisplayArea;
private int mStackId = -1;
private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
private int mActivityType = ACTIVITY_TYPE_STANDARD;
@@ -419,6 +420,7 @@ class ActivityTestsBase extends SystemServiceTestsBase {
StackBuilder(RootWindowContainer root) {
mRootWindowContainer = root;
mDisplay = mRootWindowContainer.getDefaultDisplay();
+ mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
}
StackBuilder setWindowingMode(int windowingMode) {
@@ -436,8 +438,20 @@ class ActivityTestsBase extends SystemServiceTestsBase {
return this;
}
+ /**
+ * Set the parent {@link DisplayContent} and use the default task display area. Overrides
+ * the task display area, if was set before.
+ */
StackBuilder setDisplay(DisplayContent display) {
mDisplay = display;
+ mTaskDisplayArea = mDisplay.getDefaultTaskDisplayArea();
+ return this;
+ }
+
+ /** Set the parent {@link TaskDisplayArea}. Overrides the display, if was set before. */
+ StackBuilder setTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
+ mTaskDisplayArea = taskDisplayArea;
+ mDisplay = mTaskDisplayArea.mDisplayContent;
return this;
}
@@ -462,9 +476,8 @@ class ActivityTestsBase extends SystemServiceTestsBase {
}
ActivityStack build() {
- final int stackId = mStackId >= 0 ? mStackId
- : mDisplay.mTaskContainers.getNextStackId();
- final ActivityStack stack = mDisplay.mTaskContainers.createStackUnchecked(
+ final int stackId = mStackId >= 0 ? mStackId : mTaskDisplayArea.getNextStackId();
+ final ActivityStack stack = mTaskDisplayArea.createStackUnchecked(
mWindowingMode, mActivityType, stackId, mOnTop, mInfo, mIntent,
false /* createdByOrganizer */);
final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 4cb50c7a9e4d..9b7ffd69da15 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -147,7 +147,7 @@ public class AppChangeTransitionTests extends WindowTestsBase {
// Reparenting to a display with different windowing mode may trigger
// a change transition internally, but it should be cleaned-up once
// the display change is complete.
- mStack.reparent(mDisplayContent, true);
+ mStack.reparent(mDisplayContent.getDefaultTaskDisplayArea(), true);
assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 8b91c7e5d5f3..8c8fd0516623 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -169,7 +169,7 @@ public class AppTransitionTests extends WindowTestsBase {
assertTrue(dc1.mOpeningApps.size() > 0);
// Move stack to another display.
- stack1.reparent(dc2, true);
+ stack1.reparent(dc2.getDefaultTaskDisplayArea(), true);
// Verify if token are cleared from both pending transition list in former display.
assertFalse(dc1.mOpeningApps.contains(activity1));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 38b3d76b447d..a901d1ebd890 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -281,7 +281,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertEquals(dc, activity.getDisplayContent());
// Move stack to first display.
- mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
+ stack.reparent(mDisplayContent.getDefaultTaskDisplayArea(), true /* onTop */);
assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
assertEquals(mDisplayContent, stack.getDisplayContent());
assertEquals(mDisplayContent, task.getDisplayContent());
@@ -753,7 +753,7 @@ public class DisplayContentTests extends WindowTestsBase {
doReturn(true).when(freeformStack).isVisible();
freeformStack.getTopChild().setBounds(100, 100, 300, 400);
- assertTrue(dc.isStackVisible(WINDOWING_MODE_FREEFORM));
+ assertTrue(dc.getDefaultTaskDisplayArea().isStackVisible(WINDOWING_MODE_FREEFORM));
freeformStack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
stack.getTopNonFinishingActivity().setOrientation(SCREEN_ORIENTATION_PORTRAIT);
@@ -1096,8 +1096,7 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testGetOrCreateRootHomeTask_defaultDisplay() {
- DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
- TaskDisplayArea defaultTaskDisplayArea = defaultDisplay.mTaskContainers;
+ TaskDisplayArea defaultTaskDisplayArea = mWm.mRoot.getDefaultTaskDisplayArea();
// Remove the current home stack if it exists so a new one can be created below.
ActivityStack homeTask = defaultTaskDisplayArea.getRootHomeTask();
@@ -1116,7 +1115,7 @@ public class DisplayContentTests extends WindowTestsBase {
doReturn(false).when(display).isUntrustedVirtualDisplay();
// Remove the current home stack if it exists so a new one can be created below.
- TaskDisplayArea taskDisplayArea = display.mTaskContainers;
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
ActivityStack homeTask = taskDisplayArea.getRootHomeTask();
if (homeTask != null) {
taskDisplayArea.removeChild(homeTask);
@@ -1129,7 +1128,7 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testGetOrCreateRootHomeTask_unsupportedSystemDecorations() {
DisplayContent display = createNewDisplay();
- TaskDisplayArea taskDisplayArea = display.mTaskContainers;
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
doReturn(false).when(display).supportsSystemDecorations();
assertNull(taskDisplayArea.getRootHomeTask());
@@ -1139,7 +1138,7 @@ public class DisplayContentTests extends WindowTestsBase {
@Test
public void testGetOrCreateRootHomeTask_untrustedVirtualDisplay() {
DisplayContent display = createNewDisplay();
- TaskDisplayArea taskDisplayArea = display.mTaskContainers;
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
doReturn(true).when(display).isUntrustedVirtualDisplay();
assertNull(taskDisplayArea.getRootHomeTask());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index cf7411e67135..9b2a2db5d3a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -860,6 +860,8 @@ public class DisplayRotationTests {
mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
.thenReturn(WmDisplayCutout.NO_CUTOUT);
+ when(mMockDisplayContent.getDefaultTaskDisplayArea())
+ .thenReturn(mock(TaskDisplayArea.class));
mMockDisplayPolicy = mock(DisplayPolicy.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index ae467c0c811d..6a71a7dd24dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -114,8 +114,8 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
.thenReturn(mTestDisplay);
- ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
- ACTIVITY_TYPE_STANDARD, /* onTop */ true);
+ ActivityStack stack = mTestDisplay.getDefaultTaskDisplayArea()
+ .createStack(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT).setStack(stack)
.build();
mTestTask.mUserId = TEST_USER_ID;
@@ -337,8 +337,8 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
public void testClearsRecordsOfTheUserOnUserCleanUp() {
mTarget.saveTask(mTestTask);
- ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
- ACTIVITY_TYPE_STANDARD, /* onTop */ true);
+ ActivityStack stack = mTestDisplay.getDefaultTaskDisplayArea().createStack(
+ TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
.setComponent(ALTERNATIVE_COMPONENT)
.setUserId(TEST_USER_ID)
@@ -349,7 +349,7 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase {
anotherTaskOfTheSameUser.setHasBeenVisible(true);
mTarget.saveTask(anotherTaskOfTheSameUser);
- stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
+ stack = mTestDisplay.getDefaultTaskDisplayArea().createStack(TEST_WINDOWING_MODE,
ACTIVITY_TYPE_STANDARD, /* onTop */ true);
final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
.setComponent(TEST_COMPONENT)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 071386fa9cbd..d9c3ace4589d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -28,7 +28,6 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -119,7 +118,7 @@ public class RecentTasksTest extends ActivityTestsBase {
public void setUp() throws Exception {
mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
spyOn(mTaskPersister);
- mTaskContainer = mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).mTaskContainers;
+ mTaskContainer = mRootWindowContainer.getDefaultTaskDisplayArea();
// Set the recent tasks we should use for testing in this class.
mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index da07baca3ce1..6d2b7b1e86fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -105,7 +105,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mDefaultDisplay = mWm.mRoot.getDefaultDisplay();
mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
DEFAULT_DISPLAY));
- mRootHomeTask = mDefaultDisplay.getRootHomeTask();
+ mRootHomeTask = mDefaultDisplay.getDefaultTaskDisplayArea().getRootHomeTask();
assertNotNull(mRootHomeTask);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 6810f6442c66..881561f5750b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -88,7 +88,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testRecentsActivityVisiblility() {
- TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay().mTaskContainers;
+ TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
ActivityStack recentsStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mService)
@@ -116,8 +116,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testPreloadRecentsActivity() {
- TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultDisplay()
- .mTaskContainers;
+ TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final ActivityStack homeStack =
defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
defaultTaskDisplayArea.positionStackAtTop(homeStack, false /* includingParents */);
@@ -178,8 +177,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testRestartRecentsActivity() throws Exception {
// Have a recents activity that is not attached to its process (ActivityRecord.app = null).
- TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultDisplay()
- .mTaskContainers;
+ TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
ActivityStack recentsStack = defaultTaskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_RECENTS, true /* onTop */);
ActivityRecord recentActivity = new ActivityBuilder(mService).setComponent(
@@ -208,7 +206,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testSetLaunchTaskBehindOfTargetActivity() {
- TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay().mTaskContainers;
+ TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
ActivityStack homeStack = taskDisplayArea.getRootHomeTask();
// Assume the home activity support recents.
ActivityRecord targetActivity = homeStack.getTopNonFinishingActivity();
@@ -253,7 +251,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testCancelAnimationOnVisibleStackOrderChange() {
- TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay().mTaskContainers;
+ TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
ActivityStack fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mService)
@@ -298,7 +296,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testKeepAnimationOnHiddenStackOrderChange() {
- TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay().mTaskContainers;
+ TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
ActivityStack fullscreenStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
new ActivityBuilder(mService)
@@ -334,7 +332,8 @@ public class RecentsAnimationTest extends ActivityTestsBase {
@Test
public void testMultipleUserHomeActivity_findUserHomeTask() {
- TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay().mTaskContainers;
+ TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultDisplay()
+ .getDefaultTaskDisplayArea();
ActivityStack homeStack = taskDisplayArea.getStack(WINDOWING_MODE_UNDEFINED,
ACTIVITY_TYPE_HOME);
ActivityRecord otherUserHomeActivity = new ActivityBuilder(mService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 836310496d0b..48d4e705ff4b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -89,7 +89,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Before
public void setUp() throws Exception {
- mFullscreenStack = mRootWindowContainer.getDefaultDisplay().createStack(
+ mFullscreenStack = mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
doNothing().when(mService).updateSleepIfNeededLocked();
}
@@ -129,8 +129,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
mRootWindowContainer.moveActivityToPinnedStack(firstActivity, sourceBounds,
0f /*aspectRatio*/, "initialMove");
- final DisplayContent display = mFullscreenStack.getDisplay();
- ActivityStack pinnedStack = display.getRootPinnedTask();
+ final TaskDisplayArea taskDisplayArea = mFullscreenStack.getDisplayArea();
+ ActivityStack pinnedStack = taskDisplayArea.getRootPinnedTask();
// Ensure a task has moved over.
ensureStackPlacement(pinnedStack, firstActivity);
ensureStackPlacement(mFullscreenStack, secondActivity);
@@ -140,8 +140,9 @@ public class RootActivityContainerTests extends ActivityTestsBase {
0f /*aspectRatio*/, "secondMove");
// Need to get stacks again as a new instance might have been created.
- pinnedStack = display.getRootPinnedTask();
- mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ pinnedStack = taskDisplayArea.getRootPinnedTask();
+ mFullscreenStack = taskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD);
// Ensure stacks have swapped tasks.
ensureStackPlacement(pinnedStack, secondActivity);
ensureStackPlacement(mFullscreenStack, firstActivity);
@@ -215,6 +216,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay();
doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack();
+ TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea();
+ doReturn(isFocusedStack ? stack : null).when(defaultTaskDisplayArea).getFocusedStack();
mRootWindowContainer.applySleepTokens(true);
verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
@@ -226,26 +229,29 @@ public class RootActivityContainerTests extends ActivityTestsBase {
*/
@Test
public void testRemovingStackOnAppCrash() {
- final DisplayContent defaultDisplay = mRootWindowContainer.getDefaultDisplay();
- final int originalStackCount = defaultDisplay.getStackCount();
- final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
+ final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ final int originalStackCount = defaultTaskDisplayArea.getStackCount();
+ final ActivityStack stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(stack).build();
- assertEquals(originalStackCount + 1, defaultDisplay.getStackCount());
+ assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount());
// Let's pretend that the app has crashed.
firstActivity.app.setThread(null);
mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
// Verify that the stack was removed.
- assertEquals(originalStackCount, defaultDisplay.getStackCount());
+ assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount());
}
@Test
public void testFocusability() {
- final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
+ final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
+ .getDefaultTaskDisplayArea();
+ final ActivityStack stack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(stack).build();
@@ -259,7 +265,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
assertFalse(stack.isTopActivityFocusable());
assertFalse(activity.isFocusable());
- final ActivityStack pinnedStack = mRootWindowContainer.getDefaultDisplay().createStack(
+ final ActivityStack pinnedStack = defaultTaskDisplayArea.createStack(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(pinnedStack).build();
@@ -288,7 +294,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() {
// Create primary split-screen stack with a task and an activity.
- final ActivityStack primaryStack = mRootWindowContainer.getDefaultDisplay()
+ final ActivityStack primaryStack = mRootWindowContainer.getDefaultTaskDisplayArea()
.createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
@@ -311,7 +317,6 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
// Create stack/task on default display.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
final ActivityStack targetStack = new StackBuilder(mRootWindowContainer)
.setOnTop(false)
.build();
@@ -325,7 +330,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
false);
- final TaskDisplayArea taskDisplayArea = display.mTaskContainers;
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
verify(taskDisplayArea).moveHomeStackToFront(contains(reason));
}
@@ -336,8 +341,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
// Create stack/task on default display.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final ActivityStack targetStack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */);
final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
@@ -353,7 +358,6 @@ public class RootActivityContainerTests extends ActivityTestsBase {
mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
false);
- final TaskDisplayArea taskDisplayArea = display.mTaskContainers;
verify(taskDisplayArea, never()).moveHomeStackToFront(contains(reason));
}
@@ -364,12 +368,12 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
// Create a stack at bottom.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final ActivityStack targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
- display.mTaskContainers.positionStackAtBottom(targetStack);
+ taskDisplayArea.positionStackAtBottom(targetStack);
// Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
// is the current top focused stack.
@@ -392,10 +396,9 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
mFullscreenStack.removeIfPossible();
- mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).getRootHomeTask()
- .removeIfPossible();
- mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ taskDisplayArea.getRootHomeTask().removeIfPossible();
+ taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt());
@@ -415,16 +418,15 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
mFullscreenStack.removeIfPossible();
- mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).getRootHomeTask()
- .removeIfPossible();
- mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
- .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ taskDisplayArea.getRootHomeTask().removeIfPossible();
+ taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
// Create an activity on secondary display.
final TestDisplayContent secondDisplay = addNewDisplayContentAt(
DisplayContent.POSITION_TOP);
- final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
new ActivityBuilder(mService).setTask(task).build();
@@ -446,8 +448,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testResumeActivityLingeringTransition() {
// Create a stack at top.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final ActivityStack targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
@@ -466,13 +468,13 @@ public class RootActivityContainerTests extends ActivityTestsBase {
@Test
public void testResumeActivityLingeringTransition_notExecuted() {
// Create a stack at bottom.
- final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
- final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ final ActivityStack targetStack = spy(taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
- display.mTaskContainers.positionStackAtBottom(targetStack);
+ taskDisplayArea.positionStackAtBottom(targetStack);
// Assume the stack is at the topmost position
assertFalse(targetStack.isTopStackInDisplayArea());
@@ -809,20 +811,20 @@ public class RootActivityContainerTests extends ActivityTestsBase {
public void testSwitchUser_missingHomeRootTask() {
doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
- DisplayContent defaultDisplay = mRootWindowContainer.getDefaultDisplay();
- ActivityStack homeStack = defaultDisplay.getRootHomeTask();
+ final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
+ ActivityStack homeStack = taskDisplayArea.getRootHomeTask();
if (homeStack != null) {
homeStack.removeImmediately();
}
- assertNull(defaultDisplay.getRootHomeTask());
+ assertNull(taskDisplayArea.getRootHomeTask());
int currentUser = mRootWindowContainer.mCurrentUser;
int otherUser = currentUser + 1;
mRootWindowContainer.switchUser(otherUser, null);
- assertNotNull(defaultDisplay.getRootHomeTask());
- assertEquals(defaultDisplay.getTopStack(), defaultDisplay.getRootHomeTask());
+ assertNotNull(taskDisplayArea.getRootHomeTask());
+ assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index d6a67abc9e76..3d3a0f148db5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -72,7 +72,8 @@ public class RunningTasksTest extends ActivityTestsBase {
final int numTasks = 10;
int activeTime = 0;
for (int i = 0; i < numTasks; i++) {
- createTask(display.getStackAt(i % numStacks), ".Task" + i, i, activeTime++, null);
+ createTask(display.getDefaultTaskDisplayArea().getStackAt(i % numStacks),
+ ".Task" + i, i, activeTime++, null);
}
// Ensure that the latest tasks were returned in order of decreasing last active time,
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 893a14541c48..673469474709 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -189,7 +189,7 @@ public class SizeCompatTests extends ActivityTestsBase {
final int originalDpi = mActivity.getConfiguration().densityDpi;
// Move the non-resizable activity to the new display.
- mStack.reparent(newDisplay.mDisplayContent, true /* onTop */);
+ mStack.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */);
assertEquals(originalBounds.width(), mActivity.getBounds().width());
assertEquals(originalBounds.height(), mActivity.getBounds().height());
@@ -257,7 +257,7 @@ public class SizeCompatTests extends ActivityTestsBase {
.setCanRotate(false).setNotch(notchHeight).build();
// Move the non-resizable activity to the new display.
- mStack.reparent(newDisplay, true /* onTop */);
+ mStack.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */);
// The configuration bounds should keep the same.
assertEquals(origWidth, configBounds.width());
assertEquals(origHeight, configBounds.height());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index af76e7fc0b76..af3ec38631ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -316,7 +316,7 @@ public class SystemServicesTestRule implements TestRule {
// that the default display is in fullscreen mode.
display.setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
spyOn(display);
- final TaskDisplayArea taskDisplayArea = display.mTaskContainers;
+ final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
spyOn(taskDisplayArea);
final ActivityStack homeStack = taskDisplayArea.getStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index a3446d16d9f3..1a38ff283477 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1312,14 +1312,14 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
}
private ActivityRecord createSourceActivity(TestDisplayContent display) {
- final ActivityStack stack = display.createStack(display.getWindowingMode(),
- ACTIVITY_TYPE_STANDARD, true);
+ final ActivityStack stack = display.getDefaultTaskDisplayArea()
+ .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
}
private void addFreeformTaskTo(TestDisplayContent display, Rect bounds) {
- final ActivityStack stack = display.createStack(display.getWindowingMode(),
- ACTIVITY_TYPE_STANDARD, true);
+ final ActivityStack stack = display.getDefaultTaskDisplayArea()
+ .createStack(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
// Just work around the unnecessary adjustments for bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index f76809b06510..50584c61cf92 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -203,9 +203,9 @@ public class TaskRecordTests extends ActivityTestsBase {
@Test
public void testFitWithinBounds() {
final Rect parentBounds = new Rect(10, 10, 200, 200);
- DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
- ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
+ TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+ ActivityStack stack = taskDisplayArea.createStack(WINDOWING_MODE_FREEFORM,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
final Configuration parentConfig = stack.getConfiguration();
parentConfig.windowConfiguration.setBounds(parentBounds);
@@ -438,9 +438,9 @@ public class TaskRecordTests extends ActivityTestsBase {
@Test
public void testInsetDisregardedWhenFreeformOverlapsNavBar() {
- DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
- ActivityStack stack = display.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
- true /* onTop */);
+ TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+ ActivityStack stack = taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD, true /* onTop */);
DisplayInfo displayInfo = new DisplayInfo();
mService.mContext.getDisplay().getDisplayInfo(displayInfo);
final int displayHeight = displayInfo.logicalHeight;
@@ -959,8 +959,8 @@ public class TaskRecordTests extends ActivityTestsBase {
private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
Rect expectedConfigBounds) {
- DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
- ActivityStack stack = display.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
+ TaskDisplayArea taskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea();
+ ActivityStack stack = taskDisplayArea.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 6387a3b7c474..d48e82723295 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -171,7 +171,7 @@ public class TaskStackTests extends WindowTestsBase {
// Reparent
clearInvocations(task1); // reset the number of onDisplayChanged for task.
- stack1.reparent(dc, true /* onTop */);
+ stack1.reparent(dc.getDefaultTaskDisplayArea(), true /* onTop */);
assertEquals(dc, stack1.getDisplayContent());
final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 900f014a0218..a4f1487dde1e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -254,7 +254,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
private WindowState createWallpaperTargetWindow(DisplayContent dc) {
final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
- .setStack(dc.getRootHomeTask())
+ .setStack(dc.getDefaultTaskDisplayArea().getRootHomeTask())
.setCreateTask(true)
.build();
homeActivity.setVisibility(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 27ea37dfeb19..118c2e4db208 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -780,8 +780,8 @@ public class WindowContainerTests extends WindowTestsBase {
WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
final DisplayContent newDc = createNewDisplay();
- mDisplayContent.removeStack(stack);
- newDc.mTaskContainers.addChild(stack, POSITION_TOP);
+ stack.getDisplayArea().removeStack(stack);
+ newDc.getDefaultTaskDisplayArea().addChild(stack, POSITION_TOP);
verify(stack).onDisplayChanged(newDc);
verify(task).onDisplayChanged(newDc);
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 8de27e8eb281..0fc9be32f4cf 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
+
import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
@@ -46,6 +48,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1257,4 +1260,26 @@ public class LinkPropertiesTest {
final LinkProperties Ipv6 = makeIpv6LinkProperties();
assertTrue(Ipv6.hasIpv6DnsServer());
}
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testHasIpv4UnreachableDefaultRoute() {
+ final LinkProperties lp = makeTestObject();
+ assertFalse(lp.hasIpv4UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv6UnreachableDefaultRoute());
+
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
+ assertTrue(lp.hasIpv4UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv6UnreachableDefaultRoute());
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testHasIpv6UnreachableDefaultRoute() {
+ final LinkProperties lp = makeTestObject();
+ assertFalse(lp.hasIpv6UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv4UnreachableDefaultRoute());
+
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
+ assertTrue(lp.hasIpv6UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv4UnreachableDefaultRoute());
+ }
}
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index 1658262c17f6..8204b494bbb8 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.fail;
import android.os.Build;
+import androidx.core.os.BuildCompat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -62,6 +63,11 @@ public class RouteInfoTest {
return new IpPrefix(prefix);
}
+ private static boolean isAtLeastR() {
+ // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
+ return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
+ }
+
@Test
public void testConstructor() {
RouteInfo r;
@@ -195,78 +201,130 @@ public class RouteInfoTest {
assertTrue(r.isDefaultRoute());
assertTrue(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
assertFalse(r.isHostRoute());
assertTrue(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertTrue(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertTrue(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertTrue(r.isIPv6UnreachableDefault());
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b02398d1f1f5..912a27f08f30 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -6336,6 +6336,7 @@ public class ConnectivityServiceTest {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
@@ -6361,6 +6362,7 @@ public class ConnectivityServiceTest {
public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
@@ -6392,6 +6394,7 @@ public class ConnectivityServiceTest {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
@@ -6428,6 +6431,7 @@ public class ConnectivityServiceTest {
reset(mMockNetd);
lp = new LinkProperties();
lp.setInterfaceName("tun1");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
vpnNetworkAgent.sendLinkProperties(lp);
waitForIdle();
@@ -6440,6 +6444,7 @@ public class ConnectivityServiceTest {
public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final UidRange vpnRange = UidRange.createForUser(VPN_USER);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index dfeea9f4b52e..f1be8b20eb53 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1887,12 +1887,20 @@ public class WifiManager {
* <li> If user reset network settings, all added suggestions will be discarded. Apps can use
* {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
* <li> In-place modification of existing suggestions are allowed.
- * If the provided suggestions {@link WifiNetworkSuggestion#equals(Object)} any previously
- * provided suggestions by the app. Previous suggestions will be updated</li>
+ * <li>If the provided suggestions includes any previously provided suggestions by the app,
+ * previous suggestions will be updated.</li>
+ * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
+ * the device is currently connected to that suggested network, then the device will disconnect
+ * from that network. The system will immediately re-evaluate all the network candidates
+ * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
+ * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
+ * </li>
+ * </li>
*
* @param networkSuggestions List of network suggestions provided by the app.
* @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
* @throws {@link SecurityException} if the caller is missing required permissions.
+ * @see WifiNetworkSuggestion#equals(Object)
*/
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
@@ -4152,6 +4160,10 @@ public class WifiManager {
*
* This function is used instead of a enableNetwork() and reconnect()
*
+ * <li> This API will cause reconnect if the credentials of the current active
+ * connection has been changed.</li>
+ * <li> This API will cause reconnect if the current active connection is marked metered.</li>
+ *
* @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
* getConfiguredNetworks}.
* @param listener for callbacks on success or failure. Can be null.
@@ -4180,8 +4192,9 @@ public class WifiManager {
*
* For an existing network, it accomplishes the task of updateNetwork()
*
- * This API will cause reconnect if the crecdentials of the current active
- * connection has been changed.
+ * <li> This API will cause reconnect if the credentials of the current active
+ * connection has been changed.</li>
+ * <li> This API will cause disconnect if the current active connection is marked metered.</li>
*
* @param config the set of variables that describe the configuration,
* contained in a {@link WifiConfiguration} object.
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 4c524f49e4df..cedf9b0b872d 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -543,7 +543,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.priority = mPriority;
wifiConfiguration.meteredOverride =
mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
- : WifiConfiguration.METERED_OVERRIDE_NONE;
+ : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
wifiConfiguration.carrierId = mCarrierId;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
return wifiConfiguration;
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index ac2f6b26aa00..aca190910ed1 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -56,7 +56,7 @@ public class WifiNetworkSuggestionTest {
.get(WifiConfiguration.KeyMgmt.NONE));
assertTrue(suggestion.isAppInteractionRequired);
assertFalse(suggestion.isUserInteractionRequired);
- assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NOT_METERED,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
@@ -86,7 +86,7 @@ public class WifiNetworkSuggestionTest {
suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.isAppInteractionRequired);
assertFalse(suggestion.isUserInteractionRequired);
- assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NOT_METERED,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(0, suggestion.wifiConfiguration.priority);
assertFalse(suggestion.isUserAllowedToManuallyConnect);