Merge "Make FGS notification deferral control tri-state" into sc-dev

This commit is contained in:
Chris Tate
2021-03-25 23:50:36 +00:00
committed by Android (Google) Code Review
5 changed files with 156 additions and 33 deletions

View File

@@ -5716,6 +5716,9 @@ package android.app {
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field @Deprecated public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
field public static final int FOREGROUND_SERVICE_DEFAULT = 0; // 0x0
field public static final int FOREGROUND_SERVICE_DEFERRED = 2; // 0x2
field public static final int FOREGROUND_SERVICE_IMMEDIATE = 1; // 0x1
field public static final int GROUP_ALERT_ALL = 0; // 0x0
field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
@@ -5919,6 +5922,7 @@ package android.app {
method @NonNull public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
method @NonNull public android.app.Notification.Builder setExtras(android.os.Bundle);
method @NonNull public android.app.Notification.Builder setFlag(int, boolean);
method @NonNull public android.app.Notification.Builder setForegroundServiceBehavior(int);
method @NonNull public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
method @NonNull public android.app.Notification.Builder setGroup(String);
method @NonNull public android.app.Notification.Builder setGroupAlertBehavior(int);
@@ -5937,7 +5941,7 @@ package android.app {
method @NonNull public android.app.Notification.Builder setRemoteInputHistory(CharSequence[]);
method @NonNull public android.app.Notification.Builder setSettingsText(CharSequence);
method @NonNull public android.app.Notification.Builder setShortcutId(String);
method @NonNull public android.app.Notification.Builder setShowForegroundImmediately(boolean);
method @Deprecated @NonNull public android.app.Notification.Builder setShowForegroundImmediately(boolean);
method @NonNull public android.app.Notification.Builder setShowWhen(boolean);
method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int);
method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int, int);

View File

@@ -272,6 +272,10 @@ package android.app {
method public abstract void onHomeVisibilityChanged(boolean);
}
public class Notification implements android.os.Parcelable {
method public boolean shouldShowForegroundImmediately();
}
public final class NotificationChannel implements android.os.Parcelable {
method public int getOriginalImportance();
method public boolean isBlockable();

View File

@@ -38,6 +38,7 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.StringRes;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -129,6 +130,52 @@ public class Notification implements Parcelable
{
private static final String TAG = "Notification";
/**
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FOREGROUND_SERVICE_DEFAULT,
FOREGROUND_SERVICE_IMMEDIATE,
FOREGROUND_SERVICE_DEFERRED
})
public @interface ServiceNotificationPolicy {};
/**
* If the Notification associated with starting a foreground service has been
* built using setForegroundServiceBehavior() with this behavior, display of
* the notification will usually be suppressed for a short time to avoid visual
* disturbances to the user.
* @see Notification.Builder#setForegroundServiceBehavior(int)
* @see #FOREGROUND_SERVICE_IMMEDIATE
* @see #FOREGROUND_SERVICE_DEFERRED
*/
public static final @ServiceNotificationPolicy int FOREGROUND_SERVICE_DEFAULT = 0;
/**
* If the Notification associated with starting a foreground service has been
* built using setForegroundServiceBehavior() with this behavior, display of
* the notification will be immediate even if the default behavior would be
* to defer visibility for a short time.
* @see Notification.Builder#setForegroundServiceBehavior(int)
* @see #FOREGROUND_SERVICE_DEFAULT
* @see #FOREGROUND_SERVICE_DEFERRED
*/
public static final @ServiceNotificationPolicy int FOREGROUND_SERVICE_IMMEDIATE = 1;
/**
* If the Notification associated with starting a foreground service has been
* built using setForegroundServiceBehavior() with this behavior, display of
* the notification will usually be suppressed for a short time to avoid visual
* disturbances to the user.
* @see Notification.Builder#setForegroundServiceBehavior(int)
* @see #FOREGROUND_SERVICE_DEFAULT
* @see #FOREGROUND_SERVICE_IMMEDIATE
*/
public static final @ServiceNotificationPolicy int FOREGROUND_SERVICE_DEFERRED = 2;
private int mFgsDeferBehavior;
/**
* An activity that provides a user interface for adjusting notification preferences for its
* containing application.
@@ -644,11 +691,6 @@ public class Notification implements Parcelable
*/
public static final int FLAG_BUBBLE = 0x00001000;
/**
* @hide
*/
public static final int FLAG_IMMEDIATE_FGS_DISPLAY = 0x00002000;
private static final List<Class<? extends Style>> PLATFORM_STYLE_CLASSES = Arrays.asList(
BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class,
@@ -658,8 +700,7 @@ public class Notification implements Parcelable
@IntDef(flag = true, prefix = { "FLAG_" }, value = {FLAG_SHOW_LIGHTS, FLAG_ONGOING_EVENT,
FLAG_INSISTENT, FLAG_ONLY_ALERT_ONCE,
FLAG_AUTO_CANCEL, FLAG_NO_CLEAR, FLAG_FOREGROUND_SERVICE, FLAG_HIGH_PRIORITY,
FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE,
FLAG_IMMEDIATE_FGS_DISPLAY})
FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE})
@Retention(RetentionPolicy.SOURCE)
public @interface NotificationFlags{};
@@ -2549,6 +2590,8 @@ public class Notification implements Parcelable
}
mAllowSystemGeneratedContextualActions = parcel.readBoolean();
mFgsDeferBehavior = parcel.readInt();
}
@Override
@@ -2664,6 +2707,7 @@ public class Notification implements Parcelable
that.mBadgeIcon = this.mBadgeIcon;
that.mSettingsText = this.mSettingsText;
that.mGroupAlertBehavior = this.mGroupAlertBehavior;
that.mFgsDeferBehavior = this.mFgsDeferBehavior;
that.mBubbleMetadata = this.mBubbleMetadata;
that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;
@@ -3063,6 +3107,8 @@ public class Notification implements Parcelable
parcel.writeBoolean(mAllowSystemGeneratedContextualActions);
parcel.writeInt(mFgsDeferBehavior);
// mUsesStandardHeader is not written because it should be recomputed in listeners
}
@@ -4531,10 +4577,40 @@ public class Notification implements Parcelable
* foreground service is shown as soon as the service's {@code startForeground()}
* method is called, even if the system's UI policy might otherwise defer
* its visibility to a later time.
* @deprecated Use setForegroundServiceBehavior(int) instead
*/
@Deprecated
@NonNull
public Builder setShowForegroundImmediately(boolean showImmediately) {
setFlag(FLAG_IMMEDIATE_FGS_DISPLAY, showImmediately);
setForegroundServiceBehavior(showImmediately
? FOREGROUND_SERVICE_IMMEDIATE
: FOREGROUND_SERVICE_DEFAULT);
return this;
}
/**
* Specify a desired visibility policy for a Notification associated with a
* foreground service. By default, the system can choose to defer
* visibility of the notification for a short time after the service is
* started. Pass
* {@link Notification#FOREGROUND_SERVICE_IMMEDIATE BEHAVIOR_IMMEDIATE_DISPLAY}
* to this method in order to guarantee that visibility is never deferred. Pass
* {@link Notification#FOREGROUND_SERVICE_DEFERRED BEHAVIOR_DEFERRED_DISPLAY}
* to request that visibility is deferred whenever possible.
*
* <p class="note">Note that deferred visibility is not guaranteed. There
* may be some circumstances under which the system will show the foreground
* service's associated Notification immediately even when the app has used
* this method to explicitly request deferred display.</p>
* @param behavior One of
* {@link Notification#FOREGROUND_SERVICE_DEFAULT BEHAVIOR_DEFAULT},
* {@link Notification#FOREGROUND_SERVICE_IMMEDIATE BEHAVIOR_IMMEDIATE_DISPLAY},
* or {@link Notification#FOREGROUND_SERVICE_DEFERRED BEHAVIOR_DEFERRED_DISPLAY}
* @return
*/
@NonNull
public Builder setForegroundServiceBehavior(int behavior) {
mN.mFgsDeferBehavior = behavior;
return this;
}
@@ -6717,30 +6793,59 @@ public class Notification implements Parcelable
* immediately when tied to a foreground service, even if the system might generally
* avoid showing the notifications for short-lived foreground service lifetimes.
*
* Immediate visibility of the Notification is recommended when:
* Immediate visibility of the Notification is indicated when:
* <ul>
* <li>The app specifically indicated it with
* {@link Notification.Builder#setShowForegroundImmediately(boolean)
* setShowForegroundImmediately(true)}</li>
* {@link Notification.Builder#setForegroundServiceBehavior(int)
* setForegroundServiceBehavior(BEHAVIOR_IMMEDIATE_DISPLAY)}</li>
* <li>It is a media notification or has an associated media session</li>
* <li>It is a call or navigation notification</li>
* <li>It provides additional action affordances</li>
* </ul>
* @return whether this notification should always be displayed immediately when
*
* If the app has specified
* {@code NotificationBuilder.setForegroundServiceBehavior(BEHAVIOR_DEFERRED_DISPLAY)}
* then this method will return {@code false} and notification visibility will be
* deferred following the service's transition to the foreground state even in the
* circumstances described above.
*
* @return whether this notification should be displayed immediately when
* its associated service transitions to the foreground state
* @hide
*/
@TestApi
public boolean shouldShowForegroundImmediately() {
if ((flags & Notification.FLAG_IMMEDIATE_FGS_DISPLAY) != 0
|| isMediaNotification() || hasMediaSession()
|| CATEGORY_CALL.equals(category)
|| CATEGORY_NAVIGATION.equals(category)
|| (actions != null && actions.length > 0)) {
// Has the app demanded immediate display?
if (mFgsDeferBehavior == FOREGROUND_SERVICE_IMMEDIATE) {
return true;
}
// Has the app demanded deferred display?
if (mFgsDeferBehavior == FOREGROUND_SERVICE_DEFERRED) {
return false;
}
// We show these sorts of notifications immediately in the absence of
// any explicit app declaration
if (isMediaNotification() || hasMediaSession()
|| CATEGORY_CALL.equals(category)
|| CATEGORY_NAVIGATION.equals(category)
|| (actions != null && actions.length > 0)) {
return true;
}
// No extenuating circumstances: defer visibility
return false;
}
/**
* Has forced deferral for FGS purposes been specified?
* @hide
*/
public boolean isForegroundDisplayForceDeferred() {
return FOREGROUND_SERVICE_DEFERRED == mFgsDeferBehavior;
}
/**
* @return whether this notification has a media session attached
* @hide

View File

@@ -300,7 +300,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
.setColorized(true)
.setColor(getResources().getColor(R.color.GM2_red_700))
.setOngoing(true)
.setShowForegroundImmediately(true)
.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
.setContentIntent(
PendingIntent.getService(this, REQUEST_CODE, stopIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))

View File

@@ -1977,20 +1977,30 @@ public final class ActiveServices {
&& isLegacyApp;
}
if (!showNow) {
// is the notification such that it should show right away?
showNow = r.foregroundNoti.shouldShowForegroundImmediately();
// or is this an type of FGS that always shows immediately?
if (!showNow) {
switch (r.foregroundServiceType) {
case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK:
case ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL:
case ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE:
case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION:
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r
+ " type gets immediate display");
}
showNow = true;
// has the app forced deferral?
if (!r.foregroundNoti.isForegroundDisplayForceDeferred()) {
// is the notification such that it should show right away?
showNow = r.foregroundNoti.shouldShowForegroundImmediately();
if (DEBUG_FOREGROUND_SERVICE && showNow) {
Slog.d(TAG_SERVICE, "FGS " + r
+ " notification policy says show immediately");
}
// or is this an type of FGS that always shows immediately?
if (!showNow) {
switch (r.foregroundServiceType) {
case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK:
case ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL:
case ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION:
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r
+ " type gets immediate display");
}
showNow = true;
}
}
} else {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.d(TAG_SERVICE, "FGS " + r + " notification is app deferred");
}
}
}