Allow notifications to be autocanceled at a time.
Test: cts Change-Id: I24ebcab2c0fa2028ec5d2984dc3b7ec19391b590
This commit is contained in:
@@ -5016,6 +5016,7 @@ package android.app {
|
||||
method public android.graphics.drawable.Icon getLargeIcon();
|
||||
method public android.graphics.drawable.Icon getSmallIcon();
|
||||
method public java.lang.String getSortKey();
|
||||
method public long getTimeout();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
|
||||
field public static final java.lang.String CATEGORY_ALARM = "alarm";
|
||||
@@ -5244,6 +5245,7 @@ package android.app {
|
||||
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
|
||||
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
|
||||
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
|
||||
method public android.app.Notification.Builder setTimeout(long);
|
||||
method public android.app.Notification.Builder setUsesChronometer(boolean);
|
||||
method public android.app.Notification.Builder setVibrate(long[]);
|
||||
method public android.app.Notification.Builder setVisibility(int);
|
||||
@@ -35873,9 +35875,9 @@ package android.service.notification {
|
||||
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
|
||||
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
|
||||
field public static final int REASON_SNOOZED = 18; // 0x12
|
||||
field public static final int REASON_TIMEOUT = 19; // 0x13
|
||||
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
|
||||
field public static final int REASON_USER_STOPPED = 6; // 0x6
|
||||
field public static final int REASON_USER_SWITCH = 19; // 0x13
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
|
||||
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
|
||||
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
|
||||
|
||||
@@ -5174,6 +5174,7 @@ package android.app {
|
||||
method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
|
||||
method public android.graphics.drawable.Icon getSmallIcon();
|
||||
method public java.lang.String getSortKey();
|
||||
method public long getTimeout();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
|
||||
field public static final java.lang.String CATEGORY_ALARM = "alarm";
|
||||
@@ -5404,6 +5405,7 @@ package android.app {
|
||||
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
|
||||
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
|
||||
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
|
||||
method public android.app.Notification.Builder setTimeout(long);
|
||||
method public android.app.Notification.Builder setUsesChronometer(boolean);
|
||||
method public android.app.Notification.Builder setVibrate(long[]);
|
||||
method public android.app.Notification.Builder setVisibility(int);
|
||||
@@ -38861,9 +38863,9 @@ package android.service.notification {
|
||||
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
|
||||
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
|
||||
field public static final int REASON_SNOOZED = 18; // 0x12
|
||||
field public static final int REASON_TIMEOUT = 19; // 0x13
|
||||
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
|
||||
field public static final int REASON_USER_STOPPED = 6; // 0x6
|
||||
field public static final int REASON_USER_SWITCH = 19; // 0x13
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
|
||||
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
|
||||
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
|
||||
|
||||
@@ -5026,6 +5026,7 @@ package android.app {
|
||||
method public android.graphics.drawable.Icon getLargeIcon();
|
||||
method public android.graphics.drawable.Icon getSmallIcon();
|
||||
method public java.lang.String getSortKey();
|
||||
method public long getTimeout();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
|
||||
field public static final java.lang.String CATEGORY_ALARM = "alarm";
|
||||
@@ -5254,6 +5255,7 @@ package android.app {
|
||||
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
|
||||
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
|
||||
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
|
||||
method public android.app.Notification.Builder setTimeout(long);
|
||||
method public android.app.Notification.Builder setUsesChronometer(boolean);
|
||||
method public android.app.Notification.Builder setVibrate(long[]);
|
||||
method public android.app.Notification.Builder setVisibility(int);
|
||||
@@ -35994,9 +35996,9 @@ package android.service.notification {
|
||||
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
|
||||
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
|
||||
field public static final int REASON_SNOOZED = 18; // 0x12
|
||||
field public static final int REASON_TIMEOUT = 19; // 0x13
|
||||
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
|
||||
field public static final int REASON_USER_STOPPED = 6; // 0x6
|
||||
field public static final int REASON_USER_SWITCH = 19; // 0x13
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
|
||||
field public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1; // 0x1
|
||||
field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 2; // 0x2
|
||||
|
||||
@@ -1022,6 +1022,7 @@ public class Notification implements Parcelable
|
||||
private Icon mLargeIcon;
|
||||
|
||||
private String mChannelId;
|
||||
private long mTimeout;
|
||||
|
||||
/**
|
||||
* Structure to encapsulate a named action that can be shown as part of this notification.
|
||||
@@ -1766,6 +1767,7 @@ public class Notification implements Parcelable
|
||||
if (parcel.readInt() != 0) {
|
||||
mChannelId = parcel.readString();
|
||||
}
|
||||
mTimeout = parcel.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1872,6 +1874,7 @@ public class Notification implements Parcelable
|
||||
that.color = this.color;
|
||||
|
||||
that.mChannelId = this.mChannelId;
|
||||
that.mTimeout = this.mTimeout;
|
||||
|
||||
if (!heavy) {
|
||||
that.lightenPayload(); // will clean out extras
|
||||
@@ -2128,6 +2131,7 @@ public class Notification implements Parcelable
|
||||
} else {
|
||||
parcel.writeInt(0);
|
||||
}
|
||||
parcel.writeLong(mTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2324,6 +2328,13 @@ public class Notification implements Parcelable
|
||||
return mChannelId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which this notification should be canceled, if it's not canceled already.
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return mTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* The small icon representing this notification in the status bar and content view.
|
||||
*
|
||||
@@ -2531,6 +2542,15 @@ public class Notification implements Parcelable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the time at which this notification should be canceled, if it is not already
|
||||
* canceled.
|
||||
*/
|
||||
public Builder setTimeout(long when) {
|
||||
mN.mTimeout = when;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a timestamp pertaining to the notification (usually the time the event occurred).
|
||||
*
|
||||
|
||||
@@ -183,8 +183,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
public static final int REASON_CHANNEL_BANNED = 17;
|
||||
/** Notification was snoozed. */
|
||||
public static final int REASON_SNOOZED = 18;
|
||||
/** Notification no longer visible because of user switch */
|
||||
public static final int REASON_USER_SWITCH = 19;
|
||||
/** Notification was canceled due to timeout */
|
||||
public static final int REASON_TIMEOUT = 19;
|
||||
|
||||
/**
|
||||
* The full trim of the StatusBarNotification including all its features.
|
||||
|
||||
@@ -443,6 +443,7 @@
|
||||
<protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
|
||||
<protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
|
||||
|
||||
<protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
|
||||
<protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
|
||||
<protected-broadcast android:name="EventConditionProvider.EVALUATE" />
|
||||
<protected-broadcast android:name="SnoozeHelper.EVALUATE" />
|
||||
|
||||
@@ -32,6 +32,7 @@ import static android.service.notification.NotificationListenerService.REASON_PA
|
||||
import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
|
||||
import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
|
||||
import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
|
||||
import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
|
||||
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
|
||||
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
|
||||
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
|
||||
@@ -50,6 +51,7 @@ import android.Manifest;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AutomaticZenRule;
|
||||
@@ -165,6 +167,7 @@ import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -229,6 +232,12 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
private static final long DELAY_FOR_ASSISTANT_TIME = 100;
|
||||
|
||||
private static final String ACTION_NOTIFICATION_TIMEOUT =
|
||||
NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
|
||||
private static final int REQUEST_CODE_TIMEOUT = 1;
|
||||
private static final String SCHEME_TIMEOUT = "timeout";
|
||||
private static final String EXTRA_KEY = "key";
|
||||
|
||||
private IActivityManager mAm;
|
||||
private IPackageManager mPackageManager;
|
||||
private PackageManager mPackageManagerClient;
|
||||
@@ -237,6 +246,7 @@ public class NotificationManagerService extends SystemService {
|
||||
@Nullable StatusBarManagerInternal mStatusBar;
|
||||
Vibrator mVibrator;
|
||||
private WindowManagerInternal mWindowManagerInternal;
|
||||
private AlarmManager mAlarmManager;
|
||||
|
||||
final IBinder mForegroundToken = new Binder();
|
||||
private Handler mHandler;
|
||||
@@ -682,6 +692,29 @@ public class NotificationManagerService extends SystemService {
|
||||
updateLightsLocked();
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
|
||||
final NotificationRecord record;
|
||||
synchronized (mNotificationLock) {
|
||||
record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
|
||||
}
|
||||
if (record != null) {
|
||||
cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
|
||||
record.sbn.getPackageName(), record.sbn.getTag(),
|
||||
record.sbn.getId(), 0,
|
||||
Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
|
||||
REASON_TIMEOUT, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
@@ -966,6 +999,7 @@ public class NotificationManagerService extends SystemService {
|
||||
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
|
||||
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
|
||||
mHandler = new WorkerHandler(looper);
|
||||
mRankingThread.start();
|
||||
@@ -1132,6 +1166,10 @@ public class NotificationManagerService extends SystemService {
|
||||
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
|
||||
null);
|
||||
|
||||
IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
|
||||
timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
|
||||
getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
|
||||
|
||||
mSettingsObserver = new SettingsObserver(mHandler);
|
||||
|
||||
mArchive = new Archive(resources.getInteger(
|
||||
@@ -3011,6 +3049,7 @@ public class NotificationManagerService extends SystemService {
|
||||
public void run() {
|
||||
synchronized (mNotificationLock) {
|
||||
mEnqueuedNotifications.add(r);
|
||||
scheduleTimeoutLocked(r);
|
||||
|
||||
if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) {
|
||||
// TODO: log to event log
|
||||
@@ -3240,6 +3279,22 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void scheduleTimeoutLocked(NotificationRecord record) {
|
||||
if (record.getNotification().getTimeout() > System.currentTimeMillis()) {
|
||||
final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
|
||||
REQUEST_CODE_TIMEOUT,
|
||||
new Intent(ACTION_NOTIFICATION_TIMEOUT)
|
||||
.setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
|
||||
.appendPath(record.getKey()).build())
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
|
||||
.putExtra(EXTRA_KEY, record.getKey()),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
mAlarmManager.setExactAndAllowWhileIdle(
|
||||
AlarmManager.RTC_WAKEUP, record.getNotification().getTimeout(), pi);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void buzzBeepBlinkLocked(NotificationRecord record) {
|
||||
boolean buzz = false;
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.EventLogTags;
|
||||
@@ -318,6 +319,7 @@ public final class NotificationRecord {
|
||||
pw.println(prefix + " vibrate=" + Arrays.toString(notification.vibrate));
|
||||
pw.println(prefix + String.format(" led=0x%08x onMs=%d offMs=%d",
|
||||
notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
|
||||
pw.println(prefix + " timeout=" + TimeUtils.formatForLogging(notification.getTimeout()));
|
||||
if (notification.actions != null && notification.actions.length > 0) {
|
||||
pw.println(prefix + " actions={");
|
||||
final int N = notification.actions.length;
|
||||
|
||||
@@ -424,6 +424,17 @@ public class NotificationTestList extends TestActivity
|
||||
mNM.notify("secret", 7012, n);
|
||||
}
|
||||
},
|
||||
new Test("1 minute timeout") {
|
||||
public void run()
|
||||
{
|
||||
Notification n = new Notification.Builder(NotificationTestList.this)
|
||||
.setSmallIcon(R.drawable.icon2)
|
||||
.setContentTitle("timeout in a minute")
|
||||
.setTimeout(System.currentTimeMillis() + (1000 * 60))
|
||||
.build();
|
||||
mNM.notify("timeout_min", 7013, n);
|
||||
}
|
||||
},
|
||||
new Test("Off") {
|
||||
public void run() {
|
||||
PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
|
||||
|
||||
Reference in New Issue
Block a user