Add APIs for notification app overlays
- Can be enabled/disabled at channel and channel group levels - An activity to launch can be added to notification Test: atest, cts Bug: 111236845 Change-Id: I9a4832211676cca4649d1f28e6e3e3157954d268
This commit is contained in:
@@ -5217,6 +5217,7 @@ package android.app {
|
||||
ctor public Notification(android.os.Parcel);
|
||||
method public android.app.Notification clone();
|
||||
method public int describeContents();
|
||||
method public android.app.PendingIntent getAppOverlayIntent();
|
||||
method public int getBadgeIconType();
|
||||
method public java.lang.String getChannelId();
|
||||
method public java.lang.String getGroup();
|
||||
@@ -5446,6 +5447,7 @@ package android.app {
|
||||
method public android.app.Notification.Style getStyle();
|
||||
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 setAppOverlayIntent(android.app.PendingIntent);
|
||||
method public android.app.Notification.Builder setAutoCancel(boolean);
|
||||
method public android.app.Notification.Builder setBadgeIconType(int);
|
||||
method public android.app.Notification.Builder setCategory(java.lang.String);
|
||||
@@ -5663,6 +5665,7 @@ package android.app {
|
||||
public final class NotificationChannel implements android.os.Parcelable {
|
||||
ctor public NotificationChannel(java.lang.String, java.lang.CharSequence, int);
|
||||
method public boolean canBypassDnd();
|
||||
method public boolean canOverlayApps();
|
||||
method public boolean canShowBadge();
|
||||
method public int describeContents();
|
||||
method public void enableLights(boolean);
|
||||
@@ -5678,6 +5681,7 @@ package android.app {
|
||||
method public android.net.Uri getSound();
|
||||
method public long[] getVibrationPattern();
|
||||
method public boolean hasUserSetImportance();
|
||||
method public void setAllowAppOverlay(boolean);
|
||||
method public void setBypassDnd(boolean);
|
||||
method public void setDescription(java.lang.String);
|
||||
method public void setGroup(java.lang.String);
|
||||
@@ -5697,6 +5701,7 @@ package android.app {
|
||||
|
||||
public final class NotificationChannelGroup implements android.os.Parcelable {
|
||||
ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
|
||||
method public boolean canOverlayApps();
|
||||
method public android.app.NotificationChannelGroup clone();
|
||||
method public int describeContents();
|
||||
method public java.util.List<android.app.NotificationChannel> getChannels();
|
||||
@@ -5704,6 +5709,7 @@ package android.app {
|
||||
method public java.lang.String getId();
|
||||
method public java.lang.CharSequence getName();
|
||||
method public boolean isBlocked();
|
||||
method public void setAllowAppOverlay(boolean);
|
||||
method public void setDescription(java.lang.String);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
|
||||
|
||||
@@ -987,8 +987,8 @@ package android.content {
|
||||
field public static final java.lang.String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
|
||||
field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
|
||||
field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
|
||||
field public static final java.lang.String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
|
||||
field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
|
||||
field public static final java.lang.String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
|
||||
field public static final java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
|
||||
field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
|
||||
field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
|
||||
|
||||
@@ -140,7 +140,10 @@ package android.app {
|
||||
}
|
||||
|
||||
public final class NotificationChannelGroup implements android.os.Parcelable {
|
||||
method public int getUserLockedFields();
|
||||
method public void lockFields(int);
|
||||
method public void setBlocked(boolean);
|
||||
field public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 2; // 0x2
|
||||
}
|
||||
|
||||
public class NotificationManager {
|
||||
|
||||
@@ -1275,6 +1275,8 @@ public class Notification implements Parcelable
|
||||
private String mShortcutId;
|
||||
private CharSequence mSettingsText;
|
||||
|
||||
private PendingIntent mAppOverlayIntent;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = { "GROUP_ALERT_" }, value = {
|
||||
GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY
|
||||
@@ -2225,6 +2227,9 @@ public class Notification implements Parcelable
|
||||
}
|
||||
|
||||
mGroupAlertBehavior = parcel.readInt();
|
||||
if (parcel.readInt() != 0) {
|
||||
mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2339,6 +2344,7 @@ public class Notification implements Parcelable
|
||||
that.mBadgeIcon = this.mBadgeIcon;
|
||||
that.mSettingsText = this.mSettingsText;
|
||||
that.mGroupAlertBehavior = this.mGroupAlertBehavior;
|
||||
that.mAppOverlayIntent = this.mAppOverlayIntent;
|
||||
|
||||
if (!heavy) {
|
||||
that.lightenPayload(); // will clean out extras
|
||||
@@ -2660,6 +2666,13 @@ public class Notification implements Parcelable
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -3072,6 +3085,14 @@ public class Notification implements Parcelable
|
||||
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.
|
||||
*
|
||||
@@ -3406,6 +3427,23 @@ public class Notification implements Parcelable
|
||||
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 */
|
||||
@Deprecated
|
||||
public Builder setChannel(String channelId) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package android.app;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
@@ -41,6 +43,7 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A representation of settings that apply to a collection of similarly themed notifications.
|
||||
@@ -81,6 +84,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 DELIMITER = ",";
|
||||
|
||||
/**
|
||||
@@ -113,6 +117,11 @@ public final class NotificationChannel implements Parcelable {
|
||||
*/
|
||||
public static final int USER_LOCKED_SHOW_BADGE = 0x00000080;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000100;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -124,6 +133,7 @@ public final class NotificationChannel implements Parcelable {
|
||||
USER_LOCKED_VIBRATION,
|
||||
USER_LOCKED_SOUND,
|
||||
USER_LOCKED_SHOW_BADGE,
|
||||
USER_LOCKED_ALLOW_APP_OVERLAY
|
||||
};
|
||||
|
||||
private static final int DEFAULT_LIGHT_COLOR = 0;
|
||||
@@ -133,6 +143,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;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
private final String mId;
|
||||
@@ -156,6 +167,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;
|
||||
|
||||
/**
|
||||
* Creates a notification channel.
|
||||
@@ -217,6 +229,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();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -269,6 +282,7 @@ public final class NotificationChannel implements Parcelable {
|
||||
}
|
||||
dest.writeInt(mLightColor);
|
||||
dest.writeBoolean(mBlockableSystem);
|
||||
dest.writeBoolean(mAllowAppOverlay);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,6 +474,22 @@ public final class NotificationChannel implements Parcelable {
|
||||
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.
|
||||
*/
|
||||
@@ -572,6 +602,22 @@ public final class NotificationChannel implements Parcelable {
|
||||
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
|
||||
*/
|
||||
@@ -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
|
||||
* initial selection from the app, or changed it to be higher or lower.
|
||||
* @see #getImportance()
|
||||
*/
|
||||
public boolean hasUserSetImportance() {
|
||||
return (mUserLockedFields & USER_LOCKED_IMPORTANCE) != 0;
|
||||
@@ -652,6 +699,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));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -770,6 +818,9 @@ 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()));
|
||||
}
|
||||
|
||||
out.endTag(null, TAG_CHANNEL);
|
||||
}
|
||||
@@ -812,6 +863,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());
|
||||
return record;
|
||||
}
|
||||
|
||||
@@ -899,58 +951,36 @@ public final class NotificationChannel implements Parcelable {
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NotificationChannel that = (NotificationChannel) o;
|
||||
|
||||
if (getImportance() != that.getImportance()) return false;
|
||||
if (mBypassDnd != that.mBypassDnd) return false;
|
||||
if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
|
||||
if (mLights != that.mLights) return false;
|
||||
if (getLightColor() != that.getLightColor()) return false;
|
||||
if (getUserLockedFields() != that.getUserLockedFields()) return false;
|
||||
if (mVibrationEnabled != that.mVibrationEnabled) return false;
|
||||
if (mShowBadge != that.mShowBadge) return false;
|
||||
if (isDeleted() != that.isDeleted()) return false;
|
||||
if (isBlockableSystem() != that.isBlockableSystem()) return false;
|
||||
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
|
||||
if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
|
||||
return false;
|
||||
}
|
||||
if (getDescription() != null ? !getDescription().equals(that.getDescription())
|
||||
: that.getDescription() != null) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
|
||||
return getImportance() == that.getImportance() &&
|
||||
mBypassDnd == that.mBypassDnd &&
|
||||
getLockscreenVisibility() == that.getLockscreenVisibility() &&
|
||||
mLights == that.mLights &&
|
||||
getLightColor() == that.getLightColor() &&
|
||||
getUserLockedFields() == that.getUserLockedFields() &&
|
||||
isFgServiceShown() == that.isFgServiceShown() &&
|
||||
mVibrationEnabled == that.mVibrationEnabled &&
|
||||
mShowBadge == that.mShowBadge &&
|
||||
isDeleted() == that.isDeleted() &&
|
||||
isBlockableSystem() == that.isBlockableSystem() &&
|
||||
mAllowAppOverlay == that.mAllowAppOverlay &&
|
||||
Objects.equals(getId(), that.getId()) &&
|
||||
Objects.equals(getName(), that.getName()) &&
|
||||
Objects.equals(mDesc, that.mDesc) &&
|
||||
Objects.equals(getSound(), that.getSound()) &&
|
||||
Arrays.equals(mVibration, that.mVibration) &&
|
||||
Objects.equals(getGroup(), that.getGroup()) &&
|
||||
Objects.equals(getAudioAttributes(), that.getAudioAttributes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = getId() != null ? getId().hashCode() : 0;
|
||||
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
|
||||
result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
|
||||
result = 31 * result + getImportance();
|
||||
result = 31 * result + (mBypassDnd ? 1 : 0);
|
||||
result = 31 * result + getLockscreenVisibility();
|
||||
result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
|
||||
result = 31 * result + (mLights ? 1 : 0);
|
||||
result = 31 * result + getLightColor();
|
||||
int result = Objects.hash(getId(), getName(), mDesc, getImportance(), mBypassDnd,
|
||||
getLockscreenVisibility(), getSound(), mLights, getLightColor(),
|
||||
getUserLockedFields(),
|
||||
isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
|
||||
getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -976,6 +1006,7 @@ public final class NotificationChannel implements Parcelable {
|
||||
+ ", mGroup='" + mGroup + '\''
|
||||
+ ", mAudioAttributes=" + mAudioAttributes
|
||||
+ ", mBlockableSystem=" + mBlockableSystem
|
||||
+ ", mAllowAppOverlay=" + mAllowAppOverlay
|
||||
+ '}';
|
||||
pw.println(prefix + output);
|
||||
}
|
||||
@@ -1001,6 +1032,7 @@ public final class NotificationChannel implements Parcelable {
|
||||
+ ", mGroup='" + mGroup + '\''
|
||||
+ ", mAudioAttributes=" + mAudioAttributes
|
||||
+ ", mBlockableSystem=" + mBlockableSystem
|
||||
+ ", mAllowAppOverlay=" + mAllowAppOverlay
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -1034,6 +1066,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.end(token);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A grouping of related notification channels. e.g., channels that all belong to a single account.
|
||||
@@ -49,13 +50,33 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
private static final String ATT_DESC = "desc";
|
||||
private static final String ATT_ID = "id";
|
||||
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
|
||||
private final String mId;
|
||||
private CharSequence mName;
|
||||
private String mDescription;
|
||||
private boolean mBlocked;
|
||||
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.
|
||||
@@ -89,6 +110,8 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
}
|
||||
in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
|
||||
mBlocked = in.readBoolean();
|
||||
mAllowAppOverlay = in.readBoolean();
|
||||
mUserLockedFields = in.readInt();
|
||||
}
|
||||
|
||||
private String getTrimmedString(String input) {
|
||||
@@ -115,6 +138,8 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
}
|
||||
dest.writeParcelableList(mChannels, flags);
|
||||
dest.writeBoolean(mBlocked);
|
||||
dest.writeBoolean(mAllowAppOverlay);
|
||||
dest.writeInt(mUserLockedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +180,15 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
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.
|
||||
*
|
||||
@@ -165,6 +199,21 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
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
|
||||
*/
|
||||
@@ -187,6 +236,29 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
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
|
||||
*/
|
||||
@@ -194,6 +266,7 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
// Name, id, and importance are set in the constructor.
|
||||
setDescription(parser.getAttributeValue(null, ATT_DESC));
|
||||
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) {
|
||||
@@ -216,6 +289,10 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
out.attribute(null, ATT_DESC, getDescription().toString());
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -230,6 +307,8 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
record.put(ATT_NAME, getName());
|
||||
record.put(ATT_DESC, getDescription());
|
||||
record.put(ATT_BLOCKED, isBlocked());
|
||||
record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
|
||||
record.put(ATT_USER_LOCKED, mUserLockedFields);
|
||||
return record;
|
||||
}
|
||||
|
||||
@@ -255,30 +334,20 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NotificationChannelGroup that = (NotificationChannelGroup) o;
|
||||
|
||||
if (isBlocked() != that.isBlocked()) return false;
|
||||
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
|
||||
if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
|
||||
return false;
|
||||
}
|
||||
if (getDescription() != null ? !getDescription().equals(that.getDescription())
|
||||
: that.getDescription() != null) {
|
||||
return false;
|
||||
}
|
||||
return getChannels() != null ? getChannels().equals(that.getChannels())
|
||||
: that.getChannels() == null;
|
||||
return isBlocked() == that.isBlocked() &&
|
||||
mAllowAppOverlay == that.mAllowAppOverlay &&
|
||||
mUserLockedFields == that.mUserLockedFields &&
|
||||
Objects.equals(getId(), that.getId()) &&
|
||||
Objects.equals(getName(), that.getName()) &&
|
||||
Objects.equals(getDescription(), that.getDescription()) &&
|
||||
Objects.equals(getChannels(), that.getChannels());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = getId() != null ? getId().hashCode() : 0;
|
||||
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
|
||||
result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
|
||||
result = 31 * result + (isBlocked() ? 1 : 0);
|
||||
result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0);
|
||||
return result;
|
||||
return Objects.hash(getId(), getName(), getDescription(), isBlocked(), getChannels(),
|
||||
mAllowAppOverlay, mUserLockedFields);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -287,6 +356,8 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
cloned.setDescription(getDescription());
|
||||
cloned.setBlocked(isBlocked());
|
||||
cloned.setChannels(getChannels());
|
||||
cloned.setAllowAppOverlay(canOverlayApps());
|
||||
cloned.lockFields(mUserLockedFields);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
@@ -298,6 +369,8 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
+ ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "")
|
||||
+ ", mBlocked=" + mBlocked
|
||||
+ ", mChannels=" + mChannels
|
||||
+ ", mAllowAppOverlay=" + mAllowAppOverlay
|
||||
+ ", mUserLockedFields=" + mUserLockedFields
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -312,7 +385,7 @@ public final class NotificationChannelGroup implements Parcelable {
|
||||
for (NotificationChannel channel : mChannels) {
|
||||
channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS);
|
||||
}
|
||||
|
||||
proto.write(NotificationChannelGroupProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +57,7 @@ message NotificationChannelProto {
|
||||
// If this is a blockable system notification channel.
|
||||
optional bool is_blockable_system = 17;
|
||||
optional bool fg_service_shown = 18;
|
||||
// Default is true.
|
||||
// Allows the notifications to appear outside of the shade in floating windows
|
||||
optional bool allow_app_overlay = 19;
|
||||
}
|
||||
|
||||
@@ -36,4 +36,7 @@ message NotificationChannelGroupProto {
|
||||
optional string description = 3;
|
||||
optional bool is_blocked = 4;
|
||||
repeated NotificationChannelProto channels = 5;
|
||||
// Default is true.
|
||||
// Allows the notifications to appear outside of the shade in floating windows
|
||||
optional bool allow_app_overlay = 6;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ public final class ChannelImpressions implements Parcelable {
|
||||
static final String ATT_DISMISSALS = "dismisses";
|
||||
static final String ATT_VIEWS = "views";
|
||||
static final String ATT_STREAK = "streak";
|
||||
static final String ATT_SENT = "sent";
|
||||
static final String ATT_INTERRUPTIVE = "interruptive";
|
||||
|
||||
private int mDismissals = 0;
|
||||
private int mViews = 0;
|
||||
|
||||
@@ -515,8 +515,20 @@ public class PreferencesHelper implements RankingConfig {
|
||||
if (oldGroup != null) {
|
||||
group.setChannels(oldGroup.getChannels());
|
||||
|
||||
// apps can't update the blocked status or app overlay permission
|
||||
if (fromTargetApp) {
|
||||
group.setBlocked(oldGroup.isBlocked());
|
||||
group.setAllowAppOverlay(oldGroup.canOverlayApps());
|
||||
group.unlockFields(group.getUserLockedFields());
|
||||
group.lockFields(oldGroup.getUserLockedFields());
|
||||
} else {
|
||||
// but the system can
|
||||
if (group.isBlocked() != oldGroup.isBlocked()) {
|
||||
group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
|
||||
}
|
||||
if (group.canOverlayApps() != oldGroup.canOverlayApps()) {
|
||||
group.lockFields(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
r.groups.put(group.getId(), group);
|
||||
@@ -1071,6 +1083,9 @@ public class PreferencesHelper implements RankingConfig {
|
||||
if (original.canShowBadge() != update.canShowBadge()) {
|
||||
update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
|
||||
}
|
||||
if (original.isAppOverlayAllowed() != update.isAppOverlayAllowed()) {
|
||||
update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String prefix,
|
||||
|
||||
@@ -280,7 +280,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
|
||||
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
|
||||
assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
|
||||
assertEquals(channel1, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
|
||||
assertEquals(channel1,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
|
||||
compareChannels(channel2,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
|
||||
|
||||
@@ -348,7 +349,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
|
||||
assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_O, UID_O));
|
||||
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
|
||||
assertEquals(channel1, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
|
||||
assertEquals(channel1,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
|
||||
compareChannels(channel2,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
|
||||
compareChannels(channel3,
|
||||
@@ -487,7 +489,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
NotificationChannel channel1 =
|
||||
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
|
||||
NotificationChannel channel2 =
|
||||
new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
|
||||
new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
|
||||
NotificationChannel channel3 =
|
||||
new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
|
||||
channel3.setGroup(ncg.getId());
|
||||
@@ -500,7 +502,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
|
||||
mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId());
|
||||
mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId());
|
||||
assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
|
||||
assertEquals(channel2,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
|
||||
|
||||
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel1.getId(),
|
||||
channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
|
||||
@@ -516,8 +519,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
|
||||
assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
|
||||
assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG_N_MR1, UID_N_MR1));
|
||||
//assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG_N_MR1, UID_N_MR1));
|
||||
assertEquals(channel2, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
|
||||
assertEquals(channel2,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -799,14 +802,15 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
|
||||
public void testCreateChannel_CannotChangeHiddenFields() {
|
||||
final NotificationChannel channel =
|
||||
new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
|
||||
new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
|
||||
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
|
||||
channel.enableLights(true);
|
||||
channel.setBypassDnd(true);
|
||||
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||
channel.setShowBadge(true);
|
||||
channel.setAllowAppOverlay(false);
|
||||
int lockMask = 0;
|
||||
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
|
||||
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
|
||||
@@ -823,19 +827,21 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
assertFalse(savedChannel.canBypassDnd());
|
||||
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
|
||||
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
|
||||
assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
|
||||
|
||||
verify(mHandler, never()).requestSort();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
|
||||
public void testCreateChannel_CannotChangeHiddenFieldsAssistant() {
|
||||
final NotificationChannel channel =
|
||||
new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
|
||||
new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
|
||||
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
|
||||
channel.enableLights(true);
|
||||
channel.setBypassDnd(true);
|
||||
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||
channel.setShowBadge(true);
|
||||
channel.setAllowAppOverlay(false);
|
||||
int lockMask = 0;
|
||||
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
|
||||
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
|
||||
@@ -852,10 +858,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
assertFalse(savedChannel.canBypassDnd());
|
||||
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
|
||||
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
|
||||
assertEquals(channel.canOverlayApps(), savedChannel.canOverlayApps());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearLockedFields() throws Exception {
|
||||
public void testClearLockedFields() {
|
||||
final NotificationChannel channel = getChannel();
|
||||
mHelper.clearLockedFields(channel);
|
||||
assertEquals(0, channel.getUserLockedFields());
|
||||
@@ -867,7 +874,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFields_soundAndVibration() throws Exception {
|
||||
public void testLockFields_soundAndVibration() {
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
|
||||
|
||||
final NotificationChannel update1 = getChannel();
|
||||
@@ -891,7 +898,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFields_vibrationAndLights() throws Exception {
|
||||
public void testLockFields_vibrationAndLights() {
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
|
||||
|
||||
final NotificationChannel update1 = getChannel();
|
||||
@@ -911,7 +918,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFields_lightsAndImportance() throws Exception {
|
||||
public void testLockFields_lightsAndImportance() {
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
|
||||
|
||||
final NotificationChannel update1 = getChannel();
|
||||
@@ -931,7 +938,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFields_visibilityAndDndAndBadge() throws Exception {
|
||||
public void testLockFields_visibilityAndDndAndBadge() {
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
|
||||
assertEquals(0,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
|
||||
@@ -962,6 +969,21 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
.getUserLockedFields());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFields_appOverlay() {
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false);
|
||||
assertEquals(0,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false)
|
||||
.getUserLockedFields());
|
||||
|
||||
final NotificationChannel update = getChannel();
|
||||
update.setAllowAppOverlay(false);
|
||||
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true);
|
||||
assertEquals(NotificationChannel.USER_LOCKED_ALLOW_APP_OVERLAY,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
|
||||
.getUserLockedFields());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteNonExistentChannel() throws Exception {
|
||||
mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist");
|
||||
@@ -1255,21 +1277,24 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true);
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true);
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false);
|
||||
mHelper.createNotificationChannel(
|
||||
PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false);
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false);
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false);
|
||||
|
||||
mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId());
|
||||
|
||||
assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1));
|
||||
assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
|
||||
assertNotNull(
|
||||
mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1));
|
||||
|
||||
assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
|
||||
compareChannels(groupedAndDeleted,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
|
||||
assertNull(mHelper.getNotificationChannel(
|
||||
PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false));
|
||||
compareChannels(groupedAndDeleted, mHelper.getNotificationChannel(
|
||||
PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true));
|
||||
|
||||
compareChannels(groupedButNotDeleted,
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
|
||||
compareChannels(groupedButNotDeleted, mHelper.getNotificationChannel(
|
||||
PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false));
|
||||
compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
|
||||
PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel.getId(), false));
|
||||
|
||||
@@ -1381,15 +1406,49 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateGroup() throws Exception {
|
||||
public void testCreateGroup() {
|
||||
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
|
||||
assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
|
||||
assertEquals(ncg,
|
||||
mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next());
|
||||
verify(mHandler, never()).requestSort();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCannotCreateChannel_badGroup() throws Exception {
|
||||
public void testUpdateGroup_fromSystem_appOverlay() {
|
||||
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
|
||||
|
||||
// from system, allowed
|
||||
NotificationChannelGroup update = ncg.clone();
|
||||
update.setAllowAppOverlay(false);
|
||||
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, update, false);
|
||||
NotificationChannelGroup updated =
|
||||
mHelper.getNotificationChannelGroup("group1", PKG_N_MR1, UID_N_MR1);
|
||||
assertFalse(updated.canOverlayApps());
|
||||
assertEquals(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY,
|
||||
updated.getUserLockedFields());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateGroup_fromApp_appOverlay() {
|
||||
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
|
||||
|
||||
// from app, not allowed
|
||||
NotificationChannelGroup update = new NotificationChannelGroup("group1", "name1");
|
||||
update.setAllowAppOverlay(false);
|
||||
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
|
||||
NotificationChannelGroup updated =
|
||||
mHelper.getNotificationChannelGroup("group1", PKG_N_MR1, UID_N_MR1);
|
||||
assertTrue(updated.canOverlayApps());
|
||||
assertEquals(0, updated.getUserLockedFields());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCannotCreateChannel_badGroup() {
|
||||
NotificationChannel channel1 =
|
||||
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
|
||||
channel1.setGroup("garbage");
|
||||
@@ -1401,7 +1460,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCannotCreateChannel_goodGroup() throws Exception {
|
||||
public void testCannotCreateChannel_goodGroup() {
|
||||
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
|
||||
NotificationChannel channel1 =
|
||||
@@ -1409,12 +1468,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
channel1.setGroup(ncg.getId());
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false);
|
||||
|
||||
assertEquals(ncg.getId(),
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
|
||||
assertEquals(ncg.getId(), mHelper.getNotificationChannel(
|
||||
PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetChannelGroups() throws Exception {
|
||||
public void testGetChannelGroups() {
|
||||
NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true);
|
||||
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
|
||||
@@ -1465,7 +1524,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetChannelGroups_noSideEffects() throws Exception {
|
||||
public void testGetChannelGroups_noSideEffects() {
|
||||
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
|
||||
|
||||
@@ -1516,10 +1575,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChannel_updateName() throws Exception {
|
||||
public void testCreateChannel_updateName() {
|
||||
NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
|
||||
NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
|
||||
NotificationChannel actual =
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
|
||||
assertEquals("hello", actual.getName());
|
||||
|
||||
nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
|
||||
@@ -1533,12 +1593,13 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateChannel_addToGroup() throws Exception {
|
||||
public void testCreateChannel_addToGroup() {
|
||||
NotificationChannelGroup group = new NotificationChannelGroup("group", "");
|
||||
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true);
|
||||
NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
|
||||
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false);
|
||||
NotificationChannel actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
|
||||
NotificationChannel actual =
|
||||
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false);
|
||||
assertNull(actual.getGroup());
|
||||
|
||||
nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
|
||||
|
||||
Reference in New Issue
Block a user