Loading api/current.txt +6 −0 Original line number Original line Diff line number Diff line Loading @@ -5217,6 +5217,7 @@ package android.app { ctor public Notification(android.os.Parcel); ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public android.app.Notification clone(); method public int describeContents(); method public int describeContents(); method public android.app.PendingIntent getAppOverlayIntent(); method public int getBadgeIconType(); method public int getBadgeIconType(); method public java.lang.String getChannelId(); method public java.lang.String getChannelId(); method public java.lang.String getGroup(); method public java.lang.String getGroup(); Loading Loading @@ -5446,6 +5447,7 @@ package android.app { method public android.app.Notification.Style getStyle(); method public android.app.Notification.Style getStyle(); method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setBadgeIconType(int); method public android.app.Notification.Builder setBadgeIconType(int); method public android.app.Notification.Builder setCategory(java.lang.String); method public android.app.Notification.Builder setCategory(java.lang.String); Loading Loading @@ -5663,6 +5665,7 @@ package android.app { public final class NotificationChannel implements android.os.Parcelable { public final class NotificationChannel implements android.os.Parcelable { ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); method public boolean canBypassDnd(); method public boolean canBypassDnd(); method public boolean canOverlayApps(); method public boolean canShowBadge(); method public boolean canShowBadge(); method public int describeContents(); method public int describeContents(); method public void enableLights(boolean); method public void enableLights(boolean); Loading @@ -5678,6 +5681,7 @@ package android.app { method public android.net.Uri getSound(); method public android.net.Uri getSound(); method public long[] getVibrationPattern(); method public long[] getVibrationPattern(); method public boolean hasUserSetImportance(); method public boolean hasUserSetImportance(); method public void setAllowAppOverlay(boolean); method public void setBypassDnd(boolean); method public void setBypassDnd(boolean); method public void setDescription(java.lang.String); method public void setDescription(java.lang.String); method public void setGroup(java.lang.String); method public void setGroup(java.lang.String); Loading @@ -5697,6 +5701,7 @@ package android.app { public final class NotificationChannelGroup implements android.os.Parcelable { public final class NotificationChannelGroup implements android.os.Parcelable { ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); method public boolean canOverlayApps(); method public android.app.NotificationChannelGroup clone(); method public android.app.NotificationChannelGroup clone(); method public int describeContents(); method public int describeContents(); method public java.util.List<android.app.NotificationChannel> getChannels(); method public java.util.List<android.app.NotificationChannel> getChannels(); Loading @@ -5704,6 +5709,7 @@ package android.app { method public java.lang.String getId(); method public java.lang.String getId(); method public java.lang.CharSequence getName(); method public java.lang.CharSequence getName(); method public boolean isBlocked(); method public boolean isBlocked(); method public void setAllowAppOverlay(boolean); method public void setDescription(java.lang.String); method public void setDescription(java.lang.String); method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR; field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR; api/test-current.txt +3 −0 Original line number Original line Diff line number Diff line Loading @@ -140,7 +140,10 @@ package android.app { } } public final class NotificationChannelGroup implements android.os.Parcelable { public final class NotificationChannelGroup implements android.os.Parcelable { method public int getUserLockedFields(); method public void lockFields(int); method public void setBlocked(boolean); method public void setBlocked(boolean); field public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 2; // 0x2 } } public class NotificationManager { public class NotificationManager { Loading core/java/android/app/Notification.java +38 −0 Original line number Original line Diff line number Diff line Loading @@ -1275,6 +1275,8 @@ public class Notification implements Parcelable private String mShortcutId; private String mShortcutId; private CharSequence mSettingsText; private CharSequence mSettingsText; private PendingIntent mAppOverlayIntent; /** @hide */ /** @hide */ @IntDef(prefix = { "GROUP_ALERT_" }, value = { @IntDef(prefix = { "GROUP_ALERT_" }, value = { GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY Loading Loading @@ -2225,6 +2227,9 @@ public class Notification implements Parcelable } } mGroupAlertBehavior = parcel.readInt(); mGroupAlertBehavior = parcel.readInt(); if (parcel.readInt() != 0) { mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel); } } } @Override @Override Loading Loading @@ -2339,6 +2344,7 @@ public class Notification implements Parcelable that.mBadgeIcon = this.mBadgeIcon; that.mBadgeIcon = this.mBadgeIcon; that.mSettingsText = this.mSettingsText; that.mSettingsText = this.mSettingsText; that.mGroupAlertBehavior = this.mGroupAlertBehavior; that.mGroupAlertBehavior = this.mGroupAlertBehavior; that.mAppOverlayIntent = this.mAppOverlayIntent; if (!heavy) { if (!heavy) { that.lightenPayload(); // will clean out extras that.lightenPayload(); // will clean out extras Loading Loading @@ -2660,6 +2666,13 @@ public class Notification implements Parcelable parcel.writeInt(mGroupAlertBehavior); parcel.writeInt(mGroupAlertBehavior); if (mAppOverlayIntent != null) { parcel.writeInt(1); mAppOverlayIntent.writeToParcel(parcel, 0); } else { parcel.writeInt(0); } // mUsesStandardHeader is not written because it should be recomputed in listeners // mUsesStandardHeader is not written because it should be recomputed in listeners } } Loading Loading @@ -3072,6 +3085,14 @@ public class Notification implements Parcelable return mGroupAlertBehavior; return mGroupAlertBehavior; } } /** * Returns the intent that will be used to display app content in a floating window over the * existing foreground activity. */ public PendingIntent getAppOverlayIntent() { return mAppOverlayIntent; } /** /** * The small icon representing this notification in the status bar and content view. * The small icon representing this notification in the status bar and content view. * * Loading Loading @@ -3406,6 +3427,23 @@ public class Notification implements Parcelable return this; return this; } } /** * Sets the intent 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>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> */ public Builder setAppOverlayIntent(PendingIntent intent) { mN.mAppOverlayIntent = intent; return this; } /** @removed */ /** @removed */ @Deprecated @Deprecated public Builder setChannel(String channelId) { public Builder setChannel(String channelId) { Loading core/java/android/app/NotificationChannel.java +79 −46 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ */ package android.app; package android.app; import static android.app.NotificationManager.IMPORTANCE_HIGH; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; Loading @@ -41,6 +43,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.IOException; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.Arrays; import java.util.Objects; /** /** * A representation of settings that apply to a collection of similarly themed notifications. * A representation of settings that apply to a collection of similarly themed notifications. Loading Loading @@ -81,6 +84,7 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; private static final String ATT_GROUP = "group"; private static final String ATT_GROUP = "group"; private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay"; private static final String DELIMITER = ","; private static final String DELIMITER = ","; /** /** Loading Loading @@ -113,6 +117,11 @@ public final class NotificationChannel implements Parcelable { */ */ public static final int USER_LOCKED_SHOW_BADGE = 0x00000080; public static final int USER_LOCKED_SHOW_BADGE = 0x00000080; /** * @hide */ public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100; /** /** * @hide * @hide */ */ Loading @@ -124,6 +133,7 @@ public final class NotificationChannel implements Parcelable { USER_LOCKED_VIBRATION, USER_LOCKED_VIBRATION, USER_LOCKED_SOUND, USER_LOCKED_SOUND, USER_LOCKED_SHOW_BADGE, USER_LOCKED_SHOW_BADGE, USER_LOCKED_ALLOW_APP_OVERLAY }; }; private static final int DEFAULT_LIGHT_COLOR = 0; private static final int DEFAULT_LIGHT_COLOR = 0; Loading @@ -133,6 +143,7 @@ public final class NotificationChannel implements Parcelable { NotificationManager.IMPORTANCE_UNSPECIFIED; NotificationManager.IMPORTANCE_UNSPECIFIED; private static final boolean DEFAULT_DELETED = false; private static final boolean DEFAULT_DELETED = false; private static final boolean DEFAULT_SHOW_BADGE = true; private static final boolean DEFAULT_SHOW_BADGE = true; private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true; @UnsupportedAppUsage @UnsupportedAppUsage private final String mId; private final String mId; Loading @@ -156,6 +167,7 @@ public final class NotificationChannel implements Parcelable { private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; // If this is a blockable system notification channel. // If this is a blockable system notification channel. private boolean mBlockableSystem = false; private boolean mBlockableSystem = false; private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY; /** /** * Creates a notification channel. * Creates a notification channel. Loading Loading @@ -217,6 +229,7 @@ public final class NotificationChannel implements Parcelable { mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null; mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null; mLightColor = in.readInt(); mLightColor = in.readInt(); mBlockableSystem = in.readBoolean(); mBlockableSystem = in.readBoolean(); mAllowAppOverlay = in.readBoolean(); } } @Override @Override Loading Loading @@ -269,6 +282,7 @@ public final class NotificationChannel implements Parcelable { } } dest.writeInt(mLightColor); dest.writeInt(mLightColor); dest.writeBoolean(mBlockableSystem); dest.writeBoolean(mBlockableSystem); dest.writeBoolean(mAllowAppOverlay); } } /** /** Loading Loading @@ -460,6 +474,22 @@ public final class NotificationChannel implements Parcelable { this.mLockscreenVisibility = lockscreenVisibility; this.mLockscreenVisibility = lockscreenVisibility; } } /** * Sets whether notifications posted to this channel can appear outside of the notification * shade, floating over other apps' content. * * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is, * channels whose {@link #getImportance() importance} is < * {@link NotificationManager#IMPORTANCE_HIGH}.</p> * * <p>Only modifiable before the channel is submitted to * * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p> * @see Notification#getAppOverlayIntent() */ public void setAllowAppOverlay(boolean allowAppOverlay) { mAllowAppOverlay = allowAppOverlay; } /** /** * Returns the id of this channel. * Returns the id of this channel. */ */ Loading Loading @@ -572,6 +602,22 @@ public final class NotificationChannel implements Parcelable { return mGroup; return mGroup; } } /** * 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; } /** * Like {@link #canOverlayApps()}, but only checks the permission, not the importance. * @hide */ public boolean isAppOverlayAllowed() { return mAllowAppOverlay; } /** /** * @hide * @hide */ */ Loading Loading @@ -605,6 +651,7 @@ public final class NotificationChannel implements Parcelable { /** /** * Returns whether the user has chosen the importance of this channel, either to affirm the * Returns whether the user has chosen the importance of this channel, either to affirm the * initial selection from the app, or changed it to be higher or lower. * initial selection from the app, or changed it to be higher or lower. * @see #getImportance() */ */ public boolean hasUserSetImportance() { public boolean hasUserSetImportance() { return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; Loading Loading @@ -652,6 +699,7 @@ public final class NotificationChannel implements Parcelable { lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY)); } } @Nullable @Nullable Loading Loading @@ -770,6 +818,9 @@ public final class NotificationChannel implements Parcelable { if (isBlockableSystem()) { if (isBlockableSystem()) { out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(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())); } out.endTag(null, TAG_CHANNEL); out.endTag(null, TAG_CHANNEL); } } Loading Loading @@ -812,6 +863,7 @@ public final class NotificationChannel implements Parcelable { record.put(ATT_DELETED, Boolean.toString(isDeleted())); record.put(ATT_DELETED, Boolean.toString(isDeleted())); record.put(ATT_GROUP, getGroup()); record.put(ATT_GROUP, getGroup()); record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem()); record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem()); record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps()); return record; return record; } } Loading Loading @@ -899,58 +951,36 @@ public final class NotificationChannel implements Parcelable { public boolean equals(Object o) { public boolean equals(Object o) { if (this == o) return true; if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false; NotificationChannel that = (NotificationChannel) o; NotificationChannel that = (NotificationChannel) o; return getImportance() == that.getImportance() && if (getImportance() != that.getImportance()) return false; mBypassDnd == that.mBypassDnd && if (mBypassDnd != that.mBypassDnd) return false; getLockscreenVisibility() == that.getLockscreenVisibility() && if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false; mLights == that.mLights && if (mLights != that.mLights) return false; getLightColor() == that.getLightColor() && if (getLightColor() != that.getLightColor()) return false; getUserLockedFields() == that.getUserLockedFields() && if (getUserLockedFields() != that.getUserLockedFields()) return false; isFgServiceShown() == that.isFgServiceShown() && if (mVibrationEnabled != that.mVibrationEnabled) return false; mVibrationEnabled == that.mVibrationEnabled && if (mShowBadge != that.mShowBadge) return false; mShowBadge == that.mShowBadge && if (isDeleted() != that.isDeleted()) return false; isDeleted() == that.isDeleted() && if (isBlockableSystem() != that.isBlockableSystem()) return false; isBlockableSystem() == that.isBlockableSystem() && if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; mAllowAppOverlay == that.mAllowAppOverlay && if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { Objects.equals(getId(), that.getId()) && return false; Objects.equals(getName(), that.getName()) && } Objects.equals(mDesc, that.mDesc) && if (getDescription() != null ? !getDescription().equals(that.getDescription()) Objects.equals(getSound(), that.getSound()) && : that.getDescription() != null) { Arrays.equals(mVibration, that.mVibration) && return false; Objects.equals(getGroup(), that.getGroup()) && } Objects.equals(getAudioAttributes(), that.getAudioAttributes()); if (getSound() != null ? !getSound().equals(that.getSound()) : that.getSound() != null) { return false; } if (!Arrays.equals(mVibration, that.mVibration)) return false; if (getGroup() != null ? !getGroup().equals(that.getGroup()) : that.getGroup() != null) { return false; } return getAudioAttributes() != null ? getAudioAttributes().equals(that.getAudioAttributes()) : that.getAudioAttributes() == null; } } @Override @Override public int hashCode() { public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd, result = 31 * result + (getName() != null ? getName().hashCode() : 0); getLockscreenVisibility(), getSound(), mLights, getLightColor(), result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0); getUserLockedFields(), result = 31 * result + getImportance(); isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(), result = 31 * result + (mBypassDnd ? 1 : 0); getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay); result = 31 * result + getLockscreenVisibility(); result = 31 * result + (getSound() != null ? getSound().hashCode() : 0); result = 31 * result + (mLights ? 1 : 0); result = 31 * result + getLightColor(); result = 31 * result + Arrays.hashCode(mVibration); result = 31 * result + Arrays.hashCode(mVibration); result = 31 * result + getUserLockedFields(); result = 31 * result + (mVibrationEnabled ? 1 : 0); result = 31 * result + (mShowBadge ? 1 : 0); result = 31 * result + (isDeleted() ? 1 : 0); result = 31 * result + (getGroup() != null ? getGroup().hashCode() : 0); result = 31 * result + (getAudioAttributes() != null ? getAudioAttributes().hashCode() : 0); result = 31 * result + (isBlockableSystem() ? 1 : 0); return result; return result; } } Loading @@ -976,6 +1006,7 @@ public final class NotificationChannel implements Parcelable { + ", mGroup='" + mGroup + '\'' + ", mGroup='" + mGroup + '\'' + ", mAudioAttributes=" + mAudioAttributes + ", mAudioAttributes=" + mAudioAttributes + ", mBlockableSystem=" + mBlockableSystem + ", mBlockableSystem=" + mBlockableSystem + ", mAllowAppOverlay=" + mAllowAppOverlay + '}'; + '}'; pw.println(prefix + output); pw.println(prefix + output); } } Loading @@ -1001,6 +1032,7 @@ public final class NotificationChannel implements Parcelable { + ", mGroup='" + mGroup + '\'' + ", mGroup='" + mGroup + '\'' + ", mAudioAttributes=" + mAudioAttributes + ", mAudioAttributes=" + mAudioAttributes + ", mBlockableSystem=" + mBlockableSystem + ", mBlockableSystem=" + mBlockableSystem + ", mAllowAppOverlay=" + mAllowAppOverlay + '}'; + '}'; } } Loading Loading @@ -1034,6 +1066,7 @@ public final class NotificationChannel implements Parcelable { mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES); mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES); } } proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem); proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem); proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay); proto.end(token); proto.end(token); } } Loading core/java/android/app/NotificationChannelGroup.java +93 −20 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.IOException; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; import java.util.Objects; /** /** * A grouping of related notification channels. e.g., channels that all belong to a single account. * A grouping of related notification channels. e.g., channels that all belong to a single account. Loading @@ -49,13 +50,33 @@ public final class NotificationChannelGroup implements Parcelable { private static final String ATT_DESC = "desc"; private static final String ATT_DESC = "desc"; private static final String ATT_ID = "id"; private static final String ATT_ID = "id"; private static final String ATT_BLOCKED = "blocked"; private static final String ATT_BLOCKED = "blocked"; private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay"; private static final String ATT_USER_LOCKED = "locked"; private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true; /** * @hide */ public static final int USER_LOCKED_BLOCKED_STATE = 0x00000001; /** * @hide */ @TestApi public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000002; /** * @see #getId() */ @UnsupportedAppUsage @UnsupportedAppUsage private final String mId; private final String mId; private CharSequence mName; private CharSequence mName; private String mDescription; private String mDescription; private boolean mBlocked; private boolean mBlocked; private List<NotificationChannel> mChannels = new ArrayList<>(); private List<NotificationChannel> mChannels = new ArrayList<>(); private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY; // Bitwise representation of fields that have been changed by the user private int mUserLockedFields; /** /** * Creates a notification channel group. * Creates a notification channel group. Loading Loading @@ -89,6 +110,8 @@ public final class NotificationChannelGroup implements Parcelable { } } in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader()); in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader()); mBlocked = in.readBoolean(); mBlocked = in.readBoolean(); mAllowAppOverlay = in.readBoolean(); mUserLockedFields = in.readInt(); } } private String getTrimmedString(String input) { private String getTrimmedString(String input) { Loading @@ -115,6 +138,8 @@ public final class NotificationChannelGroup implements Parcelable { } } dest.writeParcelableList(mChannels, flags); dest.writeParcelableList(mChannels, flags); dest.writeBoolean(mBlocked); dest.writeBoolean(mBlocked); dest.writeBoolean(mAllowAppOverlay); dest.writeInt(mUserLockedFields); } } /** /** Loading Loading @@ -155,6 +180,15 @@ public final class NotificationChannelGroup implements Parcelable { return mBlocked; return mBlocked; } } /** * Returns whether notifications posted to this channel group can display outside of the * notification shade, in a floating window on top of other apps. These may additionally be * blocked at the notification channel level, see {@link NotificationChannel#canOverlayApps()}. */ public boolean canOverlayApps() { return mAllowAppOverlay; } /** /** * Sets the user visible description of this group. * Sets the user visible description of this group. * * Loading @@ -165,6 +199,21 @@ public final class NotificationChannelGroup implements Parcelable { mDescription = getTrimmedString(description); mDescription = getTrimmedString(description); } } /** * Sets whether notifications posted to this channel group can appear outside of the * 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()}. * * <p>Only modifiable before the channel is submitted to * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.</p> * @see Notification#getAppOverlayIntent() */ public void setAllowAppOverlay(boolean allowAppOverlay) { mAllowAppOverlay = allowAppOverlay; } /** /** * @hide * @hide */ */ Loading @@ -187,6 +236,29 @@ public final class NotificationChannelGroup implements Parcelable { mChannels = channels; mChannels = channels; } } /** * @hide */ @TestApi public void lockFields(int field) { mUserLockedFields |= field; } /** * @hide */ public void unlockFields(int field) { mUserLockedFields &= ~field; } /** * @hide */ @TestApi public int getUserLockedFields() { return mUserLockedFields; } /** /** * @hide * @hide */ */ Loading @@ -194,6 +266,7 @@ public final class NotificationChannelGroup implements Parcelable { // Name, id, and importance are set in the constructor. // Name, id, and importance are set in the constructor. setDescription(parser.getAttributeValue(null, ATT_DESC)); setDescription(parser.getAttributeValue(null, ATT_DESC)); setBlocked(safeBool(parser, ATT_BLOCKED, false)); setBlocked(safeBool(parser, ATT_BLOCKED, false)); setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY)); } } private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) { private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) { Loading @@ -216,6 +289,10 @@ public final class NotificationChannelGroup implements Parcelable { out.attribute(null, ATT_DESC, getDescription().toString()); out.attribute(null, ATT_DESC, getDescription().toString()); } } out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked())); out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked())); if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) { out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps())); } out.attribute(null, ATT_USER_LOCKED, Integer.toString(mUserLockedFields)); out.endTag(null, TAG_GROUP); out.endTag(null, TAG_GROUP); } } Loading @@ -230,6 +307,8 @@ public final class NotificationChannelGroup implements Parcelable { record.put(ATT_NAME, getName()); record.put(ATT_NAME, getName()); record.put(ATT_DESC, getDescription()); record.put(ATT_DESC, getDescription()); record.put(ATT_BLOCKED, isBlocked()); record.put(ATT_BLOCKED, isBlocked()); record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps()); record.put(ATT_USER_LOCKED, mUserLockedFields); return record; return record; } } Loading @@ -255,30 +334,20 @@ public final class NotificationChannelGroup implements Parcelable { public boolean equals(Object o) { public boolean equals(Object o) { if (this == o) return true; if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false; NotificationChannelGroup that = (NotificationChannelGroup) o; NotificationChannelGroup that = (NotificationChannelGroup) o; return isBlocked() == that.isBlocked() && if (isBlocked() != that.isBlocked()) return false; mAllowAppOverlay == that.mAllowAppOverlay && if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; mUserLockedFields == that.mUserLockedFields && if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { Objects.equals(getId(), that.getId()) && return false; Objects.equals(getName(), that.getName()) && } Objects.equals(getDescription(), that.getDescription()) && if (getDescription() != null ? !getDescription().equals(that.getDescription()) Objects.equals(getChannels(), that.getChannels()); : that.getDescription() != null) { return false; } return getChannels() != null ? getChannels().equals(that.getChannels()) : that.getChannels() == null; } } @Override @Override public int hashCode() { public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; return Objects.hash(getId(), getName(), getDescription(), isBlocked(), getChannels(), result = 31 * result + (getName() != null ? getName().hashCode() : 0); mAllowAppOverlay, mUserLockedFields); result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0); result = 31 * result + (isBlocked() ? 1 : 0); result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0); return result; } } @Override @Override Loading @@ -287,6 +356,8 @@ public final class NotificationChannelGroup implements Parcelable { cloned.setDescription(getDescription()); cloned.setDescription(getDescription()); cloned.setBlocked(isBlocked()); cloned.setBlocked(isBlocked()); cloned.setChannels(getChannels()); cloned.setChannels(getChannels()); cloned.setAllowAppOverlay(canOverlayApps()); cloned.lockFields(mUserLockedFields); return cloned; return cloned; } } Loading @@ -298,6 +369,8 @@ public final class NotificationChannelGroup implements Parcelable { + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "") + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "") + ", mBlocked=" + mBlocked + ", mBlocked=" + mBlocked + ", mChannels=" + mChannels + ", mChannels=" + mChannels + ", mAllowAppOverlay=" + mAllowAppOverlay + ", mUserLockedFields=" + mUserLockedFields + '}'; + '}'; } } Loading @@ -312,7 +385,7 @@ public final class NotificationChannelGroup implements Parcelable { for (NotificationChannel channel : mChannels) { for (NotificationChannel channel : mChannels) { channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS); channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS); } } proto.write(NotificationChannelGroupProto.ALLOW_APP_OVERLAY, mAllowAppOverlay); proto.end(token); proto.end(token); } } } } Loading
api/current.txt +6 −0 Original line number Original line Diff line number Diff line Loading @@ -5217,6 +5217,7 @@ package android.app { ctor public Notification(android.os.Parcel); ctor public Notification(android.os.Parcel); method public android.app.Notification clone(); method public android.app.Notification clone(); method public int describeContents(); method public int describeContents(); method public android.app.PendingIntent getAppOverlayIntent(); method public int getBadgeIconType(); method public int getBadgeIconType(); method public java.lang.String getChannelId(); method public java.lang.String getChannelId(); method public java.lang.String getGroup(); method public java.lang.String getGroup(); Loading Loading @@ -5446,6 +5447,7 @@ package android.app { method public android.app.Notification.Style getStyle(); method public android.app.Notification.Style getStyle(); method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification); method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setActions(android.app.Notification.Action...); method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setAutoCancel(boolean); method public android.app.Notification.Builder setBadgeIconType(int); method public android.app.Notification.Builder setBadgeIconType(int); method public android.app.Notification.Builder setCategory(java.lang.String); method public android.app.Notification.Builder setCategory(java.lang.String); Loading Loading @@ -5663,6 +5665,7 @@ package android.app { public final class NotificationChannel implements android.os.Parcelable { public final class NotificationChannel implements android.os.Parcelable { ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int); method public boolean canBypassDnd(); method public boolean canBypassDnd(); method public boolean canOverlayApps(); method public boolean canShowBadge(); method public boolean canShowBadge(); method public int describeContents(); method public int describeContents(); method public void enableLights(boolean); method public void enableLights(boolean); Loading @@ -5678,6 +5681,7 @@ package android.app { method public android.net.Uri getSound(); method public android.net.Uri getSound(); method public long[] getVibrationPattern(); method public long[] getVibrationPattern(); method public boolean hasUserSetImportance(); method public boolean hasUserSetImportance(); method public void setAllowAppOverlay(boolean); method public void setBypassDnd(boolean); method public void setBypassDnd(boolean); method public void setDescription(java.lang.String); method public void setDescription(java.lang.String); method public void setGroup(java.lang.String); method public void setGroup(java.lang.String); Loading @@ -5697,6 +5701,7 @@ package android.app { public final class NotificationChannelGroup implements android.os.Parcelable { public final class NotificationChannelGroup implements android.os.Parcelable { ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence); method public boolean canOverlayApps(); method public android.app.NotificationChannelGroup clone(); method public android.app.NotificationChannelGroup clone(); method public int describeContents(); method public int describeContents(); method public java.util.List<android.app.NotificationChannel> getChannels(); method public java.util.List<android.app.NotificationChannel> getChannels(); Loading @@ -5704,6 +5709,7 @@ package android.app { method public java.lang.String getId(); method public java.lang.String getId(); method public java.lang.CharSequence getName(); method public java.lang.CharSequence getName(); method public boolean isBlocked(); method public boolean isBlocked(); method public void setAllowAppOverlay(boolean); method public void setDescription(java.lang.String); method public void setDescription(java.lang.String); method public void writeToParcel(android.os.Parcel, int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR; field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
api/test-current.txt +3 −0 Original line number Original line Diff line number Diff line Loading @@ -140,7 +140,10 @@ package android.app { } } public final class NotificationChannelGroup implements android.os.Parcelable { public final class NotificationChannelGroup implements android.os.Parcelable { method public int getUserLockedFields(); method public void lockFields(int); method public void setBlocked(boolean); method public void setBlocked(boolean); field public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 2; // 0x2 } } public class NotificationManager { public class NotificationManager { Loading
core/java/android/app/Notification.java +38 −0 Original line number Original line Diff line number Diff line Loading @@ -1275,6 +1275,8 @@ public class Notification implements Parcelable private String mShortcutId; private String mShortcutId; private CharSequence mSettingsText; private CharSequence mSettingsText; private PendingIntent mAppOverlayIntent; /** @hide */ /** @hide */ @IntDef(prefix = { "GROUP_ALERT_" }, value = { @IntDef(prefix = { "GROUP_ALERT_" }, value = { GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY Loading Loading @@ -2225,6 +2227,9 @@ public class Notification implements Parcelable } } mGroupAlertBehavior = parcel.readInt(); mGroupAlertBehavior = parcel.readInt(); if (parcel.readInt() != 0) { mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel); } } } @Override @Override Loading Loading @@ -2339,6 +2344,7 @@ public class Notification implements Parcelable that.mBadgeIcon = this.mBadgeIcon; that.mBadgeIcon = this.mBadgeIcon; that.mSettingsText = this.mSettingsText; that.mSettingsText = this.mSettingsText; that.mGroupAlertBehavior = this.mGroupAlertBehavior; that.mGroupAlertBehavior = this.mGroupAlertBehavior; that.mAppOverlayIntent = this.mAppOverlayIntent; if (!heavy) { if (!heavy) { that.lightenPayload(); // will clean out extras that.lightenPayload(); // will clean out extras Loading Loading @@ -2660,6 +2666,13 @@ public class Notification implements Parcelable parcel.writeInt(mGroupAlertBehavior); parcel.writeInt(mGroupAlertBehavior); if (mAppOverlayIntent != null) { parcel.writeInt(1); mAppOverlayIntent.writeToParcel(parcel, 0); } else { parcel.writeInt(0); } // mUsesStandardHeader is not written because it should be recomputed in listeners // mUsesStandardHeader is not written because it should be recomputed in listeners } } Loading Loading @@ -3072,6 +3085,14 @@ public class Notification implements Parcelable return mGroupAlertBehavior; return mGroupAlertBehavior; } } /** * Returns the intent that will be used to display app content in a floating window over the * existing foreground activity. */ public PendingIntent getAppOverlayIntent() { return mAppOverlayIntent; } /** /** * The small icon representing this notification in the status bar and content view. * The small icon representing this notification in the status bar and content view. * * Loading Loading @@ -3406,6 +3427,23 @@ public class Notification implements Parcelable return this; return this; } } /** * Sets the intent 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>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> */ public Builder setAppOverlayIntent(PendingIntent intent) { mN.mAppOverlayIntent = intent; return this; } /** @removed */ /** @removed */ @Deprecated @Deprecated public Builder setChannel(String channelId) { public Builder setChannel(String channelId) { Loading
core/java/android/app/NotificationChannel.java +79 −46 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ */ package android.app; package android.app; import static android.app.NotificationManager.IMPORTANCE_HIGH; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; Loading @@ -41,6 +43,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.IOException; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.Arrays; import java.util.Objects; /** /** * A representation of settings that apply to a collection of similarly themed notifications. * A representation of settings that apply to a collection of similarly themed notifications. Loading Loading @@ -81,6 +84,7 @@ public final class NotificationChannel implements Parcelable { private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; private static final String ATT_FG_SERVICE_SHOWN = "fgservice"; private static final String ATT_GROUP = "group"; private static final String ATT_GROUP = "group"; private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system"; private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay"; private static final String DELIMITER = ","; private static final String DELIMITER = ","; /** /** Loading Loading @@ -113,6 +117,11 @@ public final class NotificationChannel implements Parcelable { */ */ public static final int USER_LOCKED_SHOW_BADGE = 0x00000080; public static final int USER_LOCKED_SHOW_BADGE = 0x00000080; /** * @hide */ public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100; /** /** * @hide * @hide */ */ Loading @@ -124,6 +133,7 @@ public final class NotificationChannel implements Parcelable { USER_LOCKED_VIBRATION, USER_LOCKED_VIBRATION, USER_LOCKED_SOUND, USER_LOCKED_SOUND, USER_LOCKED_SHOW_BADGE, USER_LOCKED_SHOW_BADGE, USER_LOCKED_ALLOW_APP_OVERLAY }; }; private static final int DEFAULT_LIGHT_COLOR = 0; private static final int DEFAULT_LIGHT_COLOR = 0; Loading @@ -133,6 +143,7 @@ public final class NotificationChannel implements Parcelable { NotificationManager.IMPORTANCE_UNSPECIFIED; NotificationManager.IMPORTANCE_UNSPECIFIED; private static final boolean DEFAULT_DELETED = false; private static final boolean DEFAULT_DELETED = false; private static final boolean DEFAULT_SHOW_BADGE = true; private static final boolean DEFAULT_SHOW_BADGE = true; private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true; @UnsupportedAppUsage @UnsupportedAppUsage private final String mId; private final String mId; Loading @@ -156,6 +167,7 @@ public final class NotificationChannel implements Parcelable { private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; private AudioAttributes mAudioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT; // If this is a blockable system notification channel. // If this is a blockable system notification channel. private boolean mBlockableSystem = false; private boolean mBlockableSystem = false; private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY; /** /** * Creates a notification channel. * Creates a notification channel. Loading Loading @@ -217,6 +229,7 @@ public final class NotificationChannel implements Parcelable { mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null; mAudioAttributes = in.readInt() > 0 ? AudioAttributes.CREATOR.createFromParcel(in) : null; mLightColor = in.readInt(); mLightColor = in.readInt(); mBlockableSystem = in.readBoolean(); mBlockableSystem = in.readBoolean(); mAllowAppOverlay = in.readBoolean(); } } @Override @Override Loading Loading @@ -269,6 +282,7 @@ public final class NotificationChannel implements Parcelable { } } dest.writeInt(mLightColor); dest.writeInt(mLightColor); dest.writeBoolean(mBlockableSystem); dest.writeBoolean(mBlockableSystem); dest.writeBoolean(mAllowAppOverlay); } } /** /** Loading Loading @@ -460,6 +474,22 @@ public final class NotificationChannel implements Parcelable { this.mLockscreenVisibility = lockscreenVisibility; this.mLockscreenVisibility = lockscreenVisibility; } } /** * Sets whether notifications posted to this channel can appear outside of the notification * shade, floating over other apps' content. * * <p>This value will be ignored for channels that aren't allowed to pop on screen (that is, * channels whose {@link #getImportance() importance} is < * {@link NotificationManager#IMPORTANCE_HIGH}.</p> * * <p>Only modifiable before the channel is submitted to * * {@link NotificationManager#createNotificationChannel(NotificationChannel)}.</p> * @see Notification#getAppOverlayIntent() */ public void setAllowAppOverlay(boolean allowAppOverlay) { mAllowAppOverlay = allowAppOverlay; } /** /** * Returns the id of this channel. * Returns the id of this channel. */ */ Loading Loading @@ -572,6 +602,22 @@ public final class NotificationChannel implements Parcelable { return mGroup; return mGroup; } } /** * 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; } /** * Like {@link #canOverlayApps()}, but only checks the permission, not the importance. * @hide */ public boolean isAppOverlayAllowed() { return mAllowAppOverlay; } /** /** * @hide * @hide */ */ Loading Loading @@ -605,6 +651,7 @@ public final class NotificationChannel implements Parcelable { /** /** * Returns whether the user has chosen the importance of this channel, either to affirm the * Returns whether the user has chosen the importance of this channel, either to affirm the * initial selection from the app, or changed it to be higher or lower. * initial selection from the app, or changed it to be higher or lower. * @see #getImportance() */ */ public boolean hasUserSetImportance() { public boolean hasUserSetImportance() { return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0; Loading Loading @@ -652,6 +699,7 @@ public final class NotificationChannel implements Parcelable { lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); lockFields(safeInt(parser, ATT_USER_LOCKED, 0)); setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); setFgServiceShown(safeBool(parser, ATT_FG_SERVICE_SHOWN, false)); setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); setBlockableSystem(safeBool(parser, ATT_BLOCKABLE_SYSTEM, false)); setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY)); } } @Nullable @Nullable Loading Loading @@ -770,6 +818,9 @@ public final class NotificationChannel implements Parcelable { if (isBlockableSystem()) { if (isBlockableSystem()) { out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(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())); } out.endTag(null, TAG_CHANNEL); out.endTag(null, TAG_CHANNEL); } } Loading Loading @@ -812,6 +863,7 @@ public final class NotificationChannel implements Parcelable { record.put(ATT_DELETED, Boolean.toString(isDeleted())); record.put(ATT_DELETED, Boolean.toString(isDeleted())); record.put(ATT_GROUP, getGroup()); record.put(ATT_GROUP, getGroup()); record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem()); record.put(ATT_BLOCKABLE_SYSTEM, isBlockableSystem()); record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps()); return record; return record; } } Loading Loading @@ -899,58 +951,36 @@ public final class NotificationChannel implements Parcelable { public boolean equals(Object o) { public boolean equals(Object o) { if (this == o) return true; if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false; NotificationChannel that = (NotificationChannel) o; NotificationChannel that = (NotificationChannel) o; return getImportance() == that.getImportance() && if (getImportance() != that.getImportance()) return false; mBypassDnd == that.mBypassDnd && if (mBypassDnd != that.mBypassDnd) return false; getLockscreenVisibility() == that.getLockscreenVisibility() && if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false; mLights == that.mLights && if (mLights != that.mLights) return false; getLightColor() == that.getLightColor() && if (getLightColor() != that.getLightColor()) return false; getUserLockedFields() == that.getUserLockedFields() && if (getUserLockedFields() != that.getUserLockedFields()) return false; isFgServiceShown() == that.isFgServiceShown() && if (mVibrationEnabled != that.mVibrationEnabled) return false; mVibrationEnabled == that.mVibrationEnabled && if (mShowBadge != that.mShowBadge) return false; mShowBadge == that.mShowBadge && if (isDeleted() != that.isDeleted()) return false; isDeleted() == that.isDeleted() && if (isBlockableSystem() != that.isBlockableSystem()) return false; isBlockableSystem() == that.isBlockableSystem() && if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; mAllowAppOverlay == that.mAllowAppOverlay && if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { Objects.equals(getId(), that.getId()) && return false; Objects.equals(getName(), that.getName()) && } Objects.equals(mDesc, that.mDesc) && if (getDescription() != null ? !getDescription().equals(that.getDescription()) Objects.equals(getSound(), that.getSound()) && : that.getDescription() != null) { Arrays.equals(mVibration, that.mVibration) && return false; Objects.equals(getGroup(), that.getGroup()) && } Objects.equals(getAudioAttributes(), that.getAudioAttributes()); if (getSound() != null ? !getSound().equals(that.getSound()) : that.getSound() != null) { return false; } if (!Arrays.equals(mVibration, that.mVibration)) return false; if (getGroup() != null ? !getGroup().equals(that.getGroup()) : that.getGroup() != null) { return false; } return getAudioAttributes() != null ? getAudioAttributes().equals(that.getAudioAttributes()) : that.getAudioAttributes() == null; } } @Override @Override public int hashCode() { public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd, result = 31 * result + (getName() != null ? getName().hashCode() : 0); getLockscreenVisibility(), getSound(), mLights, getLightColor(), result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0); getUserLockedFields(), result = 31 * result + getImportance(); isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(), result = 31 * result + (mBypassDnd ? 1 : 0); getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay); result = 31 * result + getLockscreenVisibility(); result = 31 * result + (getSound() != null ? getSound().hashCode() : 0); result = 31 * result + (mLights ? 1 : 0); result = 31 * result + getLightColor(); result = 31 * result + Arrays.hashCode(mVibration); result = 31 * result + Arrays.hashCode(mVibration); result = 31 * result + getUserLockedFields(); result = 31 * result + (mVibrationEnabled ? 1 : 0); result = 31 * result + (mShowBadge ? 1 : 0); result = 31 * result + (isDeleted() ? 1 : 0); result = 31 * result + (getGroup() != null ? getGroup().hashCode() : 0); result = 31 * result + (getAudioAttributes() != null ? getAudioAttributes().hashCode() : 0); result = 31 * result + (isBlockableSystem() ? 1 : 0); return result; return result; } } Loading @@ -976,6 +1006,7 @@ public final class NotificationChannel implements Parcelable { + ", mGroup='" + mGroup + '\'' + ", mGroup='" + mGroup + '\'' + ", mAudioAttributes=" + mAudioAttributes + ", mAudioAttributes=" + mAudioAttributes + ", mBlockableSystem=" + mBlockableSystem + ", mBlockableSystem=" + mBlockableSystem + ", mAllowAppOverlay=" + mAllowAppOverlay + '}'; + '}'; pw.println(prefix + output); pw.println(prefix + output); } } Loading @@ -1001,6 +1032,7 @@ public final class NotificationChannel implements Parcelable { + ", mGroup='" + mGroup + '\'' + ", mGroup='" + mGroup + '\'' + ", mAudioAttributes=" + mAudioAttributes + ", mAudioAttributes=" + mAudioAttributes + ", mBlockableSystem=" + mBlockableSystem + ", mBlockableSystem=" + mBlockableSystem + ", mAllowAppOverlay=" + mAllowAppOverlay + '}'; + '}'; } } Loading Loading @@ -1034,6 +1066,7 @@ public final class NotificationChannel implements Parcelable { mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES); mAudioAttributes.writeToProto(proto, NotificationChannelProto.AUDIO_ATTRIBUTES); } } proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem); proto.write(NotificationChannelProto.IS_BLOCKABLE_SYSTEM, mBlockableSystem); proto.write(NotificationChannelProto.ALLOW_APP_OVERLAY, mAllowAppOverlay); proto.end(token); proto.end(token); } } Loading
core/java/android/app/NotificationChannelGroup.java +93 −20 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.IOException; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; import java.util.Objects; /** /** * A grouping of related notification channels. e.g., channels that all belong to a single account. * A grouping of related notification channels. e.g., channels that all belong to a single account. Loading @@ -49,13 +50,33 @@ public final class NotificationChannelGroup implements Parcelable { private static final String ATT_DESC = "desc"; private static final String ATT_DESC = "desc"; private static final String ATT_ID = "id"; private static final String ATT_ID = "id"; private static final String ATT_BLOCKED = "blocked"; private static final String ATT_BLOCKED = "blocked"; private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay"; private static final String ATT_USER_LOCKED = "locked"; private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true; /** * @hide */ public static final int USER_LOCKED_BLOCKED_STATE = 0x00000001; /** * @hide */ @TestApi public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000002; /** * @see #getId() */ @UnsupportedAppUsage @UnsupportedAppUsage private final String mId; private final String mId; private CharSequence mName; private CharSequence mName; private String mDescription; private String mDescription; private boolean mBlocked; private boolean mBlocked; private List<NotificationChannel> mChannels = new ArrayList<>(); private List<NotificationChannel> mChannels = new ArrayList<>(); private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY; // Bitwise representation of fields that have been changed by the user private int mUserLockedFields; /** /** * Creates a notification channel group. * Creates a notification channel group. Loading Loading @@ -89,6 +110,8 @@ public final class NotificationChannelGroup implements Parcelable { } } in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader()); in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader()); mBlocked = in.readBoolean(); mBlocked = in.readBoolean(); mAllowAppOverlay = in.readBoolean(); mUserLockedFields = in.readInt(); } } private String getTrimmedString(String input) { private String getTrimmedString(String input) { Loading @@ -115,6 +138,8 @@ public final class NotificationChannelGroup implements Parcelable { } } dest.writeParcelableList(mChannels, flags); dest.writeParcelableList(mChannels, flags); dest.writeBoolean(mBlocked); dest.writeBoolean(mBlocked); dest.writeBoolean(mAllowAppOverlay); dest.writeInt(mUserLockedFields); } } /** /** Loading Loading @@ -155,6 +180,15 @@ public final class NotificationChannelGroup implements Parcelable { return mBlocked; return mBlocked; } } /** * Returns whether notifications posted to this channel group can display outside of the * notification shade, in a floating window on top of other apps. These may additionally be * blocked at the notification channel level, see {@link NotificationChannel#canOverlayApps()}. */ public boolean canOverlayApps() { return mAllowAppOverlay; } /** /** * Sets the user visible description of this group. * Sets the user visible description of this group. * * Loading @@ -165,6 +199,21 @@ public final class NotificationChannelGroup implements Parcelable { mDescription = getTrimmedString(description); mDescription = getTrimmedString(description); } } /** * Sets whether notifications posted to this channel group can appear outside of the * 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()}. * * <p>Only modifiable before the channel is submitted to * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.</p> * @see Notification#getAppOverlayIntent() */ public void setAllowAppOverlay(boolean allowAppOverlay) { mAllowAppOverlay = allowAppOverlay; } /** /** * @hide * @hide */ */ Loading @@ -187,6 +236,29 @@ public final class NotificationChannelGroup implements Parcelable { mChannels = channels; mChannels = channels; } } /** * @hide */ @TestApi public void lockFields(int field) { mUserLockedFields |= field; } /** * @hide */ public void unlockFields(int field) { mUserLockedFields &= ~field; } /** * @hide */ @TestApi public int getUserLockedFields() { return mUserLockedFields; } /** /** * @hide * @hide */ */ Loading @@ -194,6 +266,7 @@ public final class NotificationChannelGroup implements Parcelable { // Name, id, and importance are set in the constructor. // Name, id, and importance are set in the constructor. setDescription(parser.getAttributeValue(null, ATT_DESC)); setDescription(parser.getAttributeValue(null, ATT_DESC)); setBlocked(safeBool(parser, ATT_BLOCKED, false)); setBlocked(safeBool(parser, ATT_BLOCKED, false)); setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY)); } } private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) { private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) { Loading @@ -216,6 +289,10 @@ public final class NotificationChannelGroup implements Parcelable { out.attribute(null, ATT_DESC, getDescription().toString()); out.attribute(null, ATT_DESC, getDescription().toString()); } } out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked())); out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked())); if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) { out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps())); } out.attribute(null, ATT_USER_LOCKED, Integer.toString(mUserLockedFields)); out.endTag(null, TAG_GROUP); out.endTag(null, TAG_GROUP); } } Loading @@ -230,6 +307,8 @@ public final class NotificationChannelGroup implements Parcelable { record.put(ATT_NAME, getName()); record.put(ATT_NAME, getName()); record.put(ATT_DESC, getDescription()); record.put(ATT_DESC, getDescription()); record.put(ATT_BLOCKED, isBlocked()); record.put(ATT_BLOCKED, isBlocked()); record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps()); record.put(ATT_USER_LOCKED, mUserLockedFields); return record; return record; } } Loading @@ -255,30 +334,20 @@ public final class NotificationChannelGroup implements Parcelable { public boolean equals(Object o) { public boolean equals(Object o) { if (this == o) return true; if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false; NotificationChannelGroup that = (NotificationChannelGroup) o; NotificationChannelGroup that = (NotificationChannelGroup) o; return isBlocked() == that.isBlocked() && if (isBlocked() != that.isBlocked()) return false; mAllowAppOverlay == that.mAllowAppOverlay && if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false; mUserLockedFields == that.mUserLockedFields && if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) { Objects.equals(getId(), that.getId()) && return false; Objects.equals(getName(), that.getName()) && } Objects.equals(getDescription(), that.getDescription()) && if (getDescription() != null ? !getDescription().equals(that.getDescription()) Objects.equals(getChannels(), that.getChannels()); : that.getDescription() != null) { return false; } return getChannels() != null ? getChannels().equals(that.getChannels()) : that.getChannels() == null; } } @Override @Override public int hashCode() { public int hashCode() { int result = getId() != null ? getId().hashCode() : 0; return Objects.hash(getId(), getName(), getDescription(), isBlocked(), getChannels(), result = 31 * result + (getName() != null ? getName().hashCode() : 0); mAllowAppOverlay, mUserLockedFields); result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0); result = 31 * result + (isBlocked() ? 1 : 0); result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0); return result; } } @Override @Override Loading @@ -287,6 +356,8 @@ public final class NotificationChannelGroup implements Parcelable { cloned.setDescription(getDescription()); cloned.setDescription(getDescription()); cloned.setBlocked(isBlocked()); cloned.setBlocked(isBlocked()); cloned.setChannels(getChannels()); cloned.setChannels(getChannels()); cloned.setAllowAppOverlay(canOverlayApps()); cloned.lockFields(mUserLockedFields); return cloned; return cloned; } } Loading @@ -298,6 +369,8 @@ public final class NotificationChannelGroup implements Parcelable { + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "") + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "") + ", mBlocked=" + mBlocked + ", mBlocked=" + mBlocked + ", mChannels=" + mChannels + ", mChannels=" + mChannels + ", mAllowAppOverlay=" + mAllowAppOverlay + ", mUserLockedFields=" + mUserLockedFields + '}'; + '}'; } } Loading @@ -312,7 +385,7 @@ public final class NotificationChannelGroup implements Parcelable { for (NotificationChannel channel : mChannels) { for (NotificationChannel channel : mChannels) { channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS); channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS); } } proto.write(NotificationChannelGroupProto.ALLOW_APP_OVERLAY, mAllowAppOverlay); proto.end(token); proto.end(token); } } } }