Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26f79f9c authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Add APIs for notification app overlays"

parents 68585439 b6bd93d9
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -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();
@@ -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);
@@ -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);
@@ -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);
@@ -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();
@@ -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;
+3 −0
Original line number Original line Diff line number Diff line
@@ -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 {
+38 −0
Original line number Original line Diff line number Diff line
@@ -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
@@ -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
@@ -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
@@ -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
    }
    }


@@ -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.
     *
     *
@@ -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) {
+79 −46
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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.
@@ -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 = ",";


    /**
    /**
@@ -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
     */
     */
@@ -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;
@@ -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;
@@ -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.
@@ -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
@@ -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);
    }
    }


    /**
    /**
@@ -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.
     */
     */
@@ -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
     */
     */
@@ -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;
@@ -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
@@ -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);
    }
    }
@@ -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;
    }
    }


@@ -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;
    }
    }


@@ -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);
    }
    }
@@ -1001,6 +1032,7 @@ public final class NotificationChannel implements Parcelable {
                + ", mGroup='" + mGroup + '\''
                + ", mGroup='" + mGroup + '\''
                + ", mAudioAttributes=" + mAudioAttributes
                + ", mAudioAttributes=" + mAudioAttributes
                + ", mBlockableSystem=" + mBlockableSystem
                + ", mBlockableSystem=" + mBlockableSystem
                + ", mAllowAppOverlay=" + mAllowAppOverlay
                + '}';
                + '}';
    }
    }


@@ -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);
    }
    }
+93 −20
Original line number Original line Diff line number Diff line
@@ -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.
@@ -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.
@@ -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) {
@@ -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);
    }
    }


    /**
    /**
@@ -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.
     *
     *
@@ -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
     */
     */
@@ -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
     */
     */
@@ -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) {
@@ -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);
    }
    }
@@ -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;
    }
    }


@@ -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
@@ -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;
    }
    }


@@ -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
                + '}';
                + '}';
    }
    }


@@ -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