summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorMady Mellor <madym@google.com>2019-01-09 17:11:37 -0800
committerMady Mellor <madym@google.com>2019-01-15 10:28:31 -0800
commitc39b4aedb0a382d4c9717bbbc81e11c8dfdc3632 (patch)
treeca28ce57fb9c243e3ddbd3d0673dda9771f18155 /core/java/android
parent4a09436a63ba29888c39ba7ac631c6473f349a66 (diff)
Create BubbleMetadata use it instead of app overlay intent
* BubbleMetadata encapsulates necessary info to display a bubble * Replaces app overlay intent usages with BubbleMetadata * Renames existing bubble APIs to use 'bubble' rather than 'app overlay' Bug: 111236845 Test: existing tests pass Change-Id: I6a85d3c41dda47139fb8d960cadf1c8e109cf29b
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/INotificationManager.aidl6
-rw-r--r--core/java/android/app/Notification.java217
-rw-r--r--core/java/android/app/NotificationChannel.java50
-rw-r--r--core/java/android/app/NotificationManager.java8
4 files changed, 230 insertions, 51 deletions
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 163be8efc8fd..199c1338c50c 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -65,9 +65,9 @@ interface INotificationManager
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
- void setAppOverlaysAllowed(String pkg, int uid, boolean allowed);
- boolean areAppOverlaysAllowed(String pkg);
- boolean areAppOverlaysAllowedForPackage(String pkg, int uid);
+ void setBubblesAllowed(String pkg, int uid, boolean allowed);
+ boolean areBubblesAllowed(String pkg);
+ boolean areBubblesAllowedForPackage(String pkg, int uid);
void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b657a916604b..72819cb1493b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1276,7 +1276,7 @@ public class Notification implements Parcelable
private String mShortcutId;
private CharSequence mSettingsText;
- private PendingIntent mAppOverlayIntent;
+ private BubbleMetadata mBubbleMetadata;
/** @hide */
@IntDef(prefix = { "GROUP_ALERT_" }, value = {
@@ -2278,7 +2278,7 @@ public class Notification implements Parcelable
mGroupAlertBehavior = parcel.readInt();
if (parcel.readInt() != 0) {
- mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+ mBubbleMetadata = BubbleMetadata.CREATOR.createFromParcel(parcel);
}
mAllowSystemGeneratedContextualActions = parcel.readBoolean();
@@ -2396,7 +2396,7 @@ public class Notification implements Parcelable
that.mBadgeIcon = this.mBadgeIcon;
that.mSettingsText = this.mSettingsText;
that.mGroupAlertBehavior = this.mGroupAlertBehavior;
- that.mAppOverlayIntent = this.mAppOverlayIntent;
+ that.mBubbleMetadata = this.mBubbleMetadata;
that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;
if (!heavy) {
@@ -2719,9 +2719,9 @@ public class Notification implements Parcelable
parcel.writeInt(mGroupAlertBehavior);
- if (mAppOverlayIntent != null) {
+ if (mBubbleMetadata != null) {
parcel.writeInt(1);
- mAppOverlayIntent.writeToParcel(parcel, 0);
+ mBubbleMetadata.writeToParcel(parcel, 0);
} else {
parcel.writeInt(0);
}
@@ -3141,11 +3141,11 @@ public class Notification implements Parcelable
}
/**
- * Returns the intent that will be used to display app content in a floating window over the
- * existing foreground activity.
+ * Returns the bubble metadata that will be used to display app content in a floating window
+ * over the existing foreground activity.
*/
- public PendingIntent getAppOverlayIntent() {
- return mAppOverlayIntent;
+ public BubbleMetadata getBubbleMetadata() {
+ return mBubbleMetadata;
}
/**
@@ -3508,19 +3508,18 @@ public class Notification implements Parcelable
}
/**
- * Sets the intent that will be used to display app content in a floating window
- * over the existing foreground activity.
+ * Sets the {@link BubbleMetadata} that will be used to display app content in a floating
+ * window over the existing foreground activity.
*
- * <p>This intent will be ignored unless this notification is posted to a channel that
- * allows {@link NotificationChannel#canOverlayApps() app overlays}.</p>
+ * <p>This data will be ignored unless the notification is posted to a channel that
+ * allows {@link NotificationChannel#canBubble() bubbles}.</p>
*
- * <p>Notifications with a valid and allowed app overlay intent will be displayed as
- * floating windows outside of the notification shade on unlocked devices. When a user
- * interacts with one of these windows, this app overlay intent will be invoked and
- * displayed.</p>
+ * <b>Notifications with a valid and allowed bubble metadata will display in collapsed state
+ * outside of the notification shade on unlocked devices. When a user interacts with the
+ * collapsed state, the bubble intent will be invoked and displayed.</b>
*/
- public Builder setAppOverlayIntent(PendingIntent intent) {
- mN.mAppOverlayIntent = intent;
+ public Builder setBubbleMetadata(BubbleMetadata data) {
+ mN.mBubbleMetadata = data;
return this;
}
@@ -8422,6 +8421,186 @@ public class Notification implements Parcelable
}
}
+ /**
+ * Encapsulates the information needed to display a notification as a bubble.
+ *
+ * <p>A bubble is used to display app content in a floating window over the existing
+ * foreground activity. A bubble has a collapsed state represented by an icon,
+ * {@link BubbleMetadata.Builder#setIcon(Icon)} and an expanded state which is populated
+ * via {@link BubbleMetadata.Builder#setIntent(PendingIntent)}.</p>
+ *
+ * <b>Notifications with a valid and allowed bubble will display in collapsed state
+ * outside of the notification shade on unlocked devices. When a user interacts with the
+ * collapsed bubble, the bubble intent will be invoked and displayed.</b>
+ *
+ * @see Notification.Builder#setBubbleMetadata(BubbleMetadata)
+ */
+ public static final class BubbleMetadata implements Parcelable {
+
+ private PendingIntent mPendingIntent;
+ private CharSequence mTitle;
+ private Icon mIcon;
+ private int mDesiredHeight;
+
+ private BubbleMetadata(PendingIntent intent, CharSequence title, Icon icon, int height) {
+ mPendingIntent = intent;
+ mTitle = title;
+ mIcon = icon;
+ mDesiredHeight = height;
+ }
+
+ private BubbleMetadata(Parcel in) {
+ mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
+ mTitle = in.readCharSequence();
+ mIcon = Icon.CREATOR.createFromParcel(in);
+ mDesiredHeight = in.readInt();
+ }
+
+ /**
+ * @return the pending intent used to populate the floating window for this bubble.
+ */
+ public PendingIntent getIntent() {
+ return mPendingIntent;
+ }
+
+ /**
+ * @return the title that will appear along with the app content defined by
+ * {@link #getIntent()} for this bubble.
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * @return the icon that will be displayed for this bubble when it is collapsed.
+ */
+ public Icon getIcon() {
+ return mIcon;
+ }
+
+ /**
+ * @return the ideal height for the floating window that app content defined by
+ * {@link #getIntent()} for this bubble.
+ */
+ public int getDesiredHeight() {
+ return mDesiredHeight;
+ }
+
+ public static final Parcelable.Creator<BubbleMetadata> CREATOR =
+ new Parcelable.Creator<BubbleMetadata>() {
+
+ @Override
+ public BubbleMetadata createFromParcel(Parcel source) {
+ return new BubbleMetadata(source);
+ }
+
+ @Override
+ public BubbleMetadata[] newArray(int size) {
+ return new BubbleMetadata[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ mPendingIntent.writeToParcel(out, 0);
+ out.writeCharSequence(mTitle);
+ mIcon.writeToParcel(out, 0);
+ out.writeInt(mDesiredHeight);
+ }
+
+ /**
+ * Builder to construct a {@link BubbleMetadata} object.
+ */
+ public static class Builder {
+
+ private PendingIntent mPendingIntent;
+ private CharSequence mTitle;
+ private Icon mIcon;
+ private int mDesiredHeight;
+
+ /**
+ * Constructs a new builder object.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Sets the intent that will be used when the bubble is expanded. This will display the
+ * app content in a floating window over the existing foreground activity.
+ */
+ public BubbleMetadata.Builder setIntent(PendingIntent intent) {
+ if (intent == null) {
+ throw new IllegalArgumentException("Bubble requires non-null pending intent");
+ }
+ mPendingIntent = intent;
+ return this;
+ }
+
+ /**
+ * Sets the title that will appear along with the app content for this bubble.
+ *
+ * <p>A title is required and should expect to fit on a single line and make sense when
+ * shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
+ */
+ public BubbleMetadata.Builder setTitle(CharSequence title) {
+ if (TextUtils.isEmpty(title)) {
+ throw new IllegalArgumentException("Bubbles require non-null or empty title");
+ }
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets the icon that will represent the bubble when it is collapsed.
+ *
+ * <p>An icon is required and should be representative of the content within the bubble.
+ * If your app produces multiple bubbles, the image should be unique for each of them.
+ * </p>
+ */
+ public BubbleMetadata.Builder setIcon(Icon icon) {
+ if (icon == null) {
+ throw new IllegalArgumentException("Bubbles require non-null icon");
+ }
+ mIcon = icon;
+ return this;
+ }
+
+ /**
+ * Sets the desired height for the app content defined by
+ * {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
+ * enough space on the screen or if the provided height is too small to be useful.
+ */
+ public BubbleMetadata.Builder setDesiredHeight(int height) {
+ mDesiredHeight = Math.max(height, 0);
+ return this;
+ }
+
+ /**
+ * Creates the {@link BubbleMetadata} defined by this builder.
+ * <p>Will throw {@link IllegalStateException} if required fields have not been set
+ * on this builder.</p>
+ */
+ public BubbleMetadata build() {
+ if (mPendingIntent == null) {
+ throw new IllegalStateException("Must supply pending intent to bubble");
+ }
+ if (TextUtils.isEmpty(mTitle)) {
+ throw new IllegalStateException("Must supply a title for the bubble");
+ }
+ if (mIcon == null) {
+ throw new IllegalStateException("Must supply an icon for the bubble");
+ }
+ return new BubbleMetadata(mPendingIntent, mTitle, mIcon, mDesiredHeight);
+ }
+ }
+ }
+
+
// When adding a new Style subclass here, don't forget to update
// Builder.getNotificationStyleClass.
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 950e9aa939f8..e95d62fc96eb 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -85,7 +85,7 @@ public final class NotificationChannel implements Parcelable {
private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
private static final String ATT_GROUP = "group";
private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
- private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
+ private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
private static final String DELIMITER = ",";
/**
@@ -121,7 +121,7 @@ public final class NotificationChannel implements Parcelable {
/**
* @hide
*/
- public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100;
+ public static final int USER_LOCKED_ALLOW_BUBBLE = 0x00000100;
/**
* @hide
@@ -134,7 +134,7 @@ public final class NotificationChannel implements Parcelable {
USER_LOCKED_VIBRATION,
USER_LOCKED_SOUND,
USER_LOCKED_SHOW_BADGE,
- USER_LOCKED_ALLOW_APP_OVERLAY
+ USER_LOCKED_ALLOW_BUBBLE
};
private static final int DEFAULT_LIGHT_COLOR = 0;
@@ -144,7 +144,7 @@ public final class NotificationChannel implements Parcelable {
NotificationManager.IMPORTANCE_UNSPECIFIED;
private static final boolean DEFAULT_DELETED = false;
private static final boolean DEFAULT_SHOW_BADGE = true;
- private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
+ private static final boolean DEFAULT_ALLOW_BUBBLE = true;
@UnsupportedAppUsage
private final String mId;
@@ -168,7 +168,7 @@ public final class NotificationChannel implements Parcelable {
private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
// If this is a blockable system notification channel.
private boolean mBlockableSystem = false;
- private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
+ private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
private boolean mImportanceLockedByOEM;
/**
@@ -231,7 +231,7 @@ public final class NotificationChannel implements Parcelable {
mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null;
mLightColor = in.readInt();
mBlockableSystem = in.readBoolean();
- mAllowAppOverlay = in.readBoolean();
+ mAllowBubbles = in.readBoolean();
mImportanceLockedByOEM = in.readBoolean();
}
@@ -285,7 +285,7 @@ public final class NotificationChannel implements Parcelable {
}
dest.writeInt(mLightColor);
dest.writeBoolean(mBlockableSystem);
- dest.writeBoolean(mAllowAppOverlay);
+ dest.writeBoolean(mAllowBubbles);
dest.writeBoolean(mImportanceLockedByOEM);
}
@@ -480,7 +480,7 @@ public final class NotificationChannel implements Parcelable {
/**
* Sets whether notifications posted to this channel can appear outside of the notification
- * shade, floating over other apps' content.
+ * shade, floating over other apps' content as a bubble.
*
* <p>This value will be ignored for channels that aren't allowed to pop on screen (that is,
* channels whose {@link #getImportance() importance} is <
@@ -488,10 +488,10 @@ public final class NotificationChannel implements Parcelable {
*
* <p>Only modifiable before the channel is submitted to
* * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p>
- * @see Notification#getAppOverlayIntent()
+ * @see Notification#getBubbleMetadata()
*/
- public void setAllowAppOverlay(boolean allowAppOverlay) {
- mAllowAppOverlay = allowAppOverlay;
+ public void setAllowBubbles(boolean allowBubbles) {
+ mAllowBubbles = allowBubbles;
}
/**
@@ -610,16 +610,16 @@ public final class NotificationChannel implements Parcelable {
* Returns whether notifications posted to this channel can display outside of the notification
* shade, in a floating window on top of other apps.
*/
- public boolean canOverlayApps() {
- return isAppOverlayAllowed() && getImportance() >= IMPORTANCE_HIGH;
+ public boolean canBubble() {
+ return isBubbleAllowed() && getImportance() >= IMPORTANCE_HIGH;
}
/**
- * Like {@link #canOverlayApps()}, but only checks the permission, not the importance.
+ * Like {@link #canBubble()}, but only checks the permission, not the importance.
* @hide
*/
- public boolean isAppOverlayAllowed() {
- return mAllowAppOverlay;
+ public boolean isBubbleAllowed() {
+ return mAllowBubbles;
}
/**
@@ -719,7 +719,7 @@ public final class NotificationChannel implements Parcelable {
lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false));
setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false));
- setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
+ setAllowBubbles(safeBool(parser, ATT_ALLOW_BUBBLE, DEFAULT_ALLOW_BUBBLE));
}
@Nullable
@@ -838,8 +838,8 @@ public final class NotificationChannel implements Parcelable {
if (isBlockableSystem()) {
out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockableSystem()));
}
- if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
- out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
+ if (canBubble() != DEFAULT_ALLOW_BUBBLE) {
+ out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
}
out.endTag(null, TAG_CHANNEL);
@@ -883,7 +883,7 @@ public final class NotificationChannel implements Parcelable {
record.put(ATT_DELETED, Boolean.toString(isDeleted()));
record.put(ATT_GROUP, getGroup());
record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem());
- record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
+ record.put(ATT_ALLOW_BUBBLE, canBubble());
return record;
}
@@ -983,7 +983,7 @@ public final class NotificationChannel implements Parcelable {
&& mShowBadge == that.mShowBadge
&& isDeleted() == that.isDeleted()
&& isBlockableSystem() == that.isBlockableSystem()
- && mAllowAppOverlay == that.mAllowAppOverlay
+ && mAllowBubbles == that.mAllowBubbles
&& Objects.equals(getId(), that.getId())
&& Objects.equals(getName(), that.getName())
&& Objects.equals(mDesc, that.mDesc)
@@ -1000,7 +1000,7 @@ public final class NotificationChannel implements Parcelable {
getLockscreenVisibility(), getSound(), mLights, getLightColor(),
getUserLockedFields(),
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
- getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay,
+ getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
mImportanceLockedByOEM);
result = 31 * result + Arrays.hashCode(mVibration);
return result;
@@ -1028,7 +1028,7 @@ public final class NotificationChannel implements Parcelable {
+ ", mGroup='" + mGroup + '\''
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
- + ", mAllowAppOverlay=" + mAllowAppOverlay
+ + ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ '}';
pw.println(prefix + output);
@@ -1055,7 +1055,7 @@ public final class NotificationChannel implements Parcelable {
+ ", mGroup='" + mGroup + '\''
+ ", mAudioAttributes=" + mAudioAttributes
+ ", mBlockableSystem=" + mBlockableSystem
- + ", mAllowAppOverlay=" + mAllowAppOverlay
+ + ", mAllowBubbles=" + mAllowBubbles
+ ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+ '}';
}
@@ -1090,7 +1090,7 @@ public final class NotificationChannel implements Parcelable {
mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES);
}
proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem);
- proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
+ proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowBubbles);
proto.end(token);
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index aad32532bbe8..43614feb28a4 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1080,14 +1080,14 @@ public class NotificationManager {
* notification shade, floating over other apps' content.
*
* <p>This value will be ignored for notifications that are posted to channels that do not
- * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
+ * allow bubbles ({@link NotificationChannel#canBubble()}.
*
- * @see Notification#getAppOverlayIntent()
+ * @see Notification#getBubbleMetadata()
*/
- public boolean areAppOverlaysAllowed() {
+ public boolean areBubblesAllowed() {
INotificationManager service = getService();
try {
- return service.areAppOverlaysAllowed(mContext.getPackageName());
+ return service.areBubblesAllowed(mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}