Merge "Allow listeners more snoozing options."
This commit is contained in:
committed by
Android (Google) Code Review
commit
1bbd133d7c
@@ -35094,6 +35094,8 @@ package android.service.notification {
|
||||
method public final void requestUnbind();
|
||||
method public final void setNotificationsShown(java.lang.String[]);
|
||||
method public final void snoozeNotification(java.lang.String, long);
|
||||
method public final void snoozeNotification(java.lang.String);
|
||||
method public final void unsnoozeNotification(java.lang.String);
|
||||
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
|
||||
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
|
||||
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
|
||||
|
||||
@@ -37893,7 +37893,9 @@ package android.service.notification {
|
||||
method public final void setNotificationsShown(java.lang.String[]);
|
||||
method public final void setOnNotificationPostedTrim(int);
|
||||
method public final void snoozeNotification(java.lang.String, long);
|
||||
method public final void snoozeNotification(java.lang.String);
|
||||
method public void unregisterAsSystemService() throws android.os.RemoteException;
|
||||
method public final void unsnoozeNotification(java.lang.String);
|
||||
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
|
||||
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
|
||||
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
|
||||
|
||||
@@ -5395,6 +5395,7 @@ package android.app {
|
||||
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
|
||||
method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
|
||||
method public final int getCurrentInterruptionFilter();
|
||||
method public android.content.ComponentName getEffectsSuppressor();
|
||||
method public int getImportance();
|
||||
method public android.app.NotificationChannel getNotificationChannel(java.lang.String);
|
||||
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
|
||||
@@ -35187,6 +35188,8 @@ package android.service.notification {
|
||||
method public final void requestUnbind();
|
||||
method public final void setNotificationsShown(java.lang.String[]);
|
||||
method public final void snoozeNotification(java.lang.String, long);
|
||||
method public final void snoozeNotification(java.lang.String);
|
||||
method public final void unsnoozeNotification(java.lang.String);
|
||||
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
|
||||
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
|
||||
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
|
||||
|
||||
@@ -77,7 +77,10 @@ interface INotificationManager
|
||||
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
|
||||
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
|
||||
|
||||
void snoozeNotificationFromListener(in INotificationListener token, String key, long until);
|
||||
|
||||
void snoozeNotificationUntilFromListener(in INotificationListener token, String key, long until);
|
||||
void snoozeNotificationFromListener(in INotificationListener token, String key);
|
||||
void unsnoozeNotificationFromListener(in INotificationListener token, String key);
|
||||
|
||||
void requestBindListener(in ComponentName component);
|
||||
void requestUnbindListener(in INotificationListener token);
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.app;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.TestApi;
|
||||
import android.app.Notification.Builder;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -428,6 +429,7 @@ public class NotificationManager
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public ComponentName getEffectsSuppressor() {
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
|
||||
@@ -534,7 +534,46 @@ public abstract class NotificationListenerService extends Service {
|
||||
public final void snoozeNotification(String key, long snoozeUntil) {
|
||||
if (!isBound()) return;
|
||||
try {
|
||||
getNotificationInterface().snoozeNotificationFromListener(mWrapper, key, snoozeUntil);
|
||||
getNotificationInterface().snoozeNotificationUntilFromListener(
|
||||
mWrapper, key, snoozeUntil);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the notification manager about snoozing a specific notification.
|
||||
* <p>
|
||||
* Use this to snooze a notification for an indeterminate time. Upon being informed, the
|
||||
* notification manager will actually remove the notification and you will get an
|
||||
* {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
|
||||
* snoozing period expires, you will get a
|
||||
* {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
|
||||
* notification. Use {@link #unsnoozeNotification(String)} to restore the notification.
|
||||
* @param key The key of the notification to snooze
|
||||
*/
|
||||
public final void snoozeNotification(String key) {
|
||||
if (!isBound()) return;
|
||||
try {
|
||||
getNotificationInterface().snoozeNotificationFromListener(mWrapper, key);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the notification manager about un-snoozing a specific notification.
|
||||
* <p>
|
||||
* This should only be used for notifications snoozed by this listener using
|
||||
* {@link #snoozeNotification(String)}. Once un-snoozed, you will get a
|
||||
* {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
|
||||
* notification.
|
||||
* @param key The key of the notification to snooze
|
||||
*/
|
||||
public final void unsnoozeNotification(String key) {
|
||||
if (!isBound()) return;
|
||||
try {
|
||||
getNotificationInterface().unsnoozeNotificationFromListener(mWrapper, key);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
|
||||
@@ -1837,7 +1837,7 @@ public class NotificationManagerService extends SystemService {
|
||||
* @param token The binder for the listener, to check that the caller is allowed
|
||||
*/
|
||||
@Override
|
||||
public void snoozeNotificationFromListener(INotificationListener token, String key,
|
||||
public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
|
||||
long snoozeUntil) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -1848,6 +1848,38 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow an INotificationListener to snooze a single notification.
|
||||
*
|
||||
* @param token The binder for the listener, to check that the caller is allowed
|
||||
*/
|
||||
@Override
|
||||
public void snoozeNotificationFromListener(INotificationListener token, String key) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
|
||||
snoozeNotificationInt(key, info);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow an INotificationListener to un-snooze a single notification.
|
||||
*
|
||||
* @param token The binder for the listener, to check that the caller is allowed
|
||||
*/
|
||||
@Override
|
||||
public void unsnoozeNotificationFromListener(INotificationListener token, String key) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
|
||||
unsnoozeNotificationInt(key, info);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow an INotificationListener to simulate clearing (dismissing) a single notification.
|
||||
*
|
||||
@@ -2206,7 +2238,6 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public ComponentName getEffectsSuppressor() {
|
||||
enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
|
||||
return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
|
||||
}
|
||||
|
||||
@@ -3686,6 +3717,34 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
void snoozeNotificationInt(String key, ManagedServiceInfo listener) {
|
||||
String listenerName = listener == null ? null : listener.component.toShortString();
|
||||
// TODO: write to event log
|
||||
if (DBG) {
|
||||
Slog.d(TAG, String.format("snooze event(%s, %s)", key, listenerName));
|
||||
}
|
||||
synchronized (mNotificationList) {
|
||||
final NotificationRecord r = mNotificationsByKey.get(key);
|
||||
if (r != null) {
|
||||
mNotificationList.remove(r);
|
||||
cancelNotificationLocked(r, false, REASON_SNOOZED);
|
||||
updateLightsLocked();
|
||||
mSnoozeHelper.snooze(r, r.getUser().getIdentifier());
|
||||
savePolicyFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
|
||||
String listenerName = listener == null ? null : listener.component.toShortString();
|
||||
// TODO: write to event log
|
||||
if (DBG) {
|
||||
Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
|
||||
}
|
||||
mSnoozeHelper.repost(key, Binder.getCallingUid());
|
||||
savePolicyFile();
|
||||
}
|
||||
|
||||
void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
|
||||
ManagedServiceInfo listener, boolean includeCurrentProfiles) {
|
||||
String listenerName = listener == null ? null : listener.component.toShortString();
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
@@ -62,6 +63,8 @@ public class SnoozeHelper {
|
||||
// User id : package name : notification key : record.
|
||||
private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, NotificationRecord>>>
|
||||
mSnoozedNotifications = new ArrayMap<>();
|
||||
// notification key : package.
|
||||
private ArrayMap<String, String> mPackages = new ArrayMap<>();
|
||||
private Callback mCallback;
|
||||
|
||||
public SnoozeHelper(Context context, Callback callback,
|
||||
@@ -82,10 +85,20 @@ public class SnoozeHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a notification that should be snoozed until the given time and schedules an alarm
|
||||
* to repost at that time.
|
||||
* Snoozes a notification and schedules an alarm to repost at that time.
|
||||
*/
|
||||
protected void snooze(NotificationRecord record, int userId, long until) {
|
||||
snooze(record, userId);
|
||||
scheduleRepost(record.sbn.getPackageName(), record.getKey(), userId, until);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a snoozed notification.
|
||||
*/
|
||||
protected void snooze(NotificationRecord record, int userId) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Snoozing " + record.getKey());
|
||||
}
|
||||
ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
|
||||
mSnoozedNotifications.get(userId);
|
||||
if (records == null) {
|
||||
@@ -98,13 +111,9 @@ public class SnoozeHelper {
|
||||
pkgRecords.put(record.getKey(), record);
|
||||
records.put(record.sbn.getPackageName(), pkgRecords);
|
||||
mSnoozedNotifications.put(userId, records);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Snoozing " + record.getKey() + " until " + new Date(until));
|
||||
}
|
||||
scheduleRepost(record.sbn.getPackageName(), record.getKey(), userId, until);
|
||||
mPackages.put(record.getKey(), record.sbn.getPackageName());
|
||||
}
|
||||
|
||||
|
||||
protected boolean cancel(int userId, String pkg, String tag, int id) {
|
||||
if (mSnoozedNotifications.containsKey(userId)) {
|
||||
ArrayMap<String, NotificationRecord> recordsForPkg =
|
||||
@@ -121,6 +130,7 @@ public class SnoozeHelper {
|
||||
if (key != null) {
|
||||
recordsForPkg.remove(key);
|
||||
cancelAlarm(userId, pkg, key);
|
||||
mPackages.remove(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -145,6 +155,7 @@ public class SnoozeHelper {
|
||||
int P = records.size();
|
||||
for (int k = 0; k < P; k++) {
|
||||
cancelAlarm(userId, snoozedPkgs.keyAt(j), records.keyAt(k));
|
||||
mPackages.remove(records.keyAt(k));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,6 +173,7 @@ public class SnoozeHelper {
|
||||
int N = records.size();
|
||||
for (int i = 0; i < N; i++) {
|
||||
cancelAlarm(userId, pkg, records.keyAt(i));
|
||||
mPackages.remove(records.keyAt(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -190,8 +202,8 @@ public class SnoozeHelper {
|
||||
pkgRecords.put(record.getKey(), record);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void repost(String pkg, String key, int userId) {
|
||||
protected void repost(String key, int userId) {
|
||||
final String pkg = mPackages.remove(key);
|
||||
ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
|
||||
mSnoozedNotifications.get(userId);
|
||||
if (records == null) {
|
||||
@@ -202,6 +214,7 @@ public class SnoozeHelper {
|
||||
return;
|
||||
}
|
||||
final NotificationRecord record = pkgRecords.remove(key);
|
||||
|
||||
if (record != null) {
|
||||
mCallback.repost(userId, record);
|
||||
}
|
||||
@@ -213,7 +226,6 @@ public class SnoozeHelper {
|
||||
new Intent(REPOST_ACTION)
|
||||
.setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build())
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
|
||||
.putExtra(EXTRA_PKG, pkg)
|
||||
.putExtra(EXTRA_KEY, key)
|
||||
.putExtra(EXTRA_USER_ID, userId),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
@@ -273,8 +285,8 @@ public class SnoozeHelper {
|
||||
Slog.d(TAG, "Reposting notification");
|
||||
}
|
||||
if (REPOST_ACTION.equals(intent.getAction())) {
|
||||
repost(intent.getStringExtra(EXTRA_PKG), intent.getStringExtra(EXTRA_KEY),
|
||||
intent.getIntExtra(EXTRA_USER_ID, 0));
|
||||
repost(intent.getStringExtra(EXTRA_KEY), intent.getIntExtra(EXTRA_USER_ID,
|
||||
UserHandle.USER_SYSTEM));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -37,6 +37,7 @@ import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -65,7 +66,7 @@ public class SnoozeHelperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnooze() throws Exception {
|
||||
public void testSnoozeForTime() throws Exception {
|
||||
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
|
||||
mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
|
||||
verify(mAm, times(1)).setExactAndAllowWhileIdle(
|
||||
@@ -74,6 +75,16 @@ public class SnoozeHelperTest {
|
||||
UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnooze() throws Exception {
|
||||
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
|
||||
mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM);
|
||||
verify(mAm, never()).setExactAndAllowWhileIdle(
|
||||
anyInt(), anyLong(), any(PendingIntent.class));
|
||||
assertTrue(mSnoozeHelper.isSnoozed(
|
||||
UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelByApp() throws Exception {
|
||||
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
|
||||
@@ -152,7 +163,7 @@ public class SnoozeHelperTest {
|
||||
mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
|
||||
NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL);
|
||||
mSnoozeHelper.snooze(r2 , UserHandle.USER_ALL, 1000);
|
||||
mSnoozeHelper.repost(r.sbn.getPackageName(), r.getKey(), UserHandle.USER_SYSTEM);
|
||||
mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM);
|
||||
verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
|
||||
}
|
||||
|
||||
@@ -165,7 +176,7 @@ public class SnoozeHelperTest {
|
||||
mSnoozeHelper.update(UserHandle.USER_SYSTEM, r);
|
||||
verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class));
|
||||
|
||||
mSnoozeHelper.repost(r.sbn.getPackageName(), r.getKey(), UserHandle.USER_SYSTEM);
|
||||
mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM);
|
||||
verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user