Merge changes I95898fa6,I21e4b17e into rvc-dev
* changes: Prevent duplicates from persisted bubbles. Persists bubbles to disk (part 4)
This commit is contained in:
committed by
Android (Google) Code Review
commit
dcc609a1b2
@@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.systemui.bubbles;
|
package com.android.systemui.bubbles;
|
||||||
|
|
||||||
|
import static android.app.Notification.FLAG_BUBBLE;
|
||||||
import static android.os.AsyncTask.Status.FINISHED;
|
import static android.os.AsyncTask.Status.FINISHED;
|
||||||
import static android.view.Display.INVALID_DISPLAY;
|
import static android.view.Display.INVALID_DISPLAY;
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ import android.app.Notification;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.LauncherApps;
|
import android.content.pm.LauncherApps;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ShortcutInfo;
|
import android.content.pm.ShortcutInfo;
|
||||||
@@ -55,6 +56,11 @@ import java.util.Objects;
|
|||||||
class Bubble implements BubbleViewProvider {
|
class Bubble implements BubbleViewProvider {
|
||||||
private static final String TAG = "Bubble";
|
private static final String TAG = "Bubble";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NotificationEntry associated with the bubble. A null value implies this bubble is loaded
|
||||||
|
* from disk.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
private NotificationEntry mEntry;
|
private NotificationEntry mEntry;
|
||||||
private final String mKey;
|
private final String mKey;
|
||||||
|
|
||||||
@@ -96,11 +102,18 @@ class Bubble implements BubbleViewProvider {
|
|||||||
private Bitmap mBadgedImage;
|
private Bitmap mBadgedImage;
|
||||||
private int mDotColor;
|
private int mDotColor;
|
||||||
private Path mDotPath;
|
private Path mDotPath;
|
||||||
|
private int mFlags;
|
||||||
|
|
||||||
// TODO: Decouple Bubble from NotificationEntry and transform ShortcutInfo into Bubble
|
/**
|
||||||
Bubble(ShortcutInfo shortcutInfo) {
|
* Create a bubble with limited information based on given {@link ShortcutInfo}.
|
||||||
|
* Note: Currently this is only being used when the bubble is persisted to disk.
|
||||||
|
*/
|
||||||
|
Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo) {
|
||||||
|
Objects.requireNonNull(key);
|
||||||
|
Objects.requireNonNull(shortcutInfo);
|
||||||
mShortcutInfo = shortcutInfo;
|
mShortcutInfo = shortcutInfo;
|
||||||
mKey = shortcutInfo.getId();
|
mKey = key;
|
||||||
|
mFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used in tests when no UI is required. */
|
/** Used in tests when no UI is required. */
|
||||||
@@ -111,6 +124,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
mKey = e.getKey();
|
mKey = e.getKey();
|
||||||
mLastUpdated = e.getSbn().getPostTime();
|
mLastUpdated = e.getSbn().getPostTime();
|
||||||
mSuppressionListener = listener;
|
mSuppressionListener = listener;
|
||||||
|
mFlags = e.getSbn().getNotification().flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,12 +132,22 @@ class Bubble implements BubbleViewProvider {
|
|||||||
return mKey;
|
return mKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public NotificationEntry getEntry() {
|
public NotificationEntry getEntry() {
|
||||||
return mEntry;
|
return mEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public UserHandle getUser() {
|
||||||
|
if (mEntry != null) return mEntry.getSbn().getUser();
|
||||||
|
if (mShortcutInfo != null) return mShortcutInfo.getUserHandle();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
return mEntry.getSbn().getPackageName();
|
return mEntry == null
|
||||||
|
? mShortcutInfo == null ? null : mShortcutInfo.getPackage()
|
||||||
|
: mEntry.getSbn().getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -167,6 +191,18 @@ class Bubble implements BubbleViewProvider {
|
|||||||
return mExpandedView;
|
return mExpandedView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getTitle() {
|
||||||
|
final CharSequence titleCharSeq;
|
||||||
|
if (mEntry == null) {
|
||||||
|
titleCharSeq = null;
|
||||||
|
} else {
|
||||||
|
titleCharSeq = mEntry.getSbn().getNotification().extras.getCharSequence(
|
||||||
|
Notification.EXTRA_TITLE);
|
||||||
|
}
|
||||||
|
return titleCharSeq != null ? titleCharSeq.toString() : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call when the views should be removed, ensure this is called to clean up ActivityView
|
* Call when the views should be removed, ensure this is called to clean up ActivityView
|
||||||
* content.
|
* content.
|
||||||
@@ -207,7 +243,8 @@ class Bubble implements BubbleViewProvider {
|
|||||||
void inflate(BubbleViewInfoTask.Callback callback,
|
void inflate(BubbleViewInfoTask.Callback callback,
|
||||||
Context context,
|
Context context,
|
||||||
BubbleStackView stackView,
|
BubbleStackView stackView,
|
||||||
BubbleIconFactory iconFactory) {
|
BubbleIconFactory iconFactory,
|
||||||
|
boolean skipInflation) {
|
||||||
if (isBubbleLoading()) {
|
if (isBubbleLoading()) {
|
||||||
mInflationTask.cancel(true /* mayInterruptIfRunning */);
|
mInflationTask.cancel(true /* mayInterruptIfRunning */);
|
||||||
}
|
}
|
||||||
@@ -215,6 +252,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
context,
|
context,
|
||||||
stackView,
|
stackView,
|
||||||
iconFactory,
|
iconFactory,
|
||||||
|
skipInflation,
|
||||||
callback);
|
callback);
|
||||||
if (mInflateSynchronously) {
|
if (mInflateSynchronously) {
|
||||||
mInflationTask.onPostExecute(mInflationTask.doInBackground());
|
mInflationTask.onPostExecute(mInflationTask.doInBackground());
|
||||||
@@ -327,6 +365,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
* Whether this notification should be shown in the shade.
|
* Whether this notification should be shown in the shade.
|
||||||
*/
|
*/
|
||||||
boolean showInShade() {
|
boolean showInShade() {
|
||||||
|
if (mEntry == null) return false;
|
||||||
return !shouldSuppressNotification() || !mEntry.isClearable();
|
return !shouldSuppressNotification() || !mEntry.isClearable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,8 +373,8 @@ class Bubble implements BubbleViewProvider {
|
|||||||
* Sets whether this notification should be suppressed in the shade.
|
* Sets whether this notification should be suppressed in the shade.
|
||||||
*/
|
*/
|
||||||
void setSuppressNotification(boolean suppressNotification) {
|
void setSuppressNotification(boolean suppressNotification) {
|
||||||
|
if (mEntry == null) return;
|
||||||
boolean prevShowInShade = showInShade();
|
boolean prevShowInShade = showInShade();
|
||||||
|
|
||||||
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
||||||
int flags = data.getFlags();
|
int flags = data.getFlags();
|
||||||
if (suppressNotification) {
|
if (suppressNotification) {
|
||||||
@@ -366,6 +405,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean showDot() {
|
public boolean showDot() {
|
||||||
|
if (mEntry == null) return false;
|
||||||
return mShowBubbleUpdateDot
|
return mShowBubbleUpdateDot
|
||||||
&& !mEntry.shouldSuppressNotificationDot()
|
&& !mEntry.shouldSuppressNotificationDot()
|
||||||
&& !shouldSuppressNotification();
|
&& !shouldSuppressNotification();
|
||||||
@@ -375,6 +415,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
* Whether the flyout for the bubble should be shown.
|
* Whether the flyout for the bubble should be shown.
|
||||||
*/
|
*/
|
||||||
boolean showFlyout() {
|
boolean showFlyout() {
|
||||||
|
if (mEntry == null) return false;
|
||||||
return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
|
return !mSuppressFlyout && !mEntry.shouldSuppressPeek()
|
||||||
&& !shouldSuppressNotification()
|
&& !shouldSuppressNotification()
|
||||||
&& !mEntry.shouldSuppressNotificationList();
|
&& !mEntry.shouldSuppressNotificationList();
|
||||||
@@ -394,6 +435,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float getDesiredHeight(Context context) {
|
float getDesiredHeight(Context context) {
|
||||||
|
if (mEntry == null) return 0;
|
||||||
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
||||||
boolean useRes = data.getDesiredHeightResId() != 0;
|
boolean useRes = data.getDesiredHeightResId() != 0;
|
||||||
if (useRes) {
|
if (useRes) {
|
||||||
@@ -407,6 +449,7 @@ class Bubble implements BubbleViewProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String getDesiredHeightString() {
|
String getDesiredHeightString() {
|
||||||
|
if (mEntry == null) return String.valueOf(0);
|
||||||
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
||||||
boolean useRes = data.getDesiredHeightResId() != 0;
|
boolean useRes = data.getDesiredHeightResId() != 0;
|
||||||
if (useRes) {
|
if (useRes) {
|
||||||
@@ -423,11 +466,13 @@ class Bubble implements BubbleViewProvider {
|
|||||||
* To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
|
* To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
|
||||||
*/
|
*/
|
||||||
boolean usingShortcutInfo() {
|
boolean usingShortcutInfo() {
|
||||||
return mEntry.getBubbleMetadata().getShortcutId() != null;
|
return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null
|
||||||
|
|| mShortcutInfo != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
PendingIntent getBubbleIntent() {
|
PendingIntent getBubbleIntent() {
|
||||||
|
if (mEntry == null) return null;
|
||||||
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
return data.getIntent();
|
return data.getIntent();
|
||||||
@@ -435,16 +480,32 @@ class Bubble implements BubbleViewProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent getSettingsIntent() {
|
Intent getSettingsIntent(final Context context) {
|
||||||
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
|
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
|
||||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
|
||||||
intent.putExtra(Settings.EXTRA_APP_UID, mEntry.getSbn().getUid());
|
final int uid = getUid(context);
|
||||||
|
if (uid != -1) {
|
||||||
|
intent.putExtra(Settings.EXTRA_APP_UID, uid);
|
||||||
|
}
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getUid(final Context context) {
|
||||||
|
if (mEntry != null) return mEntry.getSbn().getUid();
|
||||||
|
final PackageManager pm = context.getPackageManager();
|
||||||
|
if (pm == null) return -1;
|
||||||
|
try {
|
||||||
|
final ApplicationInfo info = pm.getApplicationInfo(mShortcutInfo.getPackage(), 0);
|
||||||
|
return info.uid;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
Log.e(TAG, "cannot find uid", e);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
|
private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) {
|
||||||
PackageManager pm = context.getPackageManager();
|
PackageManager pm = context.getPackageManager();
|
||||||
Resources r;
|
Resources r;
|
||||||
@@ -466,11 +527,13 @@ class Bubble implements BubbleViewProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldSuppressNotification() {
|
private boolean shouldSuppressNotification() {
|
||||||
|
if (mEntry == null) return false;
|
||||||
return mEntry.getBubbleMetadata() != null
|
return mEntry.getBubbleMetadata() != null
|
||||||
&& mEntry.getBubbleMetadata().isNotificationSuppressed();
|
&& mEntry.getBubbleMetadata().isNotificationSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean shouldAutoExpand() {
|
boolean shouldAutoExpand() {
|
||||||
|
if (mEntry == null) return false;
|
||||||
Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
|
Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
|
||||||
return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand;
|
return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand;
|
||||||
}
|
}
|
||||||
@@ -479,6 +542,19 @@ class Bubble implements BubbleViewProvider {
|
|||||||
mShouldAutoExpand = shouldAutoExpand;
|
mShouldAutoExpand = shouldAutoExpand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBubble() {
|
||||||
|
if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0;
|
||||||
|
return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enable(int option) {
|
||||||
|
mFlags |= option;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disable(int option) {
|
||||||
|
mFlags &= ~option;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Bubble{" + mKey + '}';
|
return "Bubble{" + mKey + '}';
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
|
|||||||
import static java.lang.annotation.ElementType.PARAMETER;
|
import static java.lang.annotation.ElementType.PARAMETER;
|
||||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
@@ -113,6 +114,7 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bubbles are a special type of content that can "float" on top of other apps or System UI.
|
* Bubbles are a special type of content that can "float" on top of other apps or System UI.
|
||||||
@@ -243,13 +245,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
* This can happen when an app cancels a bubbled notification or when the user dismisses a
|
* This can happen when an app cancels a bubbled notification or when the user dismisses a
|
||||||
* bubble.
|
* bubble.
|
||||||
*/
|
*/
|
||||||
void removeNotification(NotificationEntry entry, int reason);
|
void removeNotification(@NonNull NotificationEntry entry, int reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a bubbled notification has changed whether it should be
|
* Called when a bubbled notification has changed whether it should be
|
||||||
* filtered from the shade.
|
* filtered from the shade.
|
||||||
*/
|
*/
|
||||||
void invalidateNotifications(String reason);
|
void invalidateNotifications(@NonNull String reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called on a bubbled entry that has been removed when there are no longer
|
* Called on a bubbled entry that has been removed when there are no longer
|
||||||
@@ -259,7 +261,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
* removes all remnants of the group's summary from the notification pipeline.
|
* removes all remnants of the group's summary from the notification pipeline.
|
||||||
* TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
|
* TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
|
||||||
*/
|
*/
|
||||||
void maybeCancelSummary(NotificationEntry entry);
|
void maybeCancelSummary(@NonNull NotificationEntry entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -755,10 +757,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
mBubbleIconFactory = new BubbleIconFactory(mContext);
|
mBubbleIconFactory = new BubbleIconFactory(mContext);
|
||||||
// Reload each bubble
|
// Reload each bubble
|
||||||
for (Bubble b: mBubbleData.getBubbles()) {
|
for (Bubble b: mBubbleData.getBubbles()) {
|
||||||
b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
|
b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory,
|
||||||
|
false /* skipInflation */);
|
||||||
}
|
}
|
||||||
for (Bubble b: mBubbleData.getOverflowBubbles()) {
|
for (Bubble b: mBubbleData.getOverflowBubbles()) {
|
||||||
b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory);
|
b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory,
|
||||||
|
false /* skipInflation */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -845,7 +849,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
|
|
||||||
void promoteBubbleFromOverflow(Bubble bubble) {
|
void promoteBubbleFromOverflow(Bubble bubble) {
|
||||||
bubble.setInflateSynchronously(mInflateSynchronously);
|
bubble.setInflateSynchronously(mInflateSynchronously);
|
||||||
setIsBubble(bubble.getEntry(), /* isBubble */ true);
|
setIsBubble(bubble, /* isBubble */ true);
|
||||||
mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
|
mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,10 +899,30 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
updateBubble(notif, false /* suppressFlyout */, true /* showInShade */);
|
updateBubble(notif, false /* suppressFlyout */, true /* showInShade */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the overflow bubbles by loading them from disk.
|
||||||
|
*/
|
||||||
|
void loadOverflowBubblesFromDisk() {
|
||||||
|
if (!mBubbleData.getOverflowBubbles().isEmpty()) {
|
||||||
|
// we don't need to load overflow bubbles from disk if it is already in memory
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mDataRepository.loadBubbles((bubbles) -> {
|
||||||
|
bubbles.forEach(bubble -> {
|
||||||
|
if (mBubbleData.getBubbles().contains(bubble)) {
|
||||||
|
// if the bubble is already active, there's no need to push it to overflow
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bubble.inflate((b) -> mBubbleData.overflowBubble(DISMISS_AGED, bubble),
|
||||||
|
mContext, mStackView, mBubbleIconFactory, true /* skipInflation */);
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
|
void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
|
||||||
// Lazy init stack view when a bubble is created
|
// Lazy init stack view when a bubble is created
|
||||||
ensureStackViewCreated();
|
ensureStackViewCreated();
|
||||||
|
|
||||||
// If this is an interruptive notif, mark that it's interrupted
|
// If this is an interruptive notif, mark that it's interrupted
|
||||||
if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
|
if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
|
||||||
notif.setInterruption();
|
notif.setInterruption();
|
||||||
@@ -918,11 +942,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mHandler.post(
|
mHandler.post(
|
||||||
() -> removeBubble(bubble.getEntry(),
|
() -> removeBubble(bubble.getKey(),
|
||||||
BubbleController.DISMISS_INVALID_INTENT));
|
BubbleController.DISMISS_INVALID_INTENT));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mContext, mStackView, mBubbleIconFactory);
|
mContext, mStackView, mBubbleIconFactory, false /* skipInflation */);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -934,7 +958,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
* @param entry the notification to change bubble state for.
|
* @param entry the notification to change bubble state for.
|
||||||
* @param shouldBubble whether the notification should show as a bubble or not.
|
* @param shouldBubble whether the notification should show as a bubble or not.
|
||||||
*/
|
*/
|
||||||
public void onUserChangedBubble(NotificationEntry entry, boolean shouldBubble) {
|
public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) {
|
||||||
|
if (entry == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
NotificationChannel channel = entry.getChannel();
|
NotificationChannel channel = entry.getChannel();
|
||||||
final String appPkg = entry.getSbn().getPackageName();
|
final String appPkg = entry.getSbn().getPackageName();
|
||||||
final int appUid = entry.getSbn().getUid();
|
final int appUid = entry.getSbn().getUid();
|
||||||
@@ -973,14 +1000,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the bubble with the given NotificationEntry.
|
* Removes the bubble with the given key.
|
||||||
* <p>
|
* <p>
|
||||||
* Must be called from the main thread.
|
* Must be called from the main thread.
|
||||||
*/
|
*/
|
||||||
@MainThread
|
@MainThread
|
||||||
void removeBubble(NotificationEntry entry, int reason) {
|
void removeBubble(String key, int reason) {
|
||||||
if (mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
|
if (mBubbleData.hasAnyBubbleWithKey(key)) {
|
||||||
mBubbleData.notificationEntryRemoved(entry, reason);
|
mBubbleData.notificationEntryRemoved(key, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,7 +1025,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
&& canLaunchInActivityView(mContext, entry);
|
&& canLaunchInActivityView(mContext, entry);
|
||||||
if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
|
if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) {
|
||||||
// It was previously a bubble but no longer a bubble -- lets remove it
|
// It was previously a bubble but no longer a bubble -- lets remove it
|
||||||
removeBubble(entry, DISMISS_NO_LONGER_BUBBLE);
|
removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
|
||||||
} else if (shouldBubble && entry.isBubble()) {
|
} else if (shouldBubble && entry.isBubble()) {
|
||||||
updateBubble(entry);
|
updateBubble(entry);
|
||||||
}
|
}
|
||||||
@@ -1012,10 +1039,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
// Remove any associated bubble children with the summary
|
// Remove any associated bubble children with the summary
|
||||||
final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
|
final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
|
||||||
for (int i = 0; i < bubbleChildren.size(); i++) {
|
for (int i = 0; i < bubbleChildren.size(); i++) {
|
||||||
removeBubble(bubbleChildren.get(i).getEntry(), DISMISS_GROUP_CANCELLED);
|
removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
removeBubble(entry, DISMISS_NOTIF_CANCEL);
|
removeBubble(entry.getKey(), DISMISS_NOTIF_CANCEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1037,7 +1064,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
rankingMap.getRanking(key, mTmpRanking);
|
rankingMap.getRanking(key, mTmpRanking);
|
||||||
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
|
boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key);
|
||||||
if (isActiveBubble && !mTmpRanking.canBubble()) {
|
if (isActiveBubble && !mTmpRanking.canBubble()) {
|
||||||
mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED);
|
mBubbleData.notificationEntryRemoved(entry.getKey(),
|
||||||
|
BubbleController.DISMISS_BLOCKED);
|
||||||
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
|
} else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
|
||||||
entry.setFlagBubble(true);
|
entry.setFlagBubble(true);
|
||||||
onEntryUpdated(entry);
|
onEntryUpdated(entry);
|
||||||
@@ -1045,7 +1073,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setIsBubble(NotificationEntry entry, boolean isBubble) {
|
private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble) {
|
||||||
|
Objects.requireNonNull(entry);
|
||||||
if (isBubble) {
|
if (isBubble) {
|
||||||
entry.getSbn().getNotification().flags |= FLAG_BUBBLE;
|
entry.getSbn().getNotification().flags |= FLAG_BUBBLE;
|
||||||
} else {
|
} else {
|
||||||
@@ -1058,11 +1087,31 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) {
|
||||||
|
Objects.requireNonNull(b);
|
||||||
|
if (isBubble) {
|
||||||
|
b.enable(FLAG_BUBBLE);
|
||||||
|
} else {
|
||||||
|
b.disable(FLAG_BUBBLE);
|
||||||
|
}
|
||||||
|
if (b.getEntry() != null) {
|
||||||
|
setIsBubble(b.getEntry(), isBubble);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Bad things have happened
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
|
private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyUpdate(BubbleData.Update update) {
|
public void applyUpdate(BubbleData.Update update) {
|
||||||
|
// Lazy load overflow bubbles from disk
|
||||||
|
loadOverflowBubblesFromDisk();
|
||||||
// Update bubbles in overflow.
|
// Update bubbles in overflow.
|
||||||
if (mOverflowCallback != null) {
|
if (mOverflowCallback != null) {
|
||||||
mOverflowCallback.run();
|
mOverflowCallback.run();
|
||||||
@@ -1097,23 +1146,27 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
// The bubble is now gone & the notification is hidden from the shade, so
|
// The bubble is now gone & the notification is hidden from the shade, so
|
||||||
// time to actually remove it
|
// time to actually remove it
|
||||||
for (NotifCallback cb : mCallbacks) {
|
for (NotifCallback cb : mCallbacks) {
|
||||||
cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
|
if (bubble.getEntry() != null) {
|
||||||
|
cb.removeNotification(bubble.getEntry(), REASON_CANCEL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bubble.getEntry().isBubble() && bubble.showInShade()) {
|
if (bubble.isBubble() && bubble.showInShade()) {
|
||||||
setIsBubble(bubble.getEntry(), false /* isBubble */);
|
setIsBubble(bubble, false /* isBubble */);
|
||||||
}
|
}
|
||||||
if (bubble.getEntry().getRow() != null) {
|
if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) {
|
||||||
bubble.getEntry().getRow().updateBubbleButton();
|
bubble.getEntry().getRow().updateBubbleButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
final String groupKey = bubble.getEntry().getSbn().getGroupKey();
|
if (bubble.getEntry() != null) {
|
||||||
if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
|
final String groupKey = bubble.getEntry().getSbn().getGroupKey();
|
||||||
// Time to potentially remove the summary
|
if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) {
|
||||||
for (NotifCallback cb : mCallbacks) {
|
// Time to potentially remove the summary
|
||||||
cb.maybeCancelSummary(bubble.getEntry());
|
for (NotifCallback cb : mCallbacks) {
|
||||||
|
cb.maybeCancelSummary(bubble.getEntry());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1138,7 +1191,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
|||||||
|
|
||||||
if (update.selectionChanged) {
|
if (update.selectionChanged) {
|
||||||
mStackView.setSelectedBubble(update.selectedBubble);
|
mStackView.setSelectedBubble(update.selectedBubble);
|
||||||
if (update.selectedBubble != null) {
|
if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) {
|
||||||
mNotificationGroupManager.updateSuppression(
|
mNotificationGroupManager.updateSuppression(
|
||||||
update.selectedBubble.getEntry());
|
update.selectedBubble.getEntry());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
|
|||||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
||||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -214,7 +215,7 @@ public class BubbleData {
|
|||||||
notificationEntryUpdated(bubble, false /* suppressFlyout */,
|
notificationEntryUpdated(bubble, false /* suppressFlyout */,
|
||||||
true /* showInShade */);
|
true /* showInShade */);
|
||||||
},
|
},
|
||||||
mContext, stack, factory);
|
mContext, stack, factory, false /* skipInflation */);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setShowingOverflow(boolean showingOverflow) {
|
void setShowingOverflow(boolean showingOverflow) {
|
||||||
@@ -268,7 +269,8 @@ public class BubbleData {
|
|||||||
}
|
}
|
||||||
mPendingBubbles.remove(bubble); // No longer pending once we're here
|
mPendingBubbles.remove(bubble); // No longer pending once we're here
|
||||||
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
|
Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
|
||||||
suppressFlyout |= !bubble.getEntry().getRanking().visuallyInterruptive();
|
suppressFlyout |= bubble.getEntry() == null
|
||||||
|
|| !bubble.getEntry().getRanking().visuallyInterruptive();
|
||||||
|
|
||||||
if (prevBubble == null) {
|
if (prevBubble == null) {
|
||||||
// Create a new bubble
|
// Create a new bubble
|
||||||
@@ -297,11 +299,14 @@ public class BubbleData {
|
|||||||
dispatchPendingChanges();
|
dispatchPendingChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
|
/**
|
||||||
|
* Called when a notification associated with a bubble is removed.
|
||||||
|
*/
|
||||||
|
public void notificationEntryRemoved(String key, @DismissReason int reason) {
|
||||||
if (DEBUG_BUBBLE_DATA) {
|
if (DEBUG_BUBBLE_DATA) {
|
||||||
Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason);
|
Log.d(TAG, "notificationEntryRemoved: key=" + key + " reason=" + reason);
|
||||||
}
|
}
|
||||||
doRemove(entry.getKey(), reason);
|
doRemove(key, reason);
|
||||||
dispatchPendingChanges();
|
dispatchPendingChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +354,7 @@ public class BubbleData {
|
|||||||
return bubbleChildren;
|
return bubbleChildren;
|
||||||
}
|
}
|
||||||
for (Bubble b : mBubbles) {
|
for (Bubble b : mBubbles) {
|
||||||
if (groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
|
if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) {
|
||||||
bubbleChildren.add(b);
|
bubbleChildren.add(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,7 +452,9 @@ public class BubbleData {
|
|||||||
Bubble newSelected = mBubbles.get(newIndex);
|
Bubble newSelected = mBubbles.get(newIndex);
|
||||||
setSelectedBubbleInternal(newSelected);
|
setSelectedBubbleInternal(newSelected);
|
||||||
}
|
}
|
||||||
maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
|
if (bubbleToRemove.getEntry() != null) {
|
||||||
|
maybeSendDeleteIntent(reason, bubbleToRemove.getEntry());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void overflowBubble(@DismissReason int reason, Bubble bubble) {
|
void overflowBubble(@DismissReason int reason, Bubble bubble) {
|
||||||
@@ -615,7 +622,8 @@ public class BubbleData {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
|
private void maybeSendDeleteIntent(@DismissReason int reason,
|
||||||
|
@NonNull final NotificationEntry entry) {
|
||||||
if (reason == BubbleController.DISMISS_USER_GESTURE) {
|
if (reason == BubbleController.DISMISS_USER_GESTURE) {
|
||||||
Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
|
Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
|
||||||
PendingIntent deleteIntent = bubbleMetadata != null
|
PendingIntent deleteIntent = bubbleMetadata != null
|
||||||
|
|||||||
@@ -74,8 +74,10 @@ internal class BubbleDataRepository @Inject constructor(
|
|||||||
|
|
||||||
private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
|
private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> {
|
||||||
return bubbles.mapNotNull { b ->
|
return bubbles.mapNotNull { b ->
|
||||||
val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null
|
var shortcutId = b.shortcutInfo?.id
|
||||||
BubbleEntity(userId, b.packageName, shortcutId)
|
if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
|
||||||
|
if (shortcutId == null) return@mapNotNull null
|
||||||
|
BubbleEntity(userId, b.packageName, shortcutId, b.key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +110,6 @@ internal class BubbleDataRepository @Inject constructor(
|
|||||||
/**
|
/**
|
||||||
* Load bubbles from disk.
|
* Load bubbles from disk.
|
||||||
*/
|
*/
|
||||||
// TODO: call this method from BubbleController and update UI
|
|
||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
|
fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch {
|
||||||
/**
|
/**
|
||||||
@@ -132,17 +133,17 @@ internal class BubbleDataRepository @Inject constructor(
|
|||||||
val shortcutKeys = entities.map { ShortcutKey(it.userId, it.packageName) }.toSet()
|
val shortcutKeys = entities.map { ShortcutKey(it.userId, it.packageName) }.toSet()
|
||||||
/**
|
/**
|
||||||
* Retrieve shortcuts with given userId/packageName combination, then construct a mapping
|
* Retrieve shortcuts with given userId/packageName combination, then construct a mapping
|
||||||
* between BubbleEntity and ShortcutInfo.
|
* from the userId/packageName pair to a list of associated ShortcutInfo.
|
||||||
* e.g.
|
* e.g.
|
||||||
* {
|
* {
|
||||||
* BubbleEntity(0, "com.example.messenger", "id-0") ->
|
* ShortcutKey(0, "com.example.messenger") -> [
|
||||||
* ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-0"),
|
* ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-0"),
|
||||||
* BubbleEntity(0, "com.example.messenger", "id-2") ->
|
* ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-2")
|
||||||
* ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-2"),
|
* ]
|
||||||
* BubbleEntity(10, "com.example.chat", "id-1") ->
|
* ShortcutKey(10, "com.example.chat") -> [
|
||||||
* ShortcutInfo(userId=10, pkg="com.example.chat", id="id-1"),
|
* ShortcutInfo(userId=10, pkg="com.example.chat", id="id-1"),
|
||||||
* BubbleEntity(10, "com.example.chat", "id-3") ->
|
|
||||||
* ShortcutInfo(userId=10, pkg="com.example.chat", id="id-3")
|
* ShortcutInfo(userId=10, pkg="com.example.chat", id="id-3")
|
||||||
|
* ]
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
val shortcutMap = shortcutKeys.flatMap { key ->
|
val shortcutMap = shortcutKeys.flatMap { key ->
|
||||||
@@ -150,11 +151,15 @@ internal class BubbleDataRepository @Inject constructor(
|
|||||||
LauncherApps.ShortcutQuery()
|
LauncherApps.ShortcutQuery()
|
||||||
.setPackage(key.pkg)
|
.setPackage(key.pkg)
|
||||||
.setQueryFlags(SHORTCUT_QUERY_FLAG), UserHandle.of(key.userId))
|
.setQueryFlags(SHORTCUT_QUERY_FLAG), UserHandle.of(key.userId))
|
||||||
?.map { BubbleEntity(key.userId, key.pkg, it.id) to it } ?: emptyList()
|
?: emptyList()
|
||||||
}.toMap()
|
}.groupBy { ShortcutKey(it.userId, it.`package`) }
|
||||||
// For each entity loaded from xml, find the corresponding ShortcutInfo then convert them
|
// For each entity loaded from xml, find the corresponding ShortcutInfo then convert them
|
||||||
// into Bubble.
|
// into Bubble.
|
||||||
val bubbles = entities.mapNotNull { entity -> shortcutMap[entity]?.let { Bubble(it) } }
|
val bubbles = entities.mapNotNull { entity ->
|
||||||
|
shortcutMap[ShortcutKey(entity.userId, entity.packageName)]
|
||||||
|
?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id }
|
||||||
|
?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo) }
|
||||||
|
}
|
||||||
uiScope.launch { cb(bubbles) }
|
uiScope.launch { cb(bubbles) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ import com.android.systemui.Dependency;
|
|||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.recents.TriangleShape;
|
import com.android.systemui.recents.TriangleShape;
|
||||||
import com.android.systemui.statusbar.AlphaOptimizedButton;
|
import com.android.systemui.statusbar.AlphaOptimizedButton;
|
||||||
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for the expanded bubble view, handles rendering the caret and settings icon.
|
* Container for the expanded bubble view, handles rendering the caret and settings icon.
|
||||||
@@ -161,7 +160,7 @@ public class BubbleExpandedView extends LinearLayout {
|
|||||||
// the bubble again so we'll just remove it.
|
// the bubble again so we'll just remove it.
|
||||||
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
|
Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey()
|
||||||
+ ", " + e.getMessage() + "; removing bubble");
|
+ ", " + e.getMessage() + "; removing bubble");
|
||||||
mBubbleController.removeBubble(getBubbleEntry(),
|
mBubbleController.removeBubble(getBubbleKey(),
|
||||||
BubbleController.DISMISS_INVALID_INTENT);
|
BubbleController.DISMISS_INVALID_INTENT);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -205,7 +204,7 @@ public class BubbleExpandedView extends LinearLayout {
|
|||||||
}
|
}
|
||||||
if (mBubble != null) {
|
if (mBubble != null) {
|
||||||
// Must post because this is called from a binder thread.
|
// Must post because this is called from a binder thread.
|
||||||
post(() -> mBubbleController.removeBubble(mBubble.getEntry(),
|
post(() -> mBubbleController.removeBubble(mBubble.getKey(),
|
||||||
BubbleController.DISMISS_TASK_FINISHED));
|
BubbleController.DISMISS_TASK_FINISHED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,10 +296,6 @@ public class BubbleExpandedView extends LinearLayout {
|
|||||||
return mBubble != null ? mBubble.getKey() : "null";
|
return mBubble != null ? mBubble.getKey() : "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
private NotificationEntry getBubbleEntry() {
|
|
||||||
return mBubble != null ? mBubble.getEntry() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setManageClickListener(OnClickListener manageClickListener) {
|
void setManageClickListener(OnClickListener manageClickListener) {
|
||||||
findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
|
findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
|
|||||||
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Notification;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -260,12 +259,9 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
|
|||||||
mPromoteBubbleFromOverflow.accept(b);
|
mPromoteBubbleFromOverflow.accept(b);
|
||||||
});
|
});
|
||||||
|
|
||||||
final CharSequence titleCharSeq =
|
String titleStr = b.getTitle();
|
||||||
b.getEntry().getSbn().getNotification().extras.getCharSequence(
|
if (titleStr == null) {
|
||||||
Notification.EXTRA_TITLE);
|
titleStr = mContext.getResources().getString(R.string.notification_bubble_title);
|
||||||
String titleStr = mContext.getResources().getString(R.string.notification_bubble_title);
|
|
||||||
if (titleCharSeq != null) {
|
|
||||||
titleStr = titleCharSeq.toString();
|
|
||||||
}
|
}
|
||||||
vh.iconView.setContentDescription(mContext.getResources().getString(
|
vh.iconView.setContentDescription(mContext.getResources().getString(
|
||||||
R.string.bubble_content_description_single, titleStr, b.getAppName()));
|
R.string.bubble_content_description_single, titleStr, b.getAppName()));
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import android.animation.Animator;
|
|||||||
import android.animation.AnimatorListenerAdapter;
|
import android.animation.AnimatorListenerAdapter;
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Notification;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -50,7 +49,6 @@ import android.graphics.RectF;
|
|||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.notification.StatusBarNotification;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
import android.view.DisplayCutout;
|
import android.view.DisplayCutout;
|
||||||
@@ -941,10 +939,10 @@ public class BubbleStackView extends FrameLayout
|
|||||||
showManageMenu(false /* show */);
|
showManageMenu(false /* show */);
|
||||||
final Bubble bubble = mBubbleData.getSelectedBubble();
|
final Bubble bubble = mBubbleData.getSelectedBubble();
|
||||||
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
||||||
final Intent intent = bubble.getSettingsIntent();
|
final Intent intent = bubble.getSettingsIntent(mContext);
|
||||||
collapseStack(() -> {
|
collapseStack(() -> {
|
||||||
mContext.startActivityAsUser(
|
|
||||||
intent, bubble.getEntry().getSbn().getUser());
|
mContext.startActivityAsUser(intent, bubble.getUser());
|
||||||
logBubbleClickEvent(
|
logBubbleClickEvent(
|
||||||
bubble,
|
bubble,
|
||||||
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
|
SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
|
||||||
@@ -1202,13 +1200,10 @@ public class BubbleStackView extends FrameLayout
|
|||||||
for (int i = 0; i < mBubbleData.getBubbles().size(); i++) {
|
for (int i = 0; i < mBubbleData.getBubbles().size(); i++) {
|
||||||
final Bubble bubble = mBubbleData.getBubbles().get(i);
|
final Bubble bubble = mBubbleData.getBubbles().get(i);
|
||||||
final String appName = bubble.getAppName();
|
final String appName = bubble.getAppName();
|
||||||
final Notification notification = bubble.getEntry().getSbn().getNotification();
|
|
||||||
final CharSequence titleCharSeq =
|
|
||||||
notification.extras.getCharSequence(Notification.EXTRA_TITLE);
|
|
||||||
|
|
||||||
String titleStr = getResources().getString(R.string.notification_bubble_title);
|
String titleStr = bubble.getTitle();
|
||||||
if (titleCharSeq != null) {
|
if (titleStr == null) {
|
||||||
titleStr = titleCharSeq.toString();
|
titleStr = getResources().getString(R.string.notification_bubble_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bubble.getIconView() != null) {
|
if (bubble.getIconView() != null) {
|
||||||
@@ -1821,7 +1816,7 @@ public class BubbleStackView extends FrameLayout
|
|||||||
private void dismissBubbleIfExists(@Nullable Bubble bubble) {
|
private void dismissBubbleIfExists(@Nullable Bubble bubble) {
|
||||||
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
|
||||||
mBubbleData.notificationEntryRemoved(
|
mBubbleData.notificationEntryRemoved(
|
||||||
bubble.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
bubble.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2319,18 +2314,12 @@ public class BubbleStackView extends FrameLayout
|
|||||||
* @param action the user interaction enum.
|
* @param action the user interaction enum.
|
||||||
*/
|
*/
|
||||||
private void logBubbleClickEvent(Bubble bubble, int action) {
|
private void logBubbleClickEvent(Bubble bubble, int action) {
|
||||||
StatusBarNotification notification = bubble.getEntry().getSbn();
|
bubble.logUIEvent(
|
||||||
SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED,
|
|
||||||
notification.getPackageName(),
|
|
||||||
notification.getNotification().getChannelId(),
|
|
||||||
notification.getId(),
|
|
||||||
getBubbleIndex(getExpandedBubble()),
|
|
||||||
getBubbleCount(),
|
getBubbleCount(),
|
||||||
action,
|
action,
|
||||||
getNormalizedXPosition(),
|
getNormalizedXPosition(),
|
||||||
getNormalizedYPosition(),
|
getNormalizedYPosition(),
|
||||||
bubble.showInShade(),
|
getBubbleIndex(getExpandedBubble())
|
||||||
false /* isOngoing (unused) */,
|
);
|
||||||
false /* isAppForeground (unused) */);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -74,6 +75,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
private WeakReference<Context> mContext;
|
private WeakReference<Context> mContext;
|
||||||
private WeakReference<BubbleStackView> mStackView;
|
private WeakReference<BubbleStackView> mStackView;
|
||||||
private BubbleIconFactory mIconFactory;
|
private BubbleIconFactory mIconFactory;
|
||||||
|
private boolean mSkipInflation;
|
||||||
private Callback mCallback;
|
private Callback mCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,17 +86,20 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
Context context,
|
Context context,
|
||||||
BubbleStackView stackView,
|
BubbleStackView stackView,
|
||||||
BubbleIconFactory factory,
|
BubbleIconFactory factory,
|
||||||
|
boolean skipInflation,
|
||||||
Callback c) {
|
Callback c) {
|
||||||
mBubble = b;
|
mBubble = b;
|
||||||
mContext = new WeakReference<>(context);
|
mContext = new WeakReference<>(context);
|
||||||
mStackView = new WeakReference<>(stackView);
|
mStackView = new WeakReference<>(stackView);
|
||||||
mIconFactory = factory;
|
mIconFactory = factory;
|
||||||
|
mSkipInflation = skipInflation;
|
||||||
mCallback = c;
|
mCallback = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BubbleViewInfo doInBackground(Void... voids) {
|
protected BubbleViewInfo doInBackground(Void... voids) {
|
||||||
return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble);
|
return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble,
|
||||||
|
mSkipInflation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -123,11 +128,36 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
static BubbleViewInfo populate(Context c, BubbleStackView stackView,
|
static BubbleViewInfo populate(Context c, BubbleStackView stackView,
|
||||||
BubbleIconFactory iconFactory, Bubble b) {
|
BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) {
|
||||||
|
final NotificationEntry entry = b.getEntry();
|
||||||
|
if (entry == null) {
|
||||||
|
// populate from ShortcutInfo when NotificationEntry is not available
|
||||||
|
final ShortcutInfo s = b.getShortcutInfo();
|
||||||
|
return populate(c, stackView, iconFactory, skipInflation || b.isInflated(),
|
||||||
|
s.getPackage(), s.getUserHandle(), s, null);
|
||||||
|
}
|
||||||
|
final StatusBarNotification sbn = entry.getSbn();
|
||||||
|
final String bubbleShortcutId = entry.getBubbleMetadata().getShortcutId();
|
||||||
|
final ShortcutInfo si = bubbleShortcutId == null
|
||||||
|
? null : entry.getRanking().getShortcutInfo();
|
||||||
|
return populate(
|
||||||
|
c, stackView, iconFactory, skipInflation || b.isInflated(),
|
||||||
|
sbn.getPackageName(), sbn.getUser(), si, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BubbleViewInfo populate(
|
||||||
|
@NonNull final Context c,
|
||||||
|
@NonNull final BubbleStackView stackView,
|
||||||
|
@NonNull final BubbleIconFactory iconFactory,
|
||||||
|
final boolean isInflated,
|
||||||
|
@NonNull final String packageName,
|
||||||
|
@NonNull final UserHandle user,
|
||||||
|
@Nullable final ShortcutInfo shortcutInfo,
|
||||||
|
@Nullable final NotificationEntry entry) {
|
||||||
BubbleViewInfo info = new BubbleViewInfo();
|
BubbleViewInfo info = new BubbleViewInfo();
|
||||||
|
|
||||||
// View inflation: only should do this once per bubble
|
// View inflation: only should do this once per bubble
|
||||||
if (!b.isInflated()) {
|
if (!isInflated) {
|
||||||
LayoutInflater inflater = LayoutInflater.from(c);
|
LayoutInflater inflater = LayoutInflater.from(c);
|
||||||
info.imageView = (BadgedImageView) inflater.inflate(
|
info.imageView = (BadgedImageView) inflater.inflate(
|
||||||
R.layout.bubble_view, stackView, false /* attachToRoot */);
|
R.layout.bubble_view, stackView, false /* attachToRoot */);
|
||||||
@@ -137,12 +167,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
info.expandedView.setStackView(stackView);
|
info.expandedView.setStackView(stackView);
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusBarNotification sbn = b.getEntry().getSbn();
|
if (shortcutInfo != null) {
|
||||||
String packageName = sbn.getPackageName();
|
info.shortcutInfo = shortcutInfo;
|
||||||
|
|
||||||
String bubbleShortcutId = b.getEntry().getBubbleMetadata().getShortcutId();
|
|
||||||
if (bubbleShortcutId != null) {
|
|
||||||
info.shortcutInfo = b.getEntry().getRanking().getShortcutInfo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// App name & app icon
|
// App name & app icon
|
||||||
@@ -161,7 +187,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
|
info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
|
||||||
}
|
}
|
||||||
appIcon = pm.getApplicationIcon(packageName);
|
appIcon = pm.getApplicationIcon(packageName);
|
||||||
badgedIcon = pm.getUserBadgedIcon(appIcon, sbn.getUser());
|
badgedIcon = pm.getUserBadgedIcon(appIcon, user);
|
||||||
} catch (PackageManager.NameNotFoundException exception) {
|
} catch (PackageManager.NameNotFoundException exception) {
|
||||||
// If we can't find package... don't think we should show the bubble.
|
// If we can't find package... don't think we should show the bubble.
|
||||||
Log.w(TAG, "Unable to find package: " + packageName);
|
Log.w(TAG, "Unable to find package: " + packageName);
|
||||||
@@ -170,7 +196,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
|
|
||||||
// Badged bubble image
|
// Badged bubble image
|
||||||
Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
|
Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
|
||||||
b.getEntry().getBubbleMetadata());
|
entry == null ? null : entry.getBubbleMetadata());
|
||||||
if (bubbleDrawable == null) {
|
if (bubbleDrawable == null) {
|
||||||
// Default to app icon
|
// Default to app icon
|
||||||
bubbleDrawable = appIcon;
|
bubbleDrawable = appIcon;
|
||||||
@@ -196,7 +222,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
|
|||||||
Color.WHITE, WHITE_SCRIM_ALPHA);
|
Color.WHITE, WHITE_SCRIM_ALPHA);
|
||||||
|
|
||||||
// Flyout
|
// Flyout
|
||||||
info.flyoutMessage = extractFlyoutMessage(c, b.getEntry());
|
if (entry != null) {
|
||||||
|
info.flyoutMessage = extractFlyoutMessage(c, entry);
|
||||||
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,5 +20,6 @@ import android.annotation.UserIdInt
|
|||||||
data class BubbleEntity(
|
data class BubbleEntity(
|
||||||
@UserIdInt val userId: Int,
|
@UserIdInt val userId: Int,
|
||||||
val packageName: String,
|
val packageName: String,
|
||||||
val shortcutId: String
|
val shortcutId: String,
|
||||||
|
val key: String
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ private const val TAG_BUBBLE = "bb"
|
|||||||
private const val ATTR_USER_ID = "uid"
|
private const val ATTR_USER_ID = "uid"
|
||||||
private const val ATTR_PACKAGE = "pkg"
|
private const val ATTR_PACKAGE = "pkg"
|
||||||
private const val ATTR_SHORTCUT_ID = "sid"
|
private const val ATTR_SHORTCUT_ID = "sid"
|
||||||
|
private const val ATTR_KEY = "key"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the bubbles in xml format into given output stream.
|
* Writes the bubbles in xml format into given output stream.
|
||||||
@@ -48,7 +49,7 @@ fun writeXml(stream: OutputStream, bubbles: List<BubbleEntity>) {
|
|||||||
/**
|
/**
|
||||||
* Creates a xml entry for given bubble in following format:
|
* Creates a xml entry for given bubble in following format:
|
||||||
* ```
|
* ```
|
||||||
* <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" />
|
* <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" key="my-key" />
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
|
private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
|
||||||
@@ -57,6 +58,7 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
|
|||||||
serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString())
|
serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString())
|
||||||
serializer.attribute(null, ATTR_PACKAGE, bubble.packageName)
|
serializer.attribute(null, ATTR_PACKAGE, bubble.packageName)
|
||||||
serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId)
|
serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId)
|
||||||
|
serializer.attribute(null, ATTR_KEY, bubble.key)
|
||||||
serializer.endTag(null, TAG_BUBBLE)
|
serializer.endTag(null, TAG_BUBBLE)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
throw RuntimeException(e)
|
throw RuntimeException(e)
|
||||||
@@ -83,7 +85,8 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? {
|
|||||||
return BubbleEntity(
|
return BubbleEntity(
|
||||||
parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null,
|
parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null,
|
||||||
parser.getAttributeWithName(ATTR_PACKAGE) ?: return null,
|
parser.getAttributeWithName(ATTR_PACKAGE) ?: return null,
|
||||||
parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null
|
parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null,
|
||||||
|
parser.getAttributeWithName(ATTR_KEY) ?: return null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
verify(mNotificationEntryManager).updateNotifications(any());
|
verify(mNotificationEntryManager).updateNotifications(any());
|
||||||
|
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||||
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
|
verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
mBubbleController.updateBubble(mRow2.getEntry());
|
mBubbleController.updateBubble(mRow2.getEntry());
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
|
||||||
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
|
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
|
||||||
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
|
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
|
||||||
@@ -352,9 +352,10 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
|
mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */
|
||||||
false, /* showInShade */ true);
|
false, /* showInShade */ true);
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
|
||||||
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
|
mBubbleController.removeBubble(
|
||||||
|
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||||
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
||||||
eq(mRow.getEntry().getSbn()), anyInt());
|
eq(mRow.getEntry().getSbn()), anyInt());
|
||||||
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
|
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
|
||||||
@@ -367,7 +368,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleController.hasBubbles());
|
assertTrue(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_CHANGED);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED);
|
||||||
verify(mNotificationEntryManager, never()).performRemoveNotification(
|
verify(mNotificationEntryManager, never()).performRemoveNotification(
|
||||||
eq(mRow.getEntry().getSbn()), anyInt());
|
eq(mRow.getEntry().getSbn()), anyInt());
|
||||||
assertFalse(mBubbleController.hasBubbles());
|
assertFalse(mBubbleController.hasBubbles());
|
||||||
@@ -565,7 +566,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss currently expanded
|
// Dismiss currently expanded
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
|
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey())
|
||||||
|
.getEntry().getKey(),
|
||||||
BubbleController.DISMISS_USER_GESTURE);
|
BubbleController.DISMISS_USER_GESTURE);
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||||
|
|
||||||
@@ -576,7 +578,8 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss that one
|
// Dismiss that one
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
|
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey())
|
||||||
|
.getEntry().getKey(),
|
||||||
BubbleController.DISMISS_USER_GESTURE);
|
BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
|
||||||
// Make sure state changes and collapse happens
|
// Make sure state changes and collapse happens
|
||||||
@@ -702,7 +705,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED);
|
mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
|
||||||
verify(mDeleteIntent, never()).send();
|
verify(mDeleteIntent, never()).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,7 +713,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verify(mDeleteIntent, times(1)).send();
|
verify(mDeleteIntent, times(1)).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,7 +816,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss the bubble into overflow.
|
// Dismiss the bubble into overflow.
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertFalse(mBubbleController.hasBubbles());
|
assertFalse(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||||
@@ -834,7 +837,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
mRow.getEntry()));
|
mRow.getEntry()));
|
||||||
|
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_NO_LONGER_BUBBLE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_NO_LONGER_BUBBLE);
|
||||||
assertFalse(mBubbleController.hasBubbles());
|
assertFalse(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
|
||||||
@@ -856,12 +859,12 @@ public class BubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
mBubbleData.setMaxOverflowBubbles(1);
|
mBubbleData.setMaxOverflowBubbles(1);
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertEquals(mBubbleData.getBubbles().size(), 2);
|
assertEquals(mBubbleData.getBubbles().size(), 2);
|
||||||
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
|
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
|
||||||
|
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow2.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
|
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
|
||||||
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
|
||||||
mRow.getEntry().getSbn(), REASON_CANCEL);
|
mRow.getEntry().getSbn(), REASON_CANCEL);
|
||||||
|
|||||||
@@ -177,7 +177,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
@@ -299,12 +300,14 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
mBubbleData.setMaxOverflowBubbles(1);
|
mBubbleData.setMaxOverflowBubbles(1);
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
|
assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
|
||||||
|
|
||||||
// Overflow max of 1 is reached; A1 is oldest, so it gets removed
|
// Overflow max of 1 is reached; A1 is oldest, so it gets removed
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
||||||
}
|
}
|
||||||
@@ -325,12 +328,14 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL);
|
mBubbleData.notificationEntryRemoved(mEntryA1.getKey(),
|
||||||
|
BubbleController.DISMISS_NOTIF_CANCEL);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
assertOverflowChangedTo(ImmutableList.of(mBubbleA2));
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_GROUP_CANCELLED);
|
mBubbleData.notificationEntryRemoved(mEntryA2.getKey(),
|
||||||
|
BubbleController.DISMISS_GROUP_CANCELLED);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertOverflowChangedTo(ImmutableList.of());
|
assertOverflowChangedTo(ImmutableList.of());
|
||||||
}
|
}
|
||||||
@@ -410,7 +415,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
// TODO: this should fail if things work as I expect them to?
|
// TODO: this should fail if things work as I expect them to?
|
||||||
assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
|
assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1);
|
||||||
@@ -430,7 +436,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertOrderNotChanged();
|
assertOrderNotChanged();
|
||||||
}
|
}
|
||||||
@@ -449,7 +456,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_NOTIF_CANCEL);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA2.getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertSelectionChangedTo(mBubbleB2);
|
assertSelectionChangedTo(mBubbleB2);
|
||||||
}
|
}
|
||||||
@@ -523,7 +531,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
|
||||||
// Verify the selection was cleared.
|
// Verify the selection was cleared.
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
@@ -623,7 +632,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryB2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleA1);
|
assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleA1);
|
||||||
}
|
}
|
||||||
@@ -647,11 +657,13 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertSelectionChangedTo(mBubbleB1);
|
assertSelectionChangedTo(mBubbleB1);
|
||||||
|
|
||||||
mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryB1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertSelectionChangedTo(mBubbleA1);
|
assertSelectionChangedTo(mBubbleA1);
|
||||||
}
|
}
|
||||||
@@ -765,7 +777,8 @@ public class BubbleDataTest extends SysuiTestCase {
|
|||||||
mBubbleData.setListener(mListener);
|
mBubbleData.setListener(mListener);
|
||||||
|
|
||||||
// Test
|
// Test
|
||||||
mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE);
|
mBubbleData.notificationEntryRemoved(
|
||||||
|
mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verifyUpdateReceived();
|
verifyUpdateReceived();
|
||||||
assertExpandedChangedTo(false);
|
assertExpandedChangedTo(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
assertTrue(mBubbleController.hasBubbles());
|
assertTrue(mBubbleController.hasBubbles());
|
||||||
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
|
verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
|
||||||
|
|
||||||
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mBubbleController.removeBubble(
|
||||||
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()));
|
||||||
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
||||||
}
|
}
|
||||||
@@ -304,7 +305,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
||||||
|
|
||||||
// Now remove the bubble
|
// Now remove the bubble
|
||||||
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mBubbleController.removeBubble(
|
||||||
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
||||||
|
|
||||||
// We don't remove the notification since the bubble is still in overflow.
|
// We don't remove the notification since the bubble is still in overflow.
|
||||||
@@ -324,7 +326,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true);
|
||||||
|
|
||||||
// Now remove the bubble
|
// Now remove the bubble
|
||||||
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
|
mBubbleController.removeBubble(
|
||||||
|
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||||
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
|
||||||
|
|
||||||
// Since the notif is dismissed and not in overflow, once the bubble is removed,
|
// Since the notif is dismissed and not in overflow, once the bubble is removed,
|
||||||
@@ -504,7 +507,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss currently expanded
|
// Dismiss currently expanded
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
|
mBubbleData.getBubbleInStackWithKey(
|
||||||
|
stackView.getExpandedBubble().getKey()).getEntry().getKey(),
|
||||||
BubbleController.DISMISS_USER_GESTURE);
|
BubbleController.DISMISS_USER_GESTURE);
|
||||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
|
||||||
|
|
||||||
@@ -515,7 +519,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss that one
|
// Dismiss that one
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
|
mBubbleData.getBubbleInStackWithKey(
|
||||||
|
stackView.getExpandedBubble().getKey()).getEntry().getKey(),
|
||||||
BubbleController.DISMISS_USER_GESTURE);
|
BubbleController.DISMISS_USER_GESTURE);
|
||||||
|
|
||||||
// Make sure state changes and collapse happens
|
// Make sure state changes and collapse happens
|
||||||
@@ -615,7 +620,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException {
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED);
|
mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED);
|
||||||
verify(mDeleteIntent, never()).send();
|
verify(mDeleteIntent, never()).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +628,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException {
|
||||||
mBubbleController.updateBubble(mRow.getEntry());
|
mBubbleController.updateBubble(mRow.getEntry());
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
verify(mDeleteIntent, times(1)).send();
|
verify(mDeleteIntent, times(1)).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,7 +696,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss the bubble
|
// Dismiss the bubble
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
|
||||||
assertFalse(mBubbleController.hasBubbles());
|
assertFalse(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
// Dismiss the notification
|
// Dismiss the notification
|
||||||
@@ -712,7 +717,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
// Dismiss the bubble
|
// Dismiss the bubble
|
||||||
mBubbleController.removeBubble(
|
mBubbleController.removeBubble(
|
||||||
mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL);
|
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
|
||||||
assertFalse(mBubbleController.hasBubbles());
|
assertFalse(mBubbleController.hasBubbles());
|
||||||
|
|
||||||
// Dismiss the notification
|
// Dismiss the notification
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ import org.junit.runner.RunWith
|
|||||||
class BubblePersistentRepositoryTest : SysuiTestCase() {
|
class BubblePersistentRepositoryTest : SysuiTestCase() {
|
||||||
|
|
||||||
private val bubbles = listOf(
|
private val bubbles = listOf(
|
||||||
BubbleEntity(0, "com.example.messenger", "shortcut-1"),
|
BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1"),
|
||||||
BubbleEntity(10, "com.example.chat", "alice and bob"),
|
BubbleEntity(10, "com.example.chat", "alice and bob", "key-2"),
|
||||||
BubbleEntity(0, "com.example.messenger", "shortcut-2")
|
BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3")
|
||||||
)
|
)
|
||||||
private lateinit var repository: BubblePersistentRepository
|
private lateinit var repository: BubblePersistentRepository
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ import org.junit.runner.RunWith
|
|||||||
@RunWith(AndroidTestingRunner::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
class BubbleVolatileRepositoryTest : SysuiTestCase() {
|
class BubbleVolatileRepositoryTest : SysuiTestCase() {
|
||||||
|
|
||||||
private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1")
|
private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1")
|
||||||
private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob")
|
private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob", "k2")
|
||||||
private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2")
|
private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3")
|
||||||
private val bubbles = listOf(bubble1, bubble2, bubble3)
|
private val bubbles = listOf(bubble1, bubble2, bubble3)
|
||||||
|
|
||||||
private lateinit var repository: BubbleVolatileRepository
|
private lateinit var repository: BubbleVolatileRepository
|
||||||
|
|||||||
@@ -31,17 +31,17 @@ import java.io.ByteArrayOutputStream
|
|||||||
class BubbleXmlHelperTest : SysuiTestCase() {
|
class BubbleXmlHelperTest : SysuiTestCase() {
|
||||||
|
|
||||||
private val bubbles = listOf(
|
private val bubbles = listOf(
|
||||||
BubbleEntity(0, "com.example.messenger", "shortcut-1"),
|
BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1"),
|
||||||
BubbleEntity(10, "com.example.chat", "alice and bob"),
|
BubbleEntity(10, "com.example.chat", "alice and bob", "k2"),
|
||||||
BubbleEntity(0, "com.example.messenger", "shortcut-2")
|
BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3")
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testWriteXml() {
|
fun testWriteXml() {
|
||||||
val expectedEntries = """
|
val expectedEntries = """
|
||||||
<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" />
|
<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" />
|
||||||
<bb uid="10" pkg="com.example.chat" sid="alice and bob" />
|
<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" />
|
||||||
<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" />
|
<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" />
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
ByteArrayOutputStream().use {
|
ByteArrayOutputStream().use {
|
||||||
writeXml(it, bubbles)
|
writeXml(it, bubbles)
|
||||||
@@ -56,9 +56,9 @@ class BubbleXmlHelperTest : SysuiTestCase() {
|
|||||||
val src = """
|
val src = """
|
||||||
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
|
||||||
<bs>
|
<bs>
|
||||||
<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" />
|
<bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" />
|
||||||
<bb uid="10" pkg="com.example.chat" sid="alice and bob" />
|
<bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" />
|
||||||
<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" />
|
<bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" />
|
||||||
</bs>
|
</bs>
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
|
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
|
||||||
|
|||||||
Reference in New Issue
Block a user