summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java56
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt12
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt17
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt11
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt14
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt5
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt6
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt10
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt93
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt150
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java18
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java12
38 files changed, 510 insertions, 342 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 0a15d8468983..f6e92ef0e8ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -165,7 +165,8 @@ public class Bubble implements BubbleViewProvider {
* Create a bubble with limited information based on given {@link ShortcutInfo}.
* Note: Currently this is only being used when the bubble is persisted to disk.
*/
- Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
+ @VisibleForTesting(visibility = PRIVATE)
+ public Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
int taskId, @Nullable final String locus, Executor mainExecutor) {
Objects.requireNonNull(key);
@@ -188,7 +189,7 @@ public class Bubble implements BubbleViewProvider {
}
@VisibleForTesting(visibility = PRIVATE)
- Bubble(@NonNull final BubbleEntry entry,
+ public Bubble(@NonNull final BubbleEntry entry,
@Nullable final Bubbles.SuppressionChangedListener listener,
final Bubbles.PendingIntentCanceledListener intentCancelListener,
Executor mainExecutor) {
@@ -718,7 +719,8 @@ public class Bubble implements BubbleViewProvider {
private int getUid(final Context context) {
if (mAppUid != -1) return mAppUid;
- final PackageManager pm = context.getPackageManager();
+ final PackageManager pm = BubbleController.getPackageManagerForUser(context,
+ mUser.getIdentifier());
if (pm == null) return -1;
try {
final ApplicationInfo info = pm.getApplicationInfo(mShortcutInfo.getPackage(), 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index dca598518432..4b037214fcdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -48,6 +48,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
+import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.PointF;
@@ -64,6 +65,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseSetArray;
import android.view.View;
import android.view.ViewGroup;
@@ -144,6 +146,8 @@ public class BubbleController {
// Tracks the id of the current (foreground) user.
private int mCurrentUserId;
+ // Current profiles of the user (e.g. user with a workprofile)
+ private SparseArray<UserInfo> mCurrentProfiles;
// Saves notification keys of active bubbles when users are switched.
private final SparseSetArray<String> mSavedBubbleKeysPerUser;
@@ -153,8 +157,8 @@ public class BubbleController {
// Callback that updates BubbleOverflowActivity on data change.
@Nullable private BubbleData.Listener mOverflowListener = null;
- // Only load overflow data from disk once
- private boolean mOverflowDataLoaded = false;
+ // Typically only load once & after user switches
+ private boolean mOverflowDataLoadNeeded = true;
/**
* When the shade status changes to SHADE (from anything but SHADE, like LOCKED) we'll select
@@ -468,14 +472,31 @@ public class BubbleController {
updateStack();
}
- private void onUserChanged(int newUserId) {
+ /** Called when the current user changes. */
+ @VisibleForTesting
+ public void onUserChanged(int newUserId) {
saveBubbles(mCurrentUserId);
+ mCurrentUserId = newUserId;
+
mBubbleData.dismissAll(DISMISS_USER_CHANGED);
+ mBubbleData.clearOverflow();
+ mOverflowDataLoadNeeded = true;
+
restoreBubbles(newUserId);
- mCurrentUserId = newUserId;
mBubbleData.setCurrentUserId(newUserId);
}
+ /** Called when the profiles for the current user change. **/
+ public void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {
+ mCurrentProfiles = currentProfiles;
+ }
+
+ /** Whether this userId belongs to the current user. */
+ private boolean isCurrentProfile(int userId) {
+ return userId == UserHandle.USER_ALL
+ || (mCurrentProfiles != null && mCurrentProfiles.get(userId) != null);
+ }
+
/**
* Sets whether to perform inflation on the same thread as the caller. This method should only
* be used in tests, not in production.
@@ -556,6 +577,7 @@ public class BubbleController {
mWmLayoutParams.setTitle("Bubbles!");
mWmLayoutParams.packageName = mContext.getPackageName();
mWmLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ mWmLayoutParams.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
try {
mAddedToWindowManager = true;
@@ -639,7 +661,7 @@ public class BubbleController {
});
});
// Finally, remove the entries for this user now that bubbles are restored.
- mSavedBubbleKeysPerUser.remove(mCurrentUserId);
+ mSavedBubbleKeysPerUser.remove(userId);
}
private void updateForThemeChanges() {
@@ -804,12 +826,12 @@ public class BubbleController {
* Fills the overflow bubbles by loading them from disk.
*/
void loadOverflowBubblesFromDisk() {
- if (!mBubbleData.getOverflowBubbles().isEmpty() || mOverflowDataLoaded) {
+ if (!mBubbleData.getOverflowBubbles().isEmpty() && !mOverflowDataLoadNeeded) {
// we don't need to load overflow bubbles from disk if it is already in memory
return;
}
- mOverflowDataLoaded = true;
- mDataRepository.loadBubbles((bubbles) -> {
+ mOverflowDataLoadNeeded = false;
+ mDataRepository.loadBubbles(mCurrentUserId, (bubbles) -> {
bubbles.forEach(bubble -> {
if (mBubbleData.hasAnyBubbleWithKey(bubble.getKey())) {
// if the bubble is already active, there's no need to push it to overflow
@@ -911,6 +933,12 @@ public class BubbleController {
Pair<BubbleEntry, Boolean> entryData = entryDataByKey.get(key);
BubbleEntry entry = entryData.first;
boolean shouldBubbleUp = entryData.second;
+
+ if (entry != null && !isCurrentProfile(
+ entry.getStatusBarNotification().getUser().getIdentifier())) {
+ return;
+ }
+
rankingMap.getRanking(key, mTmpRanking);
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
if (isActiveBubble && !mTmpRanking.canBubble()) {
@@ -1428,6 +1456,13 @@ public class BubbleController {
}
@Override
+ public void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {
+ mMainExecutor.execute(() -> {
+ BubbleController.this.onCurrentProfilesChanged(currentProfiles);
+ });
+ }
+
+ @Override
public void onConfigChanged(Configuration newConfig) {
mMainExecutor.execute(() -> {
BubbleController.this.onConfigChanged(newConfig);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index f6e6b8f3b700..8434d668e153 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -510,7 +510,8 @@ public class BubbleData {
|| reason == Bubbles.DISMISS_NO_LONGER_BUBBLE
|| reason == Bubbles.DISMISS_BLOCKED
|| reason == Bubbles.DISMISS_SHORTCUT_REMOVED
- || reason == Bubbles.DISMISS_PACKAGE_REMOVED)) {
+ || reason == Bubbles.DISMISS_PACKAGE_REMOVED
+ || reason == Bubbles.DISMISS_USER_CHANGED)) {
Bubble b = getOverflowBubbleWithKey(key);
if (DEBUG_BUBBLE_DATA) {
@@ -642,6 +643,16 @@ public class BubbleData {
}
}
+ /**
+ * Removes all bubbles from the overflow, called when the user changes.
+ */
+ public void clearOverflow() {
+ while (!mOverflowBubbles.isEmpty()) {
+ doRemove(mOverflowBubbles.get(0).getKey(), Bubbles.DISMISS_USER_CHANGED);
+ }
+ dispatchPendingChanges();
+ }
+
private void dispatchPendingChanges() {
if (mListener != null && mStateChange.anythingChanged()) {
mListener.applyUpdate(mStateChange);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index bfacd1cfe90e..9d9e442affd3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -58,7 +58,8 @@ internal class BubbleDataRepository(
*/
fun addBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) {
if (DEBUG) Log.d(TAG, "adding ${bubbles.size} bubbles")
- val entities = transform(userId, bubbles).also(volatileRepository::addBubbles)
+ val entities = transform(bubbles).also {
+ b -> volatileRepository.addBubbles(userId, b) }
if (entities.isNotEmpty()) persistToDisk()
}
@@ -67,14 +68,15 @@ internal class BubbleDataRepository(
*/
fun removeBubbles(@UserIdInt userId: Int, bubbles: List<Bubble>) {
if (DEBUG) Log.d(TAG, "removing ${bubbles.size} bubbles")
- val entities = transform(userId, bubbles).also(volatileRepository::removeBubbles)
+ val entities = transform(bubbles).also {
+ b -> volatileRepository.removeBubbles(userId, b) }
if (entities.isNotEmpty()) persistToDisk()
}
- private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
+ private fun transform(bubbles: List<Bubble>): List<BubbleEntity> {
return bubbles.mapNotNull { b ->
BubbleEntity(
- userId,
+ b.user.identifier,
b.packageName,
b.metadataShortcutId ?: return@mapNotNull null,
b.key,
@@ -116,10 +118,11 @@ internal class BubbleDataRepository(
/**
* Load bubbles from disk.
* @param cb The callback to be run after the bubbles are loaded. This callback is always made
- * on the main thread of the hosting process.
+ * on the main thread of the hosting process. The callback is only run if there are
+ * bubbles.
*/
@SuppressLint("WrongConstant")
- fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
+ fun loadBubbles(userId: Int, cb: (List<Bubble>) -> Unit) = ioScope.launch {
/**
* Load BubbleEntity from disk.
* e.g.
@@ -129,8 +132,9 @@ internal class BubbleDataRepository(
* BubbleEntity(0, "com.example.messenger", "id-1")
* ]
*/
- val entities = persistentRepository.readFromDisk()
- volatileRepository.addBubbles(entities)
+ val entitiesByUser = persistentRepository.readFromDisk()
+ val entities = entitiesByUser.get(userId) ?: return@launch
+ volatileRepository.addBubbles(userId, entities)
/**
* Extract userId/packageName from these entities.
* e.g.
@@ -139,9 +143,10 @@ internal class BubbleDataRepository(
* ]
*/
val shortcutKeys = entities.map { ShortcutKey(it.userId, it.packageName) }.toSet()
+
/**
- * Retrieve shortcuts with given userId/packageName combination, then construct a mapping
- * from the userId/packageName pair to a list of associated ShortcutInfo.
+ * Retrieve shortcuts with given userId/packageName combination, then construct a
+ * mapping from the userId/packageName pair to a list of associated ShortcutInfo.
* e.g.
* {
* ShortcutKey(0, "com.example.messenger") -> [
@@ -161,21 +166,23 @@ internal class BubbleDataRepository(
.setQueryFlags(SHORTCUT_QUERY_FLAG), UserHandle.of(key.userId))
?: emptyList()
}.groupBy { ShortcutKey(it.userId, it.`package`) }
- // For each entity loaded from xml, find the corresponding ShortcutInfo then convert them
- // into Bubble.
+ // For each entity loaded from xml, find the corresponding ShortcutInfo then convert
+ // them into Bubble.
val bubbles = entities.mapNotNull { entity ->
shortcutMap[ShortcutKey(entity.userId, entity.packageName)]
?.firstOrNull { shortcutInfo -> entity.shortcutId == shortcutInfo.id }
- ?.let { shortcutInfo -> Bubble(
- entity.key,
- shortcutInfo,
- entity.desiredHeight,
- entity.desiredHeightResId,
- entity.title,
- entity.taskId,
- entity.locus,
- mainExecutor
- ) }
+ ?.let { shortcutInfo ->
+ Bubble(
+ entity.key,
+ shortcutInfo,
+ entity.desiredHeight,
+ entity.desiredHeightResId,
+ entity.title,
+ entity.taskId,
+ entity.locus,
+ mainExecutor
+ )
+ }
}
mainExecutor.execute { cb(bubbles) }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
index fe3f9ef6aa5f..e64ed6a0836c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
@@ -29,6 +29,8 @@ import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ShadowGenerator;
@@ -39,11 +41,12 @@ import com.android.wm.shell.R;
* We are not using Launcher's IconFactory because bubbles only runs on the UI thread,
* so there is no need to manage a pool across multiple threads.
*/
+@VisibleForTesting
public class BubbleIconFactory extends BaseIconFactory {
private int mBadgeSize;
- protected BubbleIconFactory(Context context) {
+ public BubbleIconFactory(Context context) {
super(context, context.getResources().getConfiguration().densityDpi,
context.getResources().getDimensionPixelSize(R.dimen.individual_bubble_size));
mBadgeSize = mContext.getResources().getDimensionPixelSize(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index c5a712e271e4..fc53ef26dbd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -39,6 +39,7 @@ import android.util.PathParser;
import android.view.LayoutInflater;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
@@ -118,7 +119,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
/**
* Info necessary to render a bubble.
*/
- static class BubbleViewInfo {
+ @VisibleForTesting
+ public static class BubbleViewInfo {
BadgedImageView imageView;
BubbleExpandedView expandedView;
ShortcutInfo shortcutInfo;
@@ -129,8 +131,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
Path dotPath;
Bubble.FlyoutMessage flyoutMessage;
+ @VisibleForTesting
@Nullable
- static BubbleViewInfo populate(Context c, BubbleController controller,
+ public static BubbleViewInfo populate(Context c, BubbleController controller,
BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b,
boolean skipInflation) {
BubbleViewInfo info = new BubbleViewInfo();
@@ -152,7 +155,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
}
// App name & app icon
- PackageManager pm = c.getPackageManager();
+ PackageManager pm = BubbleController.getPackageManagerForUser(c,
+ b.getUser().getIdentifier());
ApplicationInfo appInfo;
Drawable badgedIcon;
Drawable appIcon;
@@ -217,10 +221,16 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
static Drawable loadSenderAvatar(@NonNull final Context context, @Nullable final Icon icon) {
Objects.requireNonNull(context);
if (icon == null) return null;
- if (icon.getType() == Icon.TYPE_URI || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
- context.grantUriPermission(context.getPackageName(),
- icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ try {
+ if (icon.getType() == Icon.TYPE_URI
+ || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ context.grantUriPermission(context.getPackageName(),
+ icon.getUri(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ return icon.loadDrawable(context);
+ } catch (Exception e) {
+ Log.w(TAG, "loadSenderAvatar failed: " + e.getMessage());
+ return null;
}
- return icon.loadDrawable(context);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 1bfb61929297..a93ce01dfc7b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -21,12 +21,14 @@ import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Looper;
import android.service.notification.NotificationListenerService.RankingMap;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.SparseArray;
import android.view.View;
import androidx.annotation.IntDef;
@@ -214,6 +216,13 @@ public interface Bubbles {
void onUserChanged(int newUserId);
/**
+ * Called when the current user profiles change.
+ *
+ * @param currentProfiles the user infos for the current profile.
+ */
+ void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles);
+
+ /**
* Called when config changed.
*
* @param newConfig the new config.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
index 66a75af7d64c..130790a04160 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.bubbles.storage
import android.content.Context
import android.util.AtomicFile
import android.util.Log
+import android.util.SparseArray
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
@@ -27,8 +28,8 @@ class BubblePersistentRepository(context: Context) {
private val bubbleFile: AtomicFile = AtomicFile(File(context.filesDir,
"overflow_bubbles.xml"), "overflow-bubbles")
- fun persistsToDisk(bubbles: List<BubbleEntity>): Boolean {
- if (DEBUG) Log.d(TAG, "persisting ${bubbles.size} bubbles")
+ fun persistsToDisk(bubbles: SparseArray<List<BubbleEntity>>): Boolean {
+ if (DEBUG) Log.d(TAG, "persisting ${bubbles.size()} bubbles")
synchronized(bubbleFile) {
val stream: FileOutputStream = try { bubbleFile.startWrite() } catch (e: IOException) {
Log.e(TAG, "Failed to save bubble file", e)
@@ -37,7 +38,7 @@ class BubblePersistentRepository(context: Context) {
try {
writeXml(stream, bubbles)
bubbleFile.finishWrite(stream)
- if (DEBUG) Log.d(TAG, "persisted ${bubbles.size} bubbles")
+ if (DEBUG) Log.d(TAG, "persisted ${bubbles.size()} bubbles")
return true
} catch (e: Exception) {
Log.e(TAG, "Failed to save bubble file, restoring backup", e)
@@ -47,13 +48,13 @@ class BubblePersistentRepository(context: Context) {
return false
}
- fun readFromDisk(): List<BubbleEntity> {
+ fun readFromDisk(): SparseArray<List<BubbleEntity>> {
synchronized(bubbleFile) {
- if (!bubbleFile.exists()) return emptyList()
+ if (!bubbleFile.exists()) return SparseArray()
try { return bubbleFile.openRead().use(::readXml) } catch (e: Throwable) {
Log.e(TAG, "Failed to open bubble file", e)
}
- return emptyList()
+ return SparseArray()
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
index 7f0b165bdc25..a5267d8be9fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
@@ -17,6 +17,7 @@ package com.android.wm.shell.bubbles.storage
import android.content.pm.LauncherApps
import android.os.UserHandle
+import android.util.SparseArray
import com.android.internal.annotations.VisibleForTesting
import com.android.wm.shell.bubbles.ShortcutKey
@@ -27,10 +28,11 @@ private const val CAPACITY = 16
* manipulation.
*/
class BubbleVolatileRepository(private val launcherApps: LauncherApps) {
+
/**
- * An ordered set of bubbles based on their natural ordering.
+ * Set of bubbles per user. Each set of bubbles is ordered by recency.
*/
- private var entities = mutableSetOf<BubbleEntity>()
+ private var entitiesByUser = SparseArray<MutableList<BubbleEntity>>()
/**
* The capacity of the cache.
@@ -39,19 +41,43 @@ class BubbleVolatileRepository(private val launcherApps: LauncherApps) {
var capacity = CAPACITY
/**
- * Returns a snapshot of all the bubbles.
+ * Returns a snapshot of all the bubbles, a map of the userId to bubble list.
*/
- val bubbles: List<BubbleEntity>
+ val bubbles: SparseArray<List<BubbleEntity>>
@Synchronized
- get() = entities.toList()
+ get() {
+ val map = SparseArray<List<BubbleEntity>>()
+ for (i in 0 until entitiesByUser.size()) {
+ val k = entitiesByUser.keyAt(i)
+ val v = entitiesByUser.valueAt(i)
+ map.put(k, v.toList())
+ }
+ return map
+ }
+
+ /**
+ * Returns the entity list of the provided user's bubbles or creates one if it doesn't exist.
+ */
+ @Synchronized
+ fun getEntities(userId: Int): MutableList<BubbleEntity> {
+ val entities = entitiesByUser.get(userId)
+ return when (entities) {
+ null -> mutableListOf<BubbleEntity>().also {
+ entitiesByUser.put(userId, it)
+ }
+ else -> entities
+ }
+ }
/**
* Add the bubbles to memory and perform a de-duplication. In case a bubble already exists,
* it will be moved to the last.
*/
@Synchronized
- fun addBubbles(bubbles: List<BubbleEntity>) {
+ fun addBubbles(userId: Int, bubbles: List<BubbleEntity>) {
if (bubbles.isEmpty()) return
+ // Get the list for this user
+ var entities = getEntities(userId)
// Verify the size of given bubbles is within capacity, otherwise trim down to capacity
val bubblesInRange = bubbles.takeLast(capacity)
// To ensure natural ordering of the bubbles, removes bubbles which already exist
@@ -61,16 +87,17 @@ class BubbleVolatileRepository(private val launcherApps: LauncherApps) {
if (overflowCount > 0) {
// Uncache ShortcutInfo of bubbles that will be removed due to capacity
uncache(entities.take(overflowCount))
- entities = entities.drop(overflowCount).toMutableSet()
+ entities = entities.drop(overflowCount).toMutableList()
}
entities.addAll(bubblesInRange)
+ entitiesByUser.put(userId, entities)
cache(uniqueBubbles)
}
@Synchronized
- fun removeBubbles(bubbles: List<BubbleEntity>) =
+ fun removeBubbles(userId: Int, bubbles: List<BubbleEntity>) =
uncache(bubbles.filter { b: BubbleEntity ->
- entities.removeIf { e: BubbleEntity -> b.key == e.key } })
+ getEntities(userId).removeIf { e: BubbleEntity -> b.key == e.key } })
private fun cache(bubbles: List<BubbleEntity>) {
bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) ->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
index a74445bba1ab..f4fa1835b7a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
@@ -16,6 +16,8 @@
package com.android.wm.shell.bubbles.storage
import android.app.ActivityTaskManager.INVALID_TASK_ID
+import android.os.UserHandle
+import android.util.SparseArray
import android.util.Xml
import com.android.internal.util.FastXmlSerializer
import com.android.internal.util.XmlUtils
@@ -26,8 +28,8 @@ import java.io.InputStream
import java.io.OutputStream
import java.nio.charset.StandardCharsets
-// TODO: handle version changes gracefully
-private const val CURRENT_VERSION = 1
+// If this number increases, consider bubbles might be restored even with differences in XML.
+private const val CURRENT_VERSION = 2
private const val TAG_BUBBLES = "bs"
private const val ATTR_VERSION = "v"
@@ -46,13 +48,20 @@ private const val ATTR_LOCUS = "l"
* Writes the bubbles in xml format into given output stream.
*/
@Throws(IOException::class)
-fun writeXml(stream: OutputStream, bubbles: List<BubbleEntity>) {
+fun writeXml(stream: OutputStream, bubbles: SparseArray<List<BubbleEntity>>) {
val serializer: XmlSerializer = FastXmlSerializer()
serializer.setOutput(stream, StandardCharsets.UTF_8.name())
serializer.startDocument(null, true)
serializer.startTag(null, TAG_BUBBLES)
serializer.attribute(null, ATTR_VERSION, CURRENT_VERSION.toString())
- bubbles.forEach { b -> writeXmlEntry(serializer, b) }
+ for (i in 0 until bubbles.size()) {
+ val k = bubbles.keyAt(i)
+ val v = bubbles.valueAt(i)
+ serializer.startTag(null, TAG_BUBBLES)
+ serializer.attribute(null, ATTR_USER_ID, k.toString())
+ v.forEach { b -> writeXmlEntry(serializer, b) }
+ serializer.endTag(null, TAG_BUBBLES)
+ }
serializer.endTag(null, TAG_BUBBLES)
serializer.endDocument()
}
@@ -84,16 +93,39 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
/**
* Reads the bubbles from xml file.
*/
-fun readXml(stream: InputStream): List<BubbleEntity> {
- val bubbles = mutableListOf<BubbleEntity>()
+fun readXml(stream: InputStream): SparseArray<List<BubbleEntity>> {
+ val bubbles = SparseArray<List<BubbleEntity>>()
val parser: XmlPullParser = Xml.newPullParser()
parser.setInput(stream, StandardCharsets.UTF_8.name())
XmlUtils.beginDocument(parser, TAG_BUBBLES)
- val version = parser.getAttributeWithName(ATTR_VERSION)?.toInt()
- if (version != null && version == CURRENT_VERSION) {
+ val veryOuterDepth = parser.depth
+ val version = parser.getAttributeWithName(ATTR_VERSION)?.toInt() ?: return bubbles
+ if (version == CURRENT_VERSION) {
+ while (XmlUtils.nextElementWithin(parser, veryOuterDepth)) {
+ val uid = parser.getAttributeWithName(ATTR_USER_ID) ?: continue
+ val outerDepth = parser.depth
+ val userBubbles = mutableListOf<BubbleEntity>()
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ userBubbles.add(readXmlEntry(parser) ?: continue)
+ }
+ if (!userBubbles.isEmpty()) {
+ bubbles.put(uid.toInt(), userBubbles.toList())
+ }
+ }
+ } else if (version == 1) {
+ // upgrade v1 to v2 format
val outerDepth = parser.depth
+ val userBubbles = mutableListOf<BubbleEntity>()
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
- bubbles.add(readXmlEntry(parser) ?: continue)
+ // We can't tell which profile the bubble was for, so we'll only copy the main users'
+ // bubbles on upgrade.
+ val b = readXmlEntry(parser)
+ if (b != null && b.userId == UserHandle.USER_SYSTEM) {
+ userBubbles.add(b)
+ }
+ }
+ if (!userBubbles.isEmpty()) {
+ bubbles.put(UserHandle.USER_SYSTEM, userBubbles.toList())
}
}
return bubbles
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index e3594d0cd367..561dff0da6ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -19,10 +19,14 @@ package com.android.wm.shell.pip;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
+import android.app.PictureInPictureUiState;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Log;
import android.util.Size;
import android.view.Display;
@@ -185,7 +189,18 @@ public final class PipBoundsState {
/** Dictate where PiP currently should be stashed, if at all. */
public void setStashed(@StashType int stashedState) {
+ if (mStashedState == stashedState) {
+ return;
+ }
+
mStashedState = stashedState;
+ try {
+ ActivityTaskManager.getService().onPictureInPictureStateChanged(
+ new PictureInPictureUiState(stashedState != STASH_TYPE_NONE /* isStashed */)
+ );
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to set alert PiP state change.");
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
index 3af0ff0dfb36..97139626a3d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
@@ -21,6 +21,7 @@ import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import android.annotation.DrawableRes;
import android.annotation.StringRes;
+import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.BroadcastReceiver;
@@ -210,13 +211,16 @@ public class PipMediaController {
/**
* Gets the set of media actions currently available.
*/
+ // This is due to using PlaybackState#isActive, which is added in API 31.
+ // It can be removed when min_sdk of the app is set to 31 or greater.
+ @SuppressLint("NewApi")
private List<RemoteAction> getMediaActions() {
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
return Collections.emptyList();
}
ArrayList<RemoteAction> mediaActions = new ArrayList<>();
- boolean isPlaying = mMediaController.getPlaybackState().isActiveState();
+ boolean isPlaying = mMediaController.getPlaybackState().isActive();
long actions = mMediaController.getPlaybackState().getActions();
// Prev action
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 582ff2180c83..3dd97f565179 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -21,6 +21,7 @@ import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.os.SystemProperties;
import android.view.SurfaceControl;
import com.android.wm.shell.R;
@@ -42,7 +43,8 @@ public class PipSurfaceTransactionHelper {
public PipSurfaceTransactionHelper(Context context) {
final Resources res = context.getResources();
- mEnableCornerRadius = res.getBoolean(R.bool.config_pipEnableRoundCorner);
+ mEnableCornerRadius = res.getBoolean(R.bool.config_pipEnableRoundCorner)
+ || SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 3c25a13e94eb..a57e8cdd0928 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -44,6 +44,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
@@ -131,7 +132,8 @@ public class PipMenuView extends FrameLayout {
inflate(context, R.layout.pip_menu, this);
final boolean enableCornerRadius = mContext.getResources()
- .getBoolean(R.bool.config_pipEnableRoundCorner);
+ .getBoolean(R.bool.config_pipEnableRoundCorner)
+ || SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
mBackgroundDrawable = enableCornerRadius
? mContext.getDrawable(R.drawable.pip_menu_background)
: new ColorDrawable(Color.BLACK);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index f29d4f59493e..2a1fe6080cb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -625,6 +625,7 @@ public class PipTouchHandler {
}
mMenuController.handlePointerEvent(cloneEvent);
+ cloneEvent.recycle();
}
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index a47483144fef..dd7e29451ffc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -50,6 +50,7 @@ public class TvPipNotificationController {
// Referenced in com.android.systemui.util.NotificationChannels.
public static final String NOTIFICATION_CHANNEL = "TVPIP";
private static final String NOTIFICATION_TAG = "TvPip";
+ private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
private static final String ACTION_SHOW_PIP_MENU =
"com.android.wm.shell.pip.tv.notification.action.SHOW_PIP_MENU";
@@ -207,7 +208,8 @@ public class TvPipNotificationController {
}
private static PendingIntent createPendingIntent(Context context, String action) {
- return PendingIntent.getBroadcast(context, 0, new Intent(action),
+ return PendingIntent.getBroadcast(context, 0,
+ new Intent(action).setPackage(context.getPackageName()),
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
@@ -223,7 +225,7 @@ public class TvPipNotificationController {
void register() {
if (mRegistered) return;
- mContext.registerReceiverForAllUsers(this, mIntentFilter, null /* permission */,
+ mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
mMainHandler);
mRegistered = true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 147f2e2ec846..f3ae0a1bf717 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -109,11 +109,12 @@ public class SplashscreenContentDrawer {
* view on background thread so the view and the drawable can be create and pre-draw in
* parallel.
*
+ * @param emptyView Create a splash screen view without icon on it.
* @param consumer Receiving the SplashScreenView object, which will also be executed
* on splash screen thread. Note that the view can be null if failed.
*/
- void createContentView(Context context, int splashScreenResId, ActivityInfo info,
- int taskId, Consumer<SplashScreenView> consumer) {
+ void createContentView(Context context, boolean emptyView, int splashScreenResId,
+ ActivityInfo info, int taskId, Consumer<SplashScreenView> consumer) {
mSplashscreenWorkerHandler.post(() -> {
SplashScreenView contentView;
try {
@@ -121,7 +122,11 @@ public class SplashscreenContentDrawer {
context, splashScreenResId);
if (contentView == null) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView");
- contentView = makeSplashScreenContentView(context, info);
+ if (emptyView) {
+ contentView = makeEmptySplashScreenContentView(context);
+ } else {
+ contentView = makeSplashScreenContentView(context, info);
+ }
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
} catch (RuntimeException e) {
@@ -190,6 +195,18 @@ public class SplashscreenContentDrawer {
}
}
+ private SplashScreenView makeEmptySplashScreenContentView(Context context) {
+ getWindowAttrs(context, mTmpAttrs);
+ final StartingWindowViewBuilder builder = new StartingWindowViewBuilder();
+ final int themeBGColor = peekWindowBGColor(context);
+ final SplashScreenView view = builder
+ .setContext(context)
+ .setWindowBGColor(themeBGColor)
+ .build();
+ view.setNotCopyable();
+ return view;
+ }
+
private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai) {
updateDensity();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 7037d18decbe..e4b28696bc4f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -317,46 +317,38 @@ public class StartingSurfaceDrawer {
// 3. Pre-draw the BitmapShader if the icon is immobile on splash screen worker thread, at
// the same time the splash screen thread should be executing Session#relayout. Blocking the
// traversal -> draw on splash screen thread until the BitmapShader of the icon is ready.
- final Runnable setViewSynchronized;
- if (!emptyView) {
- // Record whether create splash screen view success, notify to current thread after
- // create splash screen view finished.
- final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
- setViewSynchronized = () -> {
- // waiting for setContentView before relayoutWindow
- SplashScreenView contentView = viewSupplier.get();
- final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
- // if record == null, either the starting window added fail or removed already.
- if (record != null) {
- // if view == null then creation of content view was failed.
- if (contentView != null) {
- try {
- win.setContentView(contentView);
- contentView.cacheRootWindow(win);
- } catch (RuntimeException e) {
- Slog.w(TAG, "failed set content view to starting window "
- + "at taskId: " + taskId, e);
- contentView = null;
- }
+
+ // Record whether create splash screen view success, notify to current thread after
+ // create splash screen view finished.
+ final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
+ final Runnable setViewSynchronized = () -> {
+ // waiting for setContentView before relayoutWindow
+ SplashScreenView contentView = viewSupplier.get();
+ final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+ // if record == null, either the starting window added fail or removed already.
+ if (record != null) {
+ // if view == null then creation of content view was failed.
+ if (contentView != null) {
+ try {
+ win.setContentView(contentView);
+ contentView.cacheRootWindow(win);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "failed set content view to starting window "
+ + "at taskId: " + taskId, e);
+ contentView = null;
}
- record.setSplashScreenView(contentView);
}
- };
- mSplashscreenContentDrawer.createContentView(context,
- splashscreenContentResId[0], activityInfo, taskId, viewSupplier::setView);
- } else {
- setViewSynchronized = null;
- }
+ record.setSplashScreenView(contentView);
+ }
+ };
+ mSplashscreenContentDrawer.createContentView(context, emptyView,
+ splashscreenContentResId[0], activityInfo, taskId, viewSupplier::setView);
try {
final View view = win.getDecorView();
final WindowManager wm = mContext.getSystemService(WindowManager.class);
postAddWindow(taskId, appToken, view, wm, params);
- // all done
- if (emptyView) {
- return;
- }
// We use the splash screen worker thread to create SplashScreenView while adding the
// window, as otherwise Choreographer#doFrame might be delayed on this thread.
// And since Choreographer#doFrame won't happen immediately after adding the window, if
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index 6494f89997e5..91d51de3a872 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -74,12 +74,6 @@ class EnterSplitScreenDockActivity(
@Test
fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
- @FlakyTest(bugId = 178531736)
- @Test
- // b/178531736
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
@Presubmit
@Test
fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsAlwaysVisible()
@@ -88,12 +82,6 @@ class EnterSplitScreenDockActivity(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @FlakyTest(bugId = 178531736)
- @Test
- // b/178531736
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Presubmit
@Test
fun appWindowIsVisible() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index 9000f22fb03d..f975ed92e872 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -83,13 +83,6 @@ class EnterSplitScreenLaunchToSide(
// b/169271943
fun dockedStackDividerBecomesVisible() = testSpec.dockedStackDividerBecomesVisible()
- @FlakyTest(bugId = 178447631)
- @Test
- // TODO(b/178447631) Remove Splash Screen from white list when flicker lib
- // add a wait for splash screen be gone
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
@Presubmit
@Test
fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp.defaultWindowName)
@@ -102,11 +95,6 @@ class EnterSplitScreenLaunchToSide(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Presubmit
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index 7d22d4dbe5ab..6bc9a5c5982c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Postsubmit
import android.provider.Settings
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -97,25 +96,9 @@ class EnterSplitScreenNotSupportNonResizable(
prevSupportNonResizableInMultiWindow)
}
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Test
fun dockedStackDividerIsInvisible() = testSpec.dockedStackDividerIsInvisible()
- @Test
- fun appWindowIsVisible() {
- testSpec.assertWmEnd {
- isInvisible(nonResizeableApp.defaultWindowName)
- }
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
index 9b4a10389619..91ca7c1d2a72 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Postsubmit
import android.provider.Settings
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -92,15 +91,6 @@ class EnterSplitScreenSupportNonResizable(
prevSupportNonResizableInMultiWindow)
}
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Test
fun dockedStackDividerIsVisible() = testSpec.dockedStackDividerIsVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index 64cc85340a38..faf7aa75a1de 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -78,12 +78,6 @@ class ExitLegacySplitScreenFromBottom(
@Test
fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(DOCKED_STACK_DIVIDER)
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
@FlakyTest
@Test
fun appWindowBecomesInVisible() =
@@ -97,11 +91,6 @@ class ExitLegacySplitScreenFromBottom(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 2e115518721f..8845777dda6e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -82,11 +82,6 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen(
@Test
fun layerBecomesInvisible() = testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
@FlakyTest
@Test
fun appWindowBecomesInVisible() =
@@ -100,11 +95,6 @@ class ExitPrimarySplitScreenShowSecondaryFullscreen(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
index 892384561eb2..968aff1ce572 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Postsubmit
import android.provider.Settings
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -96,16 +95,6 @@ class LegacySplitScreenFromIntentNotSupportNonResizable(
prevSupportNonResizableInMultiWindow)
}
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Test
fun resizableAppLayerBecomesInvisible() =
testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
index 2f5e0bddd71f..8d206730b436 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Postsubmit
import android.provider.Settings
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -94,16 +93,6 @@ class LegacySplitScreenFromIntentSupportNonResizable(
prevSupportNonResizableInMultiWindow)
}
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Test
fun nonResizableAppLayerBecomesVisible() =
testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
index a42774d93b5b..4e291d9ef9f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Postsubmit
import android.provider.Settings
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -97,16 +96,6 @@ class LegacySplitScreenFromRecentNotSupportNonResizable(
prevSupportNonResizableInMultiWindow)
}
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Test
fun resizableAppLayerBecomesInvisible() =
testSpec.layerBecomesInvisible(splitScreenApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
index 14f6deef6ff4..880dc5567d8a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
@@ -19,7 +19,6 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.platform.test.annotations.Postsubmit
import android.provider.Settings
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -95,16 +94,6 @@ class LegacySplitScreenFromRecentSupportNonResizable(
prevSupportNonResizableInMultiWindow)
}
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@Test
fun nonResizableAppLayerBecomesVisible() =
testSpec.layerBecomesVisible(nonResizeableApp.defaultWindowName)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
index 08d5db0f9124..1e89a25c06df 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenRotateTransition.kt
@@ -17,13 +17,11 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.view.Surface
-import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import org.junit.Test
abstract class LegacySplitScreenRotateTransition(
testSpec: FlickerTestParameter
@@ -46,16 +44,4 @@ abstract class LegacySplitScreenRotateTransition(
}
}
}
-
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @FlakyTest
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 39f4ce298ff5..976668e60231 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -118,11 +118,6 @@ class LegacySplitScreenToLauncher(
fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
- @FlakyTest
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
@Presubmit
@Test
fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsAlwaysVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
index e13056c36684..8684ba52bd52 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenTransition.kt
@@ -18,9 +18,9 @@ package com.android.wm.shell.flicker.legacysplitscreen
import android.app.Instrumentation
import android.content.Context
-import android.platform.test.annotations.Presubmit
import android.support.test.launcherhelper.LauncherStrategyFactory
import android.view.Surface
+import androidx.test.filters.FlakyTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerBuilderProvider
import com.android.server.wm.flicker.FlickerTestParameter
@@ -102,7 +102,7 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa
}
}
- @Presubmit
+ @FlakyTest(bugId = 178447631)
@Test
open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
testSpec.assertWm {
@@ -110,7 +110,7 @@ abstract class LegacySplitScreenTransition(protected val testSpec: FlickerTestPa
}
}
- @Presubmit
+ @FlakyTest(bugId = 178447631)
@Test
open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 7cf30ec116eb..69520c291522 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -65,11 +65,6 @@ class OpenAppToLegacySplitScreen(
WindowManagerStateHelper.SPLASH_SCREEN_NAME,
WindowManagerStateHelper.SNAPSHOT_WINDOW_NAME)
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
- super.visibleWindowsShownMoreThanOneConsecutiveEntry()
-
@FlakyTest
@Test
fun appWindowBecomesVisible() = testSpec.appWindowBecomesVisible(splitScreenApp.getPackage())
@@ -90,11 +85,6 @@ class OpenAppToLegacySplitScreen(
@Test
fun layerBecomesVisible() = testSpec.layerBecomesVisible(splitScreenApp.getPackage())
- @FlakyTest(bugId = 178447631)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
@FlakyTest(bugId = 151179149)
@Test
fun focusChanges() = testSpec.focusChanges(splitScreenApp.`package`,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index 33ade38d0373..ecbb887e2f9b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -104,13 +104,6 @@ class ResizeLegacySplitScreen(
@Test
fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
- @Test
- override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
- testSpec.assertWm {
- this.visibleWindowsShownMoreThanOneConsecutiveEntry()
- }
- }
-
@FlakyTest(bugId = 156223549)
@Test
fun topAppWindowIsAlwaysVisible() {
@@ -145,10 +138,6 @@ class ResizeLegacySplitScreen(
testSpec.statusBarLayerRotatesScales(testSpec.config.endRotation)
@Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
- @Test
fun topAppLayerIsAlwaysVisible() {
testSpec.assertLayers {
this.isVisible(sSimpleActivity)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index 2f064ac95204..0972cf2c032f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -18,8 +18,10 @@ package com.android.wm.shell.bubbles.storage
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.testing.AndroidTestingRunner
+import android.util.SparseArray
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.bubbles.storage.BubbleXmlHelperTest.Companion.sparseArraysEqual
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
@@ -31,19 +33,32 @@ import org.junit.runner.RunWith
@RunWith(AndroidTestingRunner::class)
class BubblePersistentRepositoryTest : ShellTestCase() {
- private val bubbles = listOf(
- // user, package, shortcut, notification key, height, res-height, title, taskId, locusId
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0, null, 1, null),
- BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428, "title",
- 2, null),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0, null,
- INVALID_TASK_ID, "key-3")
+ // user, package, shortcut, notification key, height, res-height, title, taskId, locusId
+ private val user0Bubbles = listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "0k1", 120, 0, null, 1, null),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "0k2", 0, 16537428, "title", 2,
+ null),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "0k3", 120, 0, null,
+ INVALID_TASK_ID, null)
)
+
+ private val user1Bubbles = listOf(
+ BubbleEntity(1, "com.example.messenger", "shortcut-1", "1k1", 120, 0, null, 3, null),
+ BubbleEntity(12, "com.example.chat", "alice and bob", "1k2", 0, 16537428, "title", 4,
+ null),
+ BubbleEntity(1, "com.example.messenger", "shortcut-2", "1k3", 120, 0, null,
+ INVALID_TASK_ID, null)
+ )
+
+ private val bubbles = SparseArray<List<BubbleEntity>>()
+
private lateinit var repository: BubblePersistentRepository
@Before
fun setup() {
repository = BubblePersistentRepository(mContext)
+ bubbles.put(0, user0Bubbles)
+ bubbles.put(1, user1Bubbles)
}
@Test
@@ -51,9 +66,9 @@ class BubblePersistentRepositoryTest : ShellTestCase() {
// Verify read before write doesn't cause FileNotFoundException
val actual = repository.readFromDisk()
assertNotNull(actual)
- assertTrue(actual.isEmpty())
+ assertEquals(actual.size(), 0)
repository.persistsToDisk(bubbles)
- assertEquals(bubbles, repository.readFromDisk())
+ assertTrue(sparseArraysEqual(bubbles, repository.readFromDisk()))
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index 03aa6c2eba12..bfdf5208bbf0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -21,32 +21,40 @@ import android.content.pm.LauncherApps
import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
+import org.junit.Test
import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import org.junit.Before
-import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.reset
@SmallTest
@RunWith(AndroidTestingRunner::class)
class BubbleVolatileRepositoryTest : ShellTestCase() {
private val user0 = UserHandle.of(0)
- private val user10 = UserHandle.of(10)
+ private val user10_managed = UserHandle.of(10) // In test, acts as workprofile of user0
+ private val user11 = UserHandle.of(11)
// user, package, shortcut, notification key, height, res-height, title, taskId, locusId
- private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0,
- null, 1, null)
+ private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1",
+ "0key-1", 120, 0, null, 1, null)
private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob",
- "key-2", 0, 16537428, "title", 2, null)
- private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0,
- null, INVALID_TASK_ID, "key-3")
+ "10key-2", 0, 16537428, "title", 2, null)
+ private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2",
+ "0key-3", 120, 0, null, INVALID_TASK_ID, null)
- private val bubbles = listOf(bubble1, bubble2, bubble3)
+ private val bubble11 = BubbleEntity(11, "com.example.messenger",
+ "shortcut-1", "01key-1", 120, 0, null, 3)
+ private val bubble12 = BubbleEntity(11, "com.example.chat", "alice and bob",
+ "11key-2", 0, 16537428, "title", INVALID_TASK_ID)
+
+ private val user0bubbles = listOf(bubble1, bubble2, bubble3)
+ private val user11bubbles = listOf(bubble11, bubble12)
private lateinit var repository: BubbleVolatileRepository
private lateinit var launcherApps: LauncherApps
@@ -59,51 +67,74 @@ class BubbleVolatileRepositoryTest : ShellTestCase() {
@Test
fun testAddBubbles() {
- repository.addBubbles(bubbles)
- assertEquals(bubbles, repository.bubbles)
+ repository.addBubbles(user0.identifier, user0bubbles)
+ repository.addBubbles(user11.identifier, user11bubbles)
+
+ assertEquals(user0bubbles, repository.getEntities(user0.identifier).toList())
+ assertEquals(user11bubbles, repository.getEntities(user11.identifier).toList())
+
verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER),
eq(listOf("shortcut-1", "shortcut-2")), eq(user0),
eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
verify(launcherApps).cacheShortcuts(eq(PKG_CHAT),
- eq(listOf("alice and bob")), eq(user10),
+ eq(listOf("alice and bob")), eq(user10_managed),
+ eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
+
+ verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER),
+ eq(listOf("shortcut-1")), eq(user11),
+ eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
+ verify(launcherApps).cacheShortcuts(eq(PKG_CHAT),
+ eq(listOf("alice and bob")), eq(user11),
eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
- repository.addBubbles(listOf(bubble1))
- assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles)
- verifyNoMoreInteractions(launcherApps)
+ repository.addBubbles(user0.identifier, listOf(bubble1))
+ assertEquals(listOf(bubble2, bubble3, bubble1), repository.getEntities(user0.identifier))
+
+ repository.addBubbles(user11.identifier, listOf(bubble12))
+ assertEquals(listOf(bubble11, bubble12), repository.getEntities(user11.identifier))
+
+ Mockito.verifyNoMoreInteractions(launcherApps)
}
@Test
fun testRemoveBubbles() {
- repository.addBubbles(bubbles)
- assertEquals(bubbles, repository.bubbles)
+ repository.addBubbles(user0.identifier, user0bubbles)
+ repository.addBubbles(user11.identifier, user11bubbles)
- repository.removeBubbles(listOf(bubble3))
- assertEquals(listOf(bubble1, bubble2), repository.bubbles)
+ repository.removeBubbles(user0.identifier, listOf(bubble3))
+ assertEquals(listOf(bubble1, bubble2), repository.getEntities(user0.identifier).toList())
verify(launcherApps).uncacheShortcuts(eq(PKG_MESSENGER),
eq(listOf("shortcut-2")), eq(user0),
eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
+
+ reset(launcherApps)
+
+ repository.removeBubbles(user11.identifier, listOf(bubble12))
+ assertEquals(listOf(bubble11), repository.getEntities(user11.identifier).toList())
+ verify(launcherApps).uncacheShortcuts(eq(PKG_CHAT),
+ eq(listOf("alice and bob")), eq(user11),
+ eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
}
@Test
fun testAddAndRemoveBubblesWhenExceedingCapacity() {
repository.capacity = 2
// push bubbles beyond capacity
- repository.addBubbles(bubbles)
+ repository.addBubbles(user0.identifier, user0bubbles)
// verify it is trim down to capacity
- assertEquals(listOf(bubble2, bubble3), repository.bubbles)
+ assertEquals(listOf(bubble2, bubble3), repository.getEntities(user0.identifier).toList())
verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER),
eq(listOf("shortcut-2")), eq(user0),
eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
verify(launcherApps).cacheShortcuts(eq(PKG_CHAT),
- eq(listOf("alice and bob")), eq(user10),
+ eq(listOf("alice and bob")), eq(user10_managed),
eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
- repository.addBubbles(listOf(bubble1))
- // verify the oldest bubble is popped
- assertEquals(listOf(bubble3, bubble1), repository.bubbles)
+ repository.addBubbles(user0.identifier, listOf(bubble1))
+ // verify the oldest bubble is popped 2, 3
+ assertEquals(listOf(bubble3, bubble1), repository.getEntities(user0.identifier).toList())
verify(launcherApps).uncacheShortcuts(eq(PKG_CHAT),
- eq(listOf("alice and bob")), eq(user10),
+ eq(listOf("alice and bob")), eq(user10_managed),
eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS))
}
@@ -111,14 +142,14 @@ class BubbleVolatileRepositoryTest : ShellTestCase() {
fun testAddBubbleMatchesByKey() {
val bubble = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0, "title",
1, null)
- repository.addBubbles(listOf(bubble))
- assertEquals(bubble, repository.bubbles.get(0))
+ repository.addBubbles(user0.identifier, listOf(bubble))
+ assertEquals(bubble, repository.getEntities(user0.identifier).get(0))
// Same key as first bubble but different entry
val bubbleModified = BubbleEntity(0, "com.example.pkg", "shortcut-id", "key", 120, 0,
- "different title", 2, null)
- repository.addBubbles(listOf(bubbleModified))
- assertEquals(bubbleModified, repository.bubbles.get(0))
+ "different title", 2)
+ repository.addBubbles(user0.identifier, listOf(bubbleModified))
+ assertEquals(bubbleModified, repository.getEntities(user0.identifier).get(0))
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
index 8d719e7a7378..4ab9f87dbbf6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
@@ -18,10 +18,12 @@ package com.android.wm.shell.bubbles.storage
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.testing.AndroidTestingRunner
+import android.util.SparseArray
import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.ByteArrayInputStream
@@ -31,21 +33,65 @@ import java.io.ByteArrayOutputStream
@RunWith(AndroidTestingRunner::class)
class BubbleXmlHelperTest : ShellTestCase() {
- private val bubbles = listOf(
- // user, package, shortcut, notification key, height, res-height, title, taskId, locusId
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null, 1),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title",
- 2, null),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
+ private val user0Bubbles = listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "0k1", 120, 0, null, 1),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "0k2", 0, 16537428, "title", 2,
+ null),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "0k3", 120, 0, null,
INVALID_TASK_ID, "l3")
)
+ private val user1Bubbles = listOf(
+ BubbleEntity(1, "com.example.messenger", "shortcut-1", "1k1", 120, 0, null, 3),
+ BubbleEntity(12, "com.example.chat", "alice and bob", "1k2", 0, 16537428, "title", 4,
+ null),
+ BubbleEntity(1, "com.example.messenger", "shortcut-2", "1k3", 120, 0, null,
+ INVALID_TASK_ID, "l4")
+ )
+
+ private val bubbles = SparseArray<List<BubbleEntity>>()
+
+ // Checks that the contents of the two sparse arrays are the same.
+ companion object {
+ fun sparseArraysEqual(
+ one: SparseArray<List<BubbleEntity>>?,
+ two: SparseArray<List<BubbleEntity>>?
+ ): Boolean {
+ if (one == null && two == null) return true
+ if ((one == null) != (two == null)) return false
+ if (one!!.size() != two!!.size()) return false
+ for (i in 0 until one.size()) {
+ val k1 = one.keyAt(i)
+ val v1 = one.valueAt(i)
+ val k2 = two.keyAt(i)
+ val v2 = two.valueAt(i)
+ if (k1 != k2 && v1 != v2) {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ @Before
+ fun setup() {
+ bubbles.put(0, user0Bubbles)
+ bubbles.put(1, user1Bubbles)
+ }
+
@Test
fun testWriteXml() {
val expectedEntries = """
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" l="l3" />
+<bs uid="0">
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="0k1" h="120" hid="0" tid="1" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="0k2" h="0" hid="16537428" t="title" tid="2" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="0k3" h="120" hid="0" tid="-1" l="l3" />
+</bs>
+<bs uid="1">
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-1" key="1k1" h="120" hid="0" tid="3" />
+<bb uid="12" pkg="com.example.chat" sid="alice and bob" key="1k2" h="0" hid="16537428" t="title" tid="4" />
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-2" key="1k3" h="120" hid="0" tid="-1" l="l4" />
+</bs>
""".trimIndent()
ByteArrayOutputStream().use {
writeXml(it, bubbles)
@@ -59,19 +105,26 @@ class BubbleXmlHelperTest : ShellTestCase() {
fun testReadXml() {
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<bs v="1">
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" tid="1" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" tid="2" />
-<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" tid="-1" l="l3" />
+<bs v="2">
+<bs uid="0">
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="0k1" h="120" hid="0" tid="1" />
+<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="0k2" h="0" hid="16537428" t="title" tid="2" />
+<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="0k3" h="120" hid="0" tid="-1" l="l3" />
+</bs>
+<bs uid="1">
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-1" key="1k1" h="120" hid="0" tid="3" />
+<bb uid="12" pkg="com.example.chat" sid="alice and bob" key="1k2" h="0" hid="16537428" t="title" tid="4" />
+<bb uid="1" pkg="com.example.messenger" sid="shortcut-2" key="1k3" h="120" hid="0" tid="-1" l="l4" />
+</bs>
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
- assertEquals("failed parsing bubbles from xml\n$src", bubbles, actual)
+ assertTrue("failed parsing bubbles from xml\n$src", sparseArraysEqual(bubbles, actual))
}
- // TODO: We should handle upgrades gracefully but this is v1
+ // V0 -> V1 happened prior to release / during dogfood so nothing is saved
@Test
- fun testUpgradeDropsPreviousData() {
+ fun testUpgradeFromV0DropsPreviousData() {
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<bs>
@@ -81,7 +134,7 @@ class BubbleXmlHelperTest : ShellTestCase() {
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
- assertEquals("failed parsing bubbles from xml\n$src", emptyList<BubbleEntity>(), actual)
+ assertEquals("failed parsing bubbles from xml\n$src", 0, actual.size())
}
/**
@@ -91,24 +144,25 @@ class BubbleXmlHelperTest : ShellTestCase() {
*/
@Test
fun testReadXMLWithoutTaskId() {
- val expectedBubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null,
- INVALID_TASK_ID),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title",
- INVALID_TASK_ID),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
- INVALID_TASK_ID)
- )
+ val expectedBubbles = SparseArray<List<BubbleEntity>>()
+ expectedBubbles.put(0, listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0,
+ null, INVALID_TASK_ID),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0,
+ null, INVALID_TASK_ID))
+ )
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<bs v="1">
+<bs v="2">
+<bs uid="0">
<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
</bs>
+</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
- assertEquals("failed parsing bubbles from xml\n$src", expectedBubbles, actual)
+ assertTrue("failed parsing bubbles from xml\n$src",
+ sparseArraysEqual(expectedBubbles, actual))
}
/**
@@ -117,23 +171,45 @@ class BubbleXmlHelperTest : ShellTestCase() {
*/
@Test
fun testXMLWithoutLocusToLocus() {
- val expectedBubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0, null,
- INVALID_TASK_ID, null),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428, "title",
- INVALID_TASK_ID, null),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0, null,
- INVALID_TASK_ID, null)
+ val expectedBubbles = SparseArray<List<BubbleEntity>>()
+ expectedBubbles.put(0, listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0,
+ null, INVALID_TASK_ID),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0,
+ null, INVALID_TASK_ID))
)
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<bs v="1">
<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
-<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
- assertEquals("failed parsing bubbles from xml\n$src", expectedBubbles, actual)
+ assertTrue("failed parsing bubbles from xml\n$src",
+ sparseArraysEqual(expectedBubbles, actual))
+ }
+
+ @Test
+ fun testUpgradeToV2SavesPreviousData() {
+ val src = """
+ <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+ <bs v="1">
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" t="title" />
+ <bb uid="2" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-4" key="k4" h="0" hid="16537428" />
+ </bs>
+ """.trimIndent()
+ val expectedBubbles = SparseArray<List<BubbleEntity>>()
+ expectedBubbles.put(0, listOf(
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0,
+ null, INVALID_TASK_ID, null),
+ BubbleEntity(0, "com.example.messenger", "shortcut-4", "k4", 0, 16537428,
+ null, INVALID_TASK_ID, null))
+ )
+ val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
+ assertTrue("failed parsing bubbles from xml\n$src",
+ sparseArraysEqual(expectedBubbles, actual))
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index dea24d3c2ec0..a6215d3347a8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -38,6 +38,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.function.Consumer;
+
/**
* Tests for {@link PipBoundsState}.
*/
@@ -178,4 +180,20 @@ public class PipBoundsStateTest extends ShellTestCase {
mPipBoundsState.setOverrideMinSize(new Size(15, 10));
assertEquals(10, mPipBoundsState.getOverrideMinEdgeSize());
}
+
+ @Test
+ public void testSetBounds_updatesPipExclusionBounds() {
+ final Consumer<Rect> callback = mock(Consumer.class);
+ final Rect currentBounds = new Rect(10, 10, 20, 15);
+ final Rect newBounds = new Rect(50, 50, 100, 75);
+ mPipBoundsState.setBounds(currentBounds);
+
+ mPipBoundsState.setPipExclusionBoundsChangeCallback(callback);
+ // Setting the listener immediately calls back with the current bounds.
+ verify(callback).accept(currentBounds);
+
+ mPipBoundsState.setBounds(newBounds);
+ // Updating the bounds makes the listener call back back with the new rect.
+ verify(callback).accept(newBounds);
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 5df391f919a7..9d7c82bb8550 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.pip;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -31,6 +32,7 @@ import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -222,6 +224,16 @@ public class PipTaskOrganizerTest extends ShellTestCase {
assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
}
+ @Test
+ public void onTaskVanished_clearsPipBounds() {
+ mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
+ createPipParams(null)), null /* leash */);
+ mPipBoundsState.setBounds(new Rect(100, 100, 200, 150));
+
+ mSpiedPipTaskOrganizer.onTaskVanished(createTaskInfo(mComponent1, createPipParams(null)));
+ assertTrue(mPipBoundsState.getBounds().isEmpty());
+ }
+
private void preparePipTaskOrg() {
final DisplayInfo info = new DisplayInfo();
mPipBoundsState.setDisplayLayout(new DisplayLayout(info,