Sysui bubbles multiuser fixes: persistence / overflow
* Persist bubbles per-user - rather than one list the XML now has a list per-user. The entries in these lists still include userId for workprofile since bubbles are mixed in the stack / overflow for workprofile. * When loading bubbles, only the ones for the current user are loaded / hit bubbleController code * When user changes, overflow data should be re-loaded * Allow the bubble window to be visible for all users Test: atest BubbleXmlHelperTest BubbleVolatileRepositoryTest BubblePersistentRepositoryTest BubblesTest Bug: 173408780 Change-Id: I88cb7cc7ee676d8e0756328a95a54fdaf018a013
This commit is contained in:
@@ -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);
|
||||
mBubbleData.dismissAll(DISMISS_USER_CHANGED);
|
||||
restoreBubbles(newUserId);
|
||||
mCurrentUserId = newUserId;
|
||||
|
||||
mBubbleData.dismissAll(DISMISS_USER_CHANGED);
|
||||
mBubbleData.clearOverflow();
|
||||
mOverflowDataLoadNeeded = true;
|
||||
|
||||
restoreBubbles(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()) {
|
||||
@@ -1427,6 +1455,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(() -> {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -217,10 +217,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -213,6 +215,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.
|
||||
*
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) ->
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
repository.addBubbles(listOf(bubble1))
|
||||
assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles)
|
||||
verifyNoMoreInteractions(launcherApps)
|
||||
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(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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -48,6 +49,7 @@ import android.service.notification.ZenModeConfig;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -247,6 +249,12 @@ public class BubblesManager implements Dumpable {
|
||||
public void onUserChanged(int userId) {
|
||||
mBubbles.onUserChanged(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {
|
||||
mBubbles.onCurrentProfilesChanged(currentProfiles);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
mSysuiProxy = new Bubbles.SysuiProxy() {
|
||||
|
||||
@@ -236,49 +236,15 @@ public class NotificationTestHelper {
|
||||
return createRow(PKG, UID, USER_HANDLE, false /* isGroupSummary */, groupkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
|
||||
*/
|
||||
public ExpandableNotificationRow createBubbleInGroup()
|
||||
throws Exception {
|
||||
return createBubble(makeBubbleMetadata(null), PKG, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
|
||||
*/
|
||||
public ExpandableNotificationRow createBubble()
|
||||
throws Exception {
|
||||
return createBubble(makeBubbleMetadata(null), PKG, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
|
||||
*
|
||||
* @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
|
||||
*/
|
||||
public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent)
|
||||
throws Exception {
|
||||
return createBubble(makeBubbleMetadata(deleteIntent), PKG, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
|
||||
*
|
||||
* @param bubbleMetadata the {@link BubbleMetadata} to use
|
||||
*/
|
||||
public ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata, String pkg)
|
||||
throws Exception {
|
||||
return createBubble(bubbleMetadata, pkg, false);
|
||||
}
|
||||
|
||||
private ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata, String pkg,
|
||||
boolean inGroup)
|
||||
throws Exception {
|
||||
Notification n = createNotification(false /* isGroupSummary */,
|
||||
inGroup ? GROUP_KEY : null /* groupKey */, bubbleMetadata);
|
||||
null /* groupKey */, makeBubbleMetadata(null));
|
||||
n.flags |= FLAG_BUBBLE;
|
||||
ExpandableNotificationRow row = generateRow(n, pkg, UID, USER_HANDLE,
|
||||
ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
|
||||
0 /* extraInflationFlags */, IMPORTANCE_HIGH);
|
||||
modifyRanking(row.getEntry())
|
||||
.setCanBubble(true)
|
||||
@@ -286,6 +252,76 @@ public class NotificationTestHelper {
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ExpandableNotificationRow} that should be shown as a bubble and is part
|
||||
* of a group of notifications.
|
||||
*/
|
||||
public ExpandableNotificationRow createBubbleInGroup()
|
||||
throws Exception {
|
||||
Notification n = createNotification(false /* isGroupSummary */,
|
||||
GROUP_KEY /* groupKey */, makeBubbleMetadata(null));
|
||||
n.flags |= FLAG_BUBBLE;
|
||||
ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
|
||||
0 /* extraInflationFlags */, IMPORTANCE_HIGH);
|
||||
modifyRanking(row.getEntry())
|
||||
.setCanBubble(true)
|
||||
.build();
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link NotificationEntry} that should be shown as a bubble.
|
||||
*
|
||||
* @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
|
||||
*/
|
||||
public NotificationEntry createBubble(@Nullable PendingIntent deleteIntent) {
|
||||
return createBubble(makeBubbleMetadata(deleteIntent), USER_HANDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link NotificationEntry} that should be shown as a bubble.
|
||||
*
|
||||
* @param handle the user to associate with this bubble.
|
||||
*/
|
||||
public NotificationEntry createBubble(UserHandle handle) {
|
||||
return createBubble(makeBubbleMetadata(null), handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link NotificationEntry} that should be shown as a bubble.
|
||||
*
|
||||
* @param userHandle the user to associate with this notification.
|
||||
*/
|
||||
private NotificationEntry createBubble(BubbleMetadata metadata, UserHandle userHandle) {
|
||||
Notification n = createNotification(false /* isGroupSummary */, null /* groupKey */,
|
||||
metadata);
|
||||
n.flags |= FLAG_BUBBLE;
|
||||
|
||||
final NotificationChannel channel =
|
||||
new NotificationChannel(
|
||||
n.getChannelId(),
|
||||
n.getChannelId(),
|
||||
IMPORTANCE_HIGH);
|
||||
channel.setBlockable(true);
|
||||
|
||||
NotificationEntry entry = new NotificationEntryBuilder()
|
||||
.setPkg(PKG)
|
||||
.setOpPkg(PKG)
|
||||
.setId(mId++)
|
||||
.setUid(UID)
|
||||
.setInitialPid(2000)
|
||||
.setNotification(n)
|
||||
.setUser(userHandle)
|
||||
.setPostTime(System.currentTimeMillis())
|
||||
.setChannel(channel)
|
||||
.build();
|
||||
|
||||
modifyRanking(entry)
|
||||
.setCanBubble(true)
|
||||
.build();
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification row with the given details.
|
||||
*
|
||||
|
||||
@@ -49,6 +49,7 @@ import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserHandle;
|
||||
import android.service.dreams.IDreamManager;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
@@ -172,14 +173,17 @@ public class BubblesTest extends SysuiTestCase {
|
||||
private NotificationRemoveInterceptor mRemoveInterceptor;
|
||||
|
||||
private NotificationTestHelper mNotificationTestHelper;
|
||||
private ExpandableNotificationRow mRow;
|
||||
private ExpandableNotificationRow mRow2;
|
||||
private ExpandableNotificationRow mRow3;
|
||||
private NotificationEntry mRow;
|
||||
private NotificationEntry mRow2;
|
||||
private NotificationEntry mRow3;
|
||||
private ExpandableNotificationRow mNonBubbleNotifRow;
|
||||
private BubbleEntry mBubbleEntry;
|
||||
private BubbleEntry mBubbleEntry2;
|
||||
private BubbleEntry mBubbleEntry3;
|
||||
|
||||
private BubbleEntry mBubbleEntryUser11;
|
||||
private BubbleEntry mBubbleEntry2User11;
|
||||
|
||||
@Mock
|
||||
private Bubbles.BubbleExpandListener mBubbleExpandListener;
|
||||
@Mock
|
||||
@@ -245,14 +249,20 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mRow3 = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
|
||||
mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow.getEntry());
|
||||
mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2.getEntry());
|
||||
mBubbleEntry3 = BubblesManager.notifToBubbleEntry(mRow3.getEntry());
|
||||
mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow);
|
||||
mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2);
|
||||
mBubbleEntry3 = BubblesManager.notifToBubbleEntry(mRow3);
|
||||
|
||||
UserHandle handle = mock(UserHandle.class);
|
||||
when(handle.getIdentifier()).thenReturn(11);
|
||||
mBubbleEntryUser11 = BubblesManager.notifToBubbleEntry(
|
||||
mNotificationTestHelper.createBubble(handle));
|
||||
mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry(
|
||||
mNotificationTestHelper.createBubble(handle));
|
||||
|
||||
// Return non-null notification data from the NEM
|
||||
when(mNotificationEntryManager
|
||||
.getActiveNotificationUnfiltered(mRow.getEntry().getKey())).thenReturn(
|
||||
mRow.getEntry());
|
||||
.getActiveNotificationUnfiltered(mRow.getKey())).thenReturn(mRow);
|
||||
|
||||
mZenModeConfig.suppressedVisualEffects = 0;
|
||||
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
|
||||
@@ -351,8 +361,8 @@ public class BubblesTest extends SysuiTestCase {
|
||||
verify(mNotificationEntryManager).updateNotifications(any());
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
@@ -362,20 +372,20 @@ public class BubblesTest extends SysuiTestCase {
|
||||
public void testPromoteBubble_autoExpand() throws Exception {
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
|
||||
.thenReturn(mRow2.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getKey()))
|
||||
.thenReturn(mRow);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getKey()))
|
||||
.thenReturn(mRow2);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
|
||||
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getKey());
|
||||
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
|
||||
verify(mNotificationEntryManager, never()).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), anyInt());
|
||||
assertThat(mRow.getEntry().isBubble()).isFalse();
|
||||
eq(mRow.getSbn()), any(), anyInt());
|
||||
assertThat(mRow.isBubble()).isFalse();
|
||||
|
||||
Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey());
|
||||
Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getKey());
|
||||
assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
|
||||
|
||||
mBubbleController.promoteBubbleFromOverflow(b);
|
||||
@@ -393,19 +403,19 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
mBubbleController.updateBubble(mBubbleEntry, /* suppressFlyout */
|
||||
false, /* showInShade */ true);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
|
||||
.thenReturn(mRow2.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getKey()))
|
||||
.thenReturn(mRow);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getKey()))
|
||||
.thenReturn(mRow2);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), anyInt());
|
||||
eq(mRow.getSbn()), any(), anyInt());
|
||||
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
|
||||
assertFalse(mRow.getEntry().isBubble());
|
||||
assertFalse(mRow.isBubble());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -414,28 +424,28 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_CHANGED);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_CHANGED);
|
||||
verify(mNotificationEntryManager, never()).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), anyInt());
|
||||
eq(mRow.getSbn()), any(), anyInt());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
assertTrue(mRow.getEntry().isBubble());
|
||||
assertTrue(mRow.isBubble());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissStack() {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
verify(mNotificationEntryManager, times(1)).updateNotifications(any());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
verify(mNotificationEntryManager, times(2)).updateNotifications(any());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mNotificationEntryManager, times(3)).updateNotifications(any());
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey()));
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
}
|
||||
@@ -445,7 +455,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
@@ -457,7 +467,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
|
||||
@@ -467,7 +477,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
@@ -477,8 +487,8 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Ignore("Currently broken.")
|
||||
public void testCollapseAfterChangingExpandedBubble() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mEntryListener.onPendingEntryAdded(mRow2);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
@@ -494,30 +504,30 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow2.getEntry().getKey());
|
||||
true, mRow2.getKey());
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Switch which bubble is expanded
|
||||
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
|
||||
mRow.getEntry().getKey()));
|
||||
mRow.getKey()));
|
||||
mBubbleData.setExpanded(true);
|
||||
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// collapse for previous bubble
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
false, mRow2.getEntry().getKey());
|
||||
false, mRow2.getKey());
|
||||
// expand for selected bubble
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow.getEntry().getKey());
|
||||
true, mRow.getKey());
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
@@ -529,7 +539,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testExpansionRemovesShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
@@ -538,12 +548,12 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Expand
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
|
||||
@@ -551,13 +561,13 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
@@ -566,12 +576,12 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Expand
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
|
||||
@@ -579,24 +589,24 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Send update
|
||||
mEntryListener.onPreEntryUpdated(mRow.getEntry());
|
||||
mEntryListener.onPreEntryUpdated(mRow);
|
||||
|
||||
// Nothing should have changed
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveLastExpanded_selectsOverflow() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mEntryListener.onPendingEntryAdded(mRow2);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
@@ -607,10 +617,10 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey());
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
assertEquals(mRow2.getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
@@ -620,12 +630,12 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getKey());
|
||||
|
||||
// Make sure first bubble is selected
|
||||
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Dismiss that one
|
||||
mBubbleController.removeBubble(
|
||||
@@ -643,7 +653,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveLastExpandedEmptyOverflow_collapses() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expand
|
||||
@@ -652,7 +662,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Block the bubble so it won't be in the overflow
|
||||
mBubbleController.removeBubble(
|
||||
@@ -660,10 +670,10 @@ public class BubblesTest extends SysuiTestCase {
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
Bubbles.DISMISS_BLOCKED);
|
||||
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
|
||||
// We should be collapsed
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
}
|
||||
@@ -671,16 +681,16 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testAutoExpand_fails_noFlag() {
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion shouldn't change
|
||||
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
|
||||
mRow.getEntry().getKey());
|
||||
mRow.getKey());
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
@@ -688,16 +698,16 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testAutoExpand_succeeds_withFlag() {
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion should change
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
|
||||
mRow.getEntry().getKey());
|
||||
mRow.getKey());
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
|
||||
assertTrue(mSysUiStateBubblesExpanded);
|
||||
@@ -705,19 +715,19 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testSuppressNotif_onInitialNotif() {
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
|
||||
|
||||
// Add the suppress notif bubble
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Notif should be suppressed because we were foreground
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
}
|
||||
@@ -730,10 +740,10 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Should show dot
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Update to suppress notif
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
@@ -741,22 +751,20 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
|
||||
|
||||
assertFalse(mSysUiStateBubblesExpanded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandStackAndSelectBubble_removedFirst() {
|
||||
final String key = mRow.getEntry().getKey();
|
||||
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Simulate notification cancellation.
|
||||
mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
|
||||
mRow.getKey(), mRow, REASON_APP_CANCEL);
|
||||
|
||||
mBubbleController.expandStackAndSelectBubble(mBubbleEntry);
|
||||
|
||||
@@ -765,12 +773,12 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testMarkNewNotificationAsShowInShade() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -784,7 +792,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_AGED);
|
||||
mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_AGED);
|
||||
verify(mDeleteIntent, never()).send();
|
||||
}
|
||||
|
||||
@@ -792,7 +800,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mDeleteIntent, times(1)).send();
|
||||
}
|
||||
|
||||
@@ -810,11 +818,11 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
mRow.getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
NotificationListenerService.Ranking ranking = new RankingBuilder(
|
||||
mRow.getEntry().getRanking()).setCanBubble(false).build();
|
||||
mRow.getEntry().setRanking(ranking);
|
||||
mEntryListener.onPreEntryUpdated(mRow.getEntry());
|
||||
mRow.getRanking()).setCanBubble(false).build();
|
||||
mRow.setRanking(ranking);
|
||||
mEntryListener.onPreEntryUpdated(mRow);
|
||||
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
verify(mDeleteIntent, never()).send();
|
||||
@@ -822,13 +830,13 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_succeeds_appCancel() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
|
||||
mRow.getKey(), mRow, REASON_APP_CANCEL);
|
||||
|
||||
// Cancels always remove so no need to intercept
|
||||
assertFalse(intercepted);
|
||||
@@ -836,19 +844,19 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_entryListenerRemove() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
// Removes the notification
|
||||
mEntryListener.onEntryRemoved(mRow.getEntry(), null, false, REASON_APP_CANCEL);
|
||||
mEntryListener.onEntryRemoved(mRow, null, false, REASON_APP_CANCEL);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeBubble_clearAllIntercepted() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
@@ -856,7 +864,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL_ALL);
|
||||
mRow.getKey(), mRow, REASON_CANCEL_ALL);
|
||||
|
||||
// Intercept!
|
||||
assertTrue(intercepted);
|
||||
@@ -867,7 +875,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void removeBubble_userDismissNotifIntercepted() {
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
@@ -875,7 +883,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
|
||||
mRow.getKey(), mRow, REASON_CANCEL);
|
||||
|
||||
// Intercept!
|
||||
assertTrue(intercepted);
|
||||
@@ -887,7 +895,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void removeNotif_inOverflow_intercepted() {
|
||||
// Get bubble with notif in shade.
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
@@ -895,11 +903,11 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
// Dismiss the bubble into overflow.
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
|
||||
mRow.getKey(), mRow, REASON_CANCEL);
|
||||
|
||||
// Notif is no longer a bubble, but still in overflow, so we intercept removal.
|
||||
assertTrue(intercepted);
|
||||
@@ -908,7 +916,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void removeNotif_notInOverflow_notIntercepted() {
|
||||
// Get bubble with notif in shade.
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
@@ -916,11 +924,11 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
|
||||
mRow.getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
|
||||
mRow.getKey(), mRow, REASON_CANCEL);
|
||||
|
||||
// Notif is no longer a bubble, so we should not intercept removal.
|
||||
assertFalse(intercepted);
|
||||
@@ -934,25 +942,25 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry2, /* suppressFlyout */ false, /* showInShade */ false);
|
||||
mBubbleController.updateBubble(
|
||||
mBubbleEntry3, /* suppressFlyout */ false, /* showInShade */ false);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getEntry().getKey()))
|
||||
.thenReturn(mRow2.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow3.getEntry().getKey()))
|
||||
.thenReturn(mRow3.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getKey()))
|
||||
.thenReturn(mRow);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow2.getKey()))
|
||||
.thenReturn(mRow2);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow3.getKey()))
|
||||
.thenReturn(mRow3);
|
||||
assertEquals(mBubbleData.getBubbles().size(), 3);
|
||||
|
||||
mBubbleData.setMaxOverflowBubbles(1);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertEquals(mBubbleData.getBubbles().size(), 2);
|
||||
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow2.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow2.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
|
||||
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
||||
eq(mRow.getEntry().getSbn()), any(), eq(REASON_CANCEL));
|
||||
eq(mRow.getSbn()), any(), eq(REASON_CANCEL));
|
||||
assertEquals(mBubbleData.getBubbles().size(), 1);
|
||||
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
|
||||
}
|
||||
@@ -963,14 +971,14 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mock(Bubbles.SuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mRemoveInterceptor.onNotificationRemoveRequested(
|
||||
mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
|
||||
mRow.getKey(), mRow, REASON_CANCEL);
|
||||
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
@@ -978,7 +986,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -987,7 +995,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mock(Bubbles.SuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onPendingEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onPendingEntryAdded(mRow);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
@@ -1001,7 +1009,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1094,14 +1102,47 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
// Overflow it
|
||||
mBubbleData.dismissBubbleWithKey(mRow.getEntry().getKey(),
|
||||
mBubbleData.dismissBubbleWithKey(mRow.getKey(),
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse();
|
||||
assertThat(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())).isTrue();
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getKey())).isFalse();
|
||||
assertThat(mBubbleData.hasOverflowBubbleWithKey(mRow.getKey())).isTrue();
|
||||
|
||||
// Test
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse();
|
||||
assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getKey())).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that when the user changes, the bubbles in the overflow list is cleared. Doesn't
|
||||
* test the loading from the repository which would be a nice thing to add.
|
||||
*/
|
||||
@Test
|
||||
public void testOnUserChanged_overflowState() {
|
||||
int firstUserId = mBubbleEntry.getStatusBarNotification().getUser().getIdentifier();
|
||||
int secondUserId = mBubbleEntryUser11.getStatusBarNotification().getUser().getIdentifier();
|
||||
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
// Verify these are in the overflow
|
||||
assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry.getKey())).isNotNull();
|
||||
assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2.getKey())).isNotNull();
|
||||
|
||||
// Switch users
|
||||
mBubbleController.onUserChanged(secondUserId);
|
||||
assertThat(mBubbleData.getOverflowBubbles().isEmpty());
|
||||
|
||||
// Give this user some bubbles
|
||||
mBubbleController.updateBubble(mBubbleEntryUser11);
|
||||
mBubbleController.updateBubble(mBubbleEntry2User11);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
|
||||
// Verify these are in the overflow
|
||||
assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntryUser11.getKey())).isNotNull();
|
||||
assertThat(mBubbleData.getOverflowBubbleWithKey(mBubbleEntry2User11.getKey())).isNotNull();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,8 +158,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
|
||||
private NotifCollectionListener mEntryListener;
|
||||
private NotificationTestHelper mNotificationTestHelper;
|
||||
private ExpandableNotificationRow mRow;
|
||||
private ExpandableNotificationRow mRow2;
|
||||
private NotificationEntry mRow;
|
||||
private NotificationEntry mRow2;
|
||||
private ExpandableNotificationRow mNonBubbleNotifRow;
|
||||
private BubbleEntry mBubbleEntry;
|
||||
private BubbleEntry mBubbleEntry2;
|
||||
@@ -224,8 +224,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
|
||||
mNonBubbleNotifRow = mNotificationTestHelper.createRow();
|
||||
mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow.getEntry());
|
||||
mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2.getEntry());
|
||||
mBubbleEntry = BubblesManager.notifToBubbleEntry(mRow);
|
||||
mBubbleEntry2 = BubblesManager.notifToBubbleEntry(mRow2);
|
||||
|
||||
mZenModeConfig.suppressedVisualEffects = 0;
|
||||
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
|
||||
@@ -306,19 +306,19 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveBubble() {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
|
||||
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_withDismissedNotif_inOverflow() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
@@ -326,40 +326,40 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Make it look like dismissed notif
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getKey()).setSuppressNotification(true);
|
||||
|
||||
// Now remove the bubble
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getKey()));
|
||||
|
||||
// We don't remove the notification since the bubble is still in overflow.
|
||||
verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), any(), anyInt());
|
||||
verify(mNotifCallback, never()).removeNotification(eq(mRow), any(), anyInt());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_withDismissedNotif_notInOverflow() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getEntry().getKey()))
|
||||
.thenReturn(mRow.getEntry());
|
||||
when(mNotificationEntryManager.getPendingOrActiveNotif(mRow.getKey()))
|
||||
.thenReturn(mRow);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Make it look like dismissed notif
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getKey()).setSuppressNotification(true);
|
||||
|
||||
// Now remove the bubble
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
||||
mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getKey()));
|
||||
|
||||
// Since the notif is dismissed and not in overflow, once the bubble is removed,
|
||||
// removeNotification gets called to really remove the notif
|
||||
verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()),
|
||||
verify(mNotifCallback, times(1)).removeNotification(eq(mRow),
|
||||
any(), anyInt());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
}
|
||||
@@ -368,16 +368,16 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
public void testDismissStack() {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
assertNotNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey()));
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mNotifCallback, times(3)).invalidateNotifications(anyString());
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -385,7 +385,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
@@ -397,7 +397,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Make sure the notif is suppressed
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
@@ -405,7 +405,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
}
|
||||
|
||||
@@ -413,8 +413,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Ignore("Currently broken.")
|
||||
public void testCollapseAfterChangingExpandedBubble() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow2.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mEntryListener.onEntryAdded(mRow2);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
@@ -430,28 +430,28 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow2.getEntry().getKey());
|
||||
true, mRow2.getKey());
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
|
||||
// Switch which bubble is expanded
|
||||
mBubbleData.setSelectedBubble(mBubbleData.getBubbleInStackWithKey(
|
||||
mRow.getEntry().getKey()));
|
||||
mRow.getKey()));
|
||||
mBubbleData.setExpanded(true);
|
||||
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// collapse for previous bubble
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
false, mRow2.getEntry().getKey());
|
||||
false, mRow2.getKey());
|
||||
// expand for selected bubble
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow.getEntry().getKey());
|
||||
true, mRow.getKey());
|
||||
|
||||
|
||||
// Collapse
|
||||
@@ -462,7 +462,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testExpansionRemovesShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
@@ -471,24 +471,24 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Expand
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// We should have bubbles & their notifs should not be suppressed
|
||||
@@ -497,35 +497,35 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Expand
|
||||
mBubbleData.setExpanded(true);
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Send update
|
||||
mEntryListener.onEntryUpdated(mRow.getEntry());
|
||||
mEntryListener.onEntryUpdated(mRow);
|
||||
|
||||
// Nothing should have changed
|
||||
// Notif is suppressed after expansion
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Notif shouldn't show dot after expansion
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveLastExpanded_selectsOverflow() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow2.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mEntryListener.onEntryAdded(mRow2);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.updateBubble(mBubbleEntry2);
|
||||
|
||||
@@ -534,10 +534,10 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey());
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
assertEquals(mRow2.getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry2.getKey(), mBubbleEntry2.getGroupKey()));
|
||||
@@ -547,12 +547,12 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getKey());
|
||||
|
||||
// Make sure first bubble is selected
|
||||
assertEquals(mRow.getEntry().getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
assertEquals(mRow.getKey(), mBubbleData.getBubbleInStackWithKey(
|
||||
stackView.getExpandedBubble().getKey()).getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Dismiss that one
|
||||
mBubbleController.removeBubble(
|
||||
@@ -569,7 +569,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testRemoveLastExpandedEmptyOverflow_collapses() {
|
||||
// Mark it as a bubble and add it explicitly
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expand
|
||||
@@ -577,7 +577,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
// Block the bubble so it won't be in the overflow
|
||||
mBubbleController.removeBubble(
|
||||
@@ -585,10 +585,10 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
stackView.getExpandedBubble().getKey()).getKey(),
|
||||
Bubbles.DISMISS_BLOCKED);
|
||||
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
|
||||
// We should be collapsed
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@@ -596,49 +596,49 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testAutoExpand_fails_noFlag() {
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion shouldn't change
|
||||
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
|
||||
mRow.getEntry().getKey());
|
||||
mRow.getKey());
|
||||
assertFalse(mBubbleController.isStackExpanded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoExpand_succeeds_withFlag() {
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
|
||||
|
||||
// Add the auto expand bubble
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Expansion should change
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
|
||||
mRow.getEntry().getKey());
|
||||
mRow.getKey());
|
||||
assertTrue(mBubbleController.isStackExpanded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuppressNotif_onInitialNotif() {
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
|
||||
|
||||
// Add the suppress notif bubble
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
// Notif should be suppressed because we were foreground
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -649,10 +649,10 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Should show dot
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
|
||||
// Update to suppress notif
|
||||
setMetadataFlags(mRow.getEntry(),
|
||||
setMetadataFlags(mRow,
|
||||
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
@@ -660,18 +660,18 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showFlyout());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkNewNotificationAsShowInShade() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mTestableLooper.processAllMessages();
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).showDot());
|
||||
assertTrue(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -685,7 +685,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_AGED);
|
||||
mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_AGED);
|
||||
verify(mDeleteIntent, never()).send();
|
||||
}
|
||||
|
||||
@@ -693,7 +693,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
mBubbleController.removeBubble(
|
||||
mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
verify(mDeleteIntent, times(1)).send();
|
||||
}
|
||||
|
||||
@@ -711,11 +711,11 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
mRow.getSbn().getNotification().flags &= ~FLAG_BUBBLE;
|
||||
NotificationListenerService.Ranking ranking = new RankingBuilder(
|
||||
mRow.getEntry().getRanking()).setCanBubble(false).build();
|
||||
mRow.getEntry().setRanking(ranking);
|
||||
mEntryListener.onEntryUpdated(mRow.getEntry());
|
||||
mRow.getRanking()).setCanBubble(false).build();
|
||||
mRow.setRanking(ranking);
|
||||
mEntryListener.onEntryUpdated(mRow);
|
||||
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
verify(mDeleteIntent, never()).send();
|
||||
@@ -723,26 +723,26 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testRemoveBubble_entryListenerRemove() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
// Removes the notification
|
||||
mEntryListener.onEntryRemoved(mRow.getEntry(), 0);
|
||||
mEntryListener.onEntryRemoved(mRow, 0);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeBubble_intercepted() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow);
|
||||
|
||||
// Intercept!
|
||||
assertTrue(intercepted);
|
||||
@@ -753,7 +753,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void removeBubble_dismissIntoOverflow_intercepted() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
@@ -761,11 +761,11 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Dismiss the bubble
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
// Dismiss the notification
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow);
|
||||
|
||||
// Intercept dismissal since bubble is going into overflow
|
||||
assertTrue(intercepted);
|
||||
@@ -773,7 +773,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void removeBubble_notIntercepted() {
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
@@ -781,11 +781,11 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
// Dismiss the bubble
|
||||
mBubbleController.removeBubble(mRow.getEntry().getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
// Dismiss the notification
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
boolean intercepted = mBubblesManager.handleDismissalInterception(mRow);
|
||||
|
||||
// Not a bubble anymore so we don't intercept dismissal.
|
||||
assertFalse(intercepted);
|
||||
@@ -797,13 +797,13 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mock(Bubbles.SuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
mBubbleEntry.getKey(), mBubbleEntry.getGroupKey()));
|
||||
|
||||
mBubblesManager.handleDismissalInterception(mRow.getEntry());
|
||||
mBubblesManager.handleDismissalInterception(mRow);
|
||||
|
||||
// Should update show in shade state
|
||||
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
@@ -811,7 +811,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -820,7 +820,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
mock(Bubbles.SuppressionChangedListener.class);
|
||||
mBubbleData.setSuppressionChangedListener(listener);
|
||||
|
||||
mEntryListener.onEntryAdded(mRow.getEntry());
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
|
||||
@@ -834,7 +834,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
|
||||
|
||||
// Should notify delegate that shade state changed
|
||||
verify(listener).onBubbleNotificationSuppressionChange(
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||
mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user