Merge "Allow companion device mgrs channel access" into oc-dev

This commit is contained in:
TreeHugger Robot
2017-04-12 01:22:49 +00:00
committed by Android (Google) Code Review
12 changed files with 628 additions and 39 deletions

View File

@@ -37304,12 +37304,16 @@ package android.service.notification {
method public final int getCurrentInterruptionFilter();
method public final int getCurrentListenerHints();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String);
method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
method public void onListenerDisconnected();
method public void onListenerHintsChanged(int);
method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int);
method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int);
method public void onNotificationPosted(android.service.notification.StatusBarNotification);
method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
@@ -37322,6 +37326,7 @@ 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 updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
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
@@ -37330,6 +37335,9 @@ package android.service.notification {
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
field public static final int REASON_CANCEL = 2; // 0x2

View File

@@ -40432,12 +40432,16 @@ package android.service.notification {
method public final int getCurrentInterruptionFilter();
method public final int getCurrentListenerHints();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String);
method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
method public void onListenerDisconnected();
method public void onListenerHintsChanged(int);
method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int);
method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int);
method public void onNotificationPosted(android.service.notification.StatusBarNotification);
method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
@@ -40454,6 +40458,7 @@ package android.service.notification {
method public final void snoozeNotification(java.lang.String, java.lang.String);
method public final void snoozeNotification(java.lang.String, long);
method public void unregisterAsSystemService() throws android.os.RemoteException;
method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
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
@@ -40462,6 +40467,9 @@ package android.service.notification {
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
field public static final int REASON_CANCEL = 2; // 0x2

View File

@@ -37489,12 +37489,16 @@ package android.service.notification {
method public final int getCurrentInterruptionFilter();
method public final int getCurrentListenerHints();
method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(java.lang.String);
method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
method public void onListenerDisconnected();
method public void onListenerHintsChanged(int);
method public void onNotificationChannelGroupModified(java.lang.String, android.app.NotificationChannelGroup, int);
method public void onNotificationChannelModified(java.lang.String, android.app.NotificationChannel, int);
method public void onNotificationPosted(android.service.notification.StatusBarNotification);
method public void onNotificationPosted(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRankingUpdate(android.service.notification.NotificationListenerService.RankingMap);
@@ -37508,6 +37512,7 @@ package android.service.notification {
method public final void setNotificationsShown(java.lang.String[]);
method public final void snoozeNotification(java.lang.String, java.lang.String);
method public final void snoozeNotification(java.lang.String, long);
method public final void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
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
@@ -37516,6 +37521,9 @@ package android.service.notification {
field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; // 0x3
field public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; // 0x2
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
field public static final int REASON_CANCEL = 2; // 0x2

View File

@@ -101,6 +101,10 @@ interface INotificationManager
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in NotificationChannel channel);
ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg);
ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg);
void applyEnqueuedAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment);
void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment);
void applyAdjustmentsFromAssistant(in INotificationListener token, in List<Adjustment> adjustments);

View File

@@ -16,6 +16,8 @@
package android.service.notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.service.notification.IStatusBarNotificationHolder;
import android.service.notification.StatusBarNotification;
import android.service.notification.NotificationRankingUpdate;
@@ -33,6 +35,10 @@ oneway interface INotificationListener
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
// companion device managers only
void onNotificationChannelModification(String pkgName, in NotificationChannel channel, int modificationType);
void onNotificationChannelGroupModification(String pkgName, in NotificationChannelGroup group, int modificationType);
// rankers only
void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder);
void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);

View File

@@ -138,7 +138,6 @@ public abstract class NotificationAssistantService extends NotificationListenerS
}
}
private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper {
@Override
public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder) {

View File

@@ -16,8 +16,13 @@
package android.service.notification;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.companion.CompanionDeviceManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -51,6 +56,8 @@ import android.widget.RemoteViews;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.SomeArgs;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -59,7 +66,7 @@ import java.util.List;
* A service that receives calls from the system when new notifications are
* posted or removed, or their ranking changed.
* <p>To extend this class, you must declare the service in your manifest file with
* the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission
* the {@link Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission
* and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
* <pre>
* &lt;service android:name=".NotificationListener"
@@ -215,6 +222,37 @@ public abstract class NotificationListenerService extends Service {
@SystemApi
public static final int TRIM_LIGHT = 1;
/** @hide */
@IntDef({NOTIFICATION_CHANNEL_OR_GROUP_ADDED, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED,
NOTIFICATION_CHANNEL_OR_GROUP_DELETED})
@Retention(RetentionPolicy.SOURCE)
public @interface ChannelOrGroupModificationTypes {}
/**
* Channel or group modification reason provided to
* {@link #onNotificationChannelModified(String, NotificationChannel, int)} or
* {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the
* provided object was created.
*/
public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1;
/**
* Channel or group modification reason provided to
* {@link #onNotificationChannelModified(String, NotificationChannel, int)} or
* {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the
* provided object was updated.
*/
public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2;
/**
* Channel or group modification reason provided to
* {@link #onNotificationChannelModified(String, NotificationChannel, int)} or
* {@link #onNotificationChannelGroupModified(String, NotificationChannelGroup, int)}- the
* provided object was deleted.
*/
public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3;
private final Object mLock = new Object();
private Handler mHandler;
@@ -387,6 +425,40 @@ public abstract class NotificationListenerService extends Service {
// optional
}
/**
* Implement this method to learn about notification channel modifications.
*
* <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated
* device} in order to receive this callback.
*
* @param pkg The package the channel belongs to.
* @param channel The channel that has changed.
* @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED},
* {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED},
* {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}.
*/
public void onNotificationChannelModified(String pkg, NotificationChannel channel,
@ChannelOrGroupModificationTypes int modificationType) {
// optional
}
/**
* Implement this method to learn about notification channel group modifications.
*
* <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated
* device} in order to receive this callback.
*
* @param pkg The package the group belongs to.
* @param group The group that has changed.
* @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED},
* {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED},
* {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}.
*/
public void onNotificationChannelGroupModified(String pkg, NotificationChannelGroup group,
@ChannelOrGroupModificationTypes int modificationType) {
// optional
}
/**
* Implement this method to be notified when the
* {@link #getCurrentInterruptionFilter() interruption filter} changed.
@@ -587,6 +659,69 @@ public abstract class NotificationListenerService extends Service {
}
}
/**
* Updates a notification channel for a given package. This should only be used to reflect
* changes a user has made to the channel via the listener's user interface.
*
* <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated
* device} in order to use this method.
*
* @param pkg The package the channel belongs to.
* @param channel the channel to update.
*/
public final void updateNotificationChannel(@NonNull String pkg,
@NonNull NotificationChannel channel) {
if (!isBound()) return;
try {
getNotificationInterface().updateNotificationChannelFromPrivilegedListener(
mWrapper, pkg, channel);
} catch (RemoteException e) {
Log.v(TAG, "Unable to contact notification manager", e);
throw e.rethrowFromSystemServer();
}
}
/**
* Returns all notification channels belonging to the given package.
*
* <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated
* device} in order to use this method.
*
* @param pkg The package to retrieve channels for.
*/
public final List<NotificationChannel> getNotificationChannels(@NonNull String pkg) {
if (!isBound()) return null;
try {
return getNotificationInterface().getNotificationChannelsFromPrivilegedListener(
mWrapper, pkg).getList();
} catch (RemoteException e) {
Log.v(TAG, "Unable to contact notification manager", e);
throw e.rethrowFromSystemServer();
}
}
/**
* Returns all notification channel groups belonging to the given package.
*
* <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated
* device} in order to use this method.
*
* @param pkg The package to retrieve channel groups for.
*/
public final List<NotificationChannelGroup> getNotificationChannelGroups(@NonNull String pkg) {
if (!isBound()) return null;
try {
return getNotificationInterface().getNotificationChannelGroupsFromPrivilegedListener(
mWrapper, pkg).getList();
} catch (RemoteException e) {
Log.v(TAG, "Unable to contact notification manager", e);
throw e.rethrowFromSystemServer();
}
}
/**
* Sets the notification trim that will be received via {@link #onNotificationPosted}.
*
@@ -1116,6 +1251,28 @@ public abstract class NotificationListenerService extends Service {
// no-op in the listener
}
@Override
public void onNotificationChannelModification(String pkgName, NotificationChannel channel,
@ChannelOrGroupModificationTypes int modificationType) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = pkgName;
args.arg2 = channel;
args.arg3 = modificationType;
mHandler.obtainMessage(
MyHandler.MSG_ON_NOTIFICATION_CHANNEL_MODIFIED, args).sendToTarget();
}
@Override
public void onNotificationChannelGroupModification(String pkgName,
NotificationChannelGroup group,
@ChannelOrGroupModificationTypes int modificationType) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = pkgName;
args.arg2 = group;
args.arg3 = modificationType;
mHandler.obtainMessage(
MyHandler.MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED, args).sendToTarget();
}
}
/**
@@ -1632,6 +1789,8 @@ public abstract class NotificationListenerService extends Service {
public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4;
public static final int MSG_ON_LISTENER_HINTS_CHANGED = 5;
public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
public static final int MSG_ON_NOTIFICATION_CHANNEL_MODIFIED = 7;
public static final int MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED = 8;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -1678,6 +1837,22 @@ public abstract class NotificationListenerService extends Service {
final int interruptionFilter = msg.arg1;
onInterruptionFilterChanged(interruptionFilter);
} break;
case MSG_ON_NOTIFICATION_CHANNEL_MODIFIED: {
SomeArgs args = (SomeArgs) msg.obj;
String pkgName = (String) args.arg1;
NotificationChannel channel = (NotificationChannel) args.arg2;
int modificationType = (int) args.arg3;
onNotificationChannelModified(pkgName, channel, modificationType);
} break;
case MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED: {
SomeArgs args = (SomeArgs) msg.obj;
String pkgName = (String) args.arg1;
NotificationChannelGroup group = (NotificationChannelGroup) args.arg2;
int modificationType = (int) args.arg3;
onNotificationChannelGroupModified(pkgName, group, modificationType);
} break;
}
}
}

View File

@@ -154,6 +154,13 @@ abstract public class ManagedServices {
abstract protected void onServiceAdded(ManagedServiceInfo info);
protected List<ManagedServiceInfo> getServices() {
synchronized (mMutex) {
List<ManagedServiceInfo> services = new ArrayList<>(mServices);
return services;
}
}
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
private ManagedServiceInfo newServiceInfo(IInterface service,

View File

@@ -19,6 +19,12 @@ package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.service.notification.NotificationListenerService
.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
import static android.service.notification.NotificationListenerService
.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
import static android.service.notification.NotificationListenerService
.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
@@ -70,6 +76,7 @@ import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -100,6 +107,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -144,6 +152,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -260,6 +269,7 @@ public class NotificationManagerService extends SystemService {
Vibrator mVibrator;
private WindowManagerInternal mWindowManagerInternal;
private AlarmManager mAlarmManager;
private ICompanionDeviceManager mCompanionManager;
final IBinder mForegroundToken = new Binder();
private Handler mHandler;
@@ -1004,7 +1014,8 @@ public class NotificationManagerService extends SystemService {
// TODO: Tests should call onStart instead once the methods above are removed.
@VisibleForTesting
void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
LightsManager lightsManager, NotificationListeners notificationListeners) {
LightsManager lightsManager, NotificationListeners notificationListeners,
ICompanionDeviceManager companionManager) {
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1017,6 +1028,7 @@ public class NotificationManagerService extends SystemService {
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mCompanionManager = companionManager;
mHandler = new WorkerHandler(looper);
mRankingThread.start();
@@ -1192,7 +1204,8 @@ public class NotificationManagerService extends SystemService {
@Override
public void onStart() {
init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class), new NotificationListeners());
getLocalService(LightsManager.class), new NotificationListeners(),
null);
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
@@ -1294,7 +1307,8 @@ public class NotificationManagerService extends SystemService {
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
}
private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel) {
private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
boolean fromListener) {
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
// cancel
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
@@ -1303,6 +1317,14 @@ public class NotificationManagerService extends SystemService {
}
mRankingHelper.updateNotificationChannel(pkg, uid, channel);
final NotificationChannel modifiedChannel =
mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
if (!fromListener) {
mListeners.notifyNotificationChannelChanged(
pkg, modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
}
synchronized (mNotificationLock) {
final int N = mNotificationList.size();
for (int i = N - 1; i >= 0; --i) {
@@ -1311,8 +1333,7 @@ public class NotificationManagerService extends SystemService {
&& r.sbn.getUid() == uid
&& channel.getId() != null
&& channel.getId().equals(r.getChannel().getId())) {
r.updateNotificationChannel(mRankingHelper.getNotificationChannel(
pkg, uid, channel.getId(), false));
r.updateNotificationChannel(modifiedChannel);
}
}
}
@@ -1626,6 +1647,8 @@ public class NotificationManagerService extends SystemService {
Preconditions.checkNotNull(group, "group in list is null");
mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
true /* fromTargetApp */);
mListeners.notifyNotificationChannelGroupChanged(pkg, group,
NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
}
savePolicyFile();
}
@@ -1639,6 +1662,9 @@ public class NotificationManagerService extends SystemService {
Preconditions.checkNotNull(channel, "channel in list is null");
mRankingHelper.createNotificationChannel(pkg, uid, channel,
true /* fromTargetApp */);
mListeners.notifyNotificationChannelChanged(pkg,
mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
}
savePolicyFile();
}
@@ -1674,12 +1700,16 @@ public class NotificationManagerService extends SystemService {
@Override
public void deleteNotificationChannel(String pkg, String channelId) {
checkCallerIsSystemOrSameApp(pkg);
final int callingUid = Binder.getCallingUid();
if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
throw new IllegalArgumentException("Cannot delete default channel");
}
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
mRankingHelper.deleteNotificationChannel(pkg, Binder.getCallingUid(), channelId);
UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
mListeners.notifyNotificationChannelChanged(pkg,
mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
savePolicyFile();
}
@@ -1692,16 +1722,28 @@ public class NotificationManagerService extends SystemService {
}
@Override
public void deleteNotificationChannelGroup(String pkg, String channelGroupId) {
public void deleteNotificationChannelGroup(String pkg, String groupId) {
checkCallerIsSystemOrSameApp(pkg);
List<String> deletedChannelIds = mRankingHelper.deleteNotificationChannelGroup(
pkg, Binder.getCallingUid(), channelGroupId);
for (int i = 0; i < deletedChannelIds.size(); i++) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannelIds.get(i), 0, 0, true,
UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
final int callingUid = Binder.getCallingUid();
NotificationChannelGroup groupToDelete =
mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
if (groupToDelete != null) {
List<NotificationChannel> deletedChannels =
mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
for (int i = 0; i < deletedChannels.size(); i++) {
final NotificationChannel deletedChannel = deletedChannels.get(i);
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
true,
UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
null);
mListeners.notifyNotificationChannelChanged(pkg, deletedChannel,
NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
}
mListeners.notifyNotificationChannelGroupChanged(
pkg, groupToDelete, NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
savePolicyFile();
}
savePolicyFile();
}
@Override
@@ -1709,7 +1751,7 @@ public class NotificationManagerService extends SystemService {
NotificationChannel channel) {
enforceSystemOrSystemUI("Caller not system or systemui");
Preconditions.checkNotNull(channel);
updateNotificationChannelInt(pkg, uid, channel);
updateNotificationChannelInt(pkg, uid, channel, false);
}
@Override
@@ -2646,6 +2688,41 @@ public class NotificationManagerService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
String pkg, NotificationChannel channel) throws RemoteException {
Preconditions.checkNotNull(channel);
ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
checkHasCompanionDevice(info);
int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
updateNotificationChannelInt(pkg, uid, channel, true);
}
@Override
public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
INotificationListener token, String pkg) throws RemoteException {
ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
checkHasCompanionDevice(info);
int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */);
}
@Override
public ParceledListSlice<NotificationChannelGroup>
getNotificationChannelGroupsFromPrivilegedListener(
INotificationListener token, String pkg) throws RemoteException {
ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
checkHasCompanionDevice(info);
List<NotificationChannelGroup> groups = new ArrayList<>();
int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
groups.addAll(mRankingHelper.getNotificationChannelGroups(pkg, uid));
return new ParceledListSlice<>(groups);
}
};
private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
@@ -4445,11 +4522,11 @@ public class NotificationManagerService extends SystemService {
return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
}
private boolean isCallerSystem() {
protected boolean isCallerSystem() {
return isUidSystem(Binder.getCallingUid());
}
protected void checkCallerIsSystem() {
private void checkCallerIsSystem() {
if (isCallerSystem()) {
return;
}
@@ -4578,6 +4655,17 @@ public class NotificationManagerService extends SystemService {
channels, overridePeople, snoozeCriteria, showBadge);
}
private void checkHasCompanionDevice(ManagedServiceInfo info) throws RemoteException {
if (mCompanionManager == null) {
mCompanionManager = ICompanionDeviceManager.Stub.asInterface(
ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
}
if (ArrayUtils.isEmpty(mCompanionManager.getAssociations(
info.component.getPackageName(), info.userid))) {
throw new SecurityException("Disallowed call from " + info.component);
}
}
private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
if (!listener.enabledAndUserMatches(sbn.getUserId())) {
return false;
@@ -4664,7 +4752,6 @@ public class NotificationManagerService extends SystemService {
final StatusBarNotification sbn = r.sbn;
TrimCache trimCache = new TrimCache(sbn);
// mServices is the list inside ManagedServices of all the assistants,
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
for (final ManagedServiceInfo info : NotificationAssistants.this.mServices) {
@@ -4903,6 +4990,58 @@ public class NotificationManagerService extends SystemService {
}
}
protected void notifyNotificationChannelChanged(final String pkg,
final NotificationChannel channel, final int modificationType) {
if (channel == null) {
return;
}
for (final ManagedServiceInfo serviceInfo : getServices()) {
if (!serviceInfo.isEnabledForCurrentProfiles()) {
continue;
}
try {
checkHasCompanionDevice(serviceInfo);
mHandler.post(new Runnable() {
@Override
public void run() {
notifyNotificationChannelChanged(serviceInfo, pkg, channel,
modificationType);
}
});
} catch (SecurityException se) {
// Not a privileged listener; do not notify
} catch (RemoteException e) {
Slog.e(TAG, "Cannot reach companion device service", e);
}
}
}
protected void notifyNotificationChannelGroupChanged(final String pkg,
final NotificationChannelGroup group, final int modificationType) {
if (group == null) {
return;
}
for (final ManagedServiceInfo serviceInfo : getServices()) {
if (!serviceInfo.isEnabledForCurrentProfiles()) {
continue;
}
try {
checkHasCompanionDevice(serviceInfo);
mHandler.post(new Runnable() {
@Override
public void run() {
notifyNotificationChannelGroupChanged(serviceInfo, pkg, group,
modificationType);
}
});
} catch (SecurityException se) {
// Not a privileged listener; do not notify
} catch (RemoteException e) {
Slog.e(TAG, "Cannot reach companion device service", e);
}
}
}
private void notifyPosted(final ManagedServiceInfo info,
final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
final INotificationListener listener = (INotificationListener) info.service;
@@ -4957,6 +5096,28 @@ public class NotificationManagerService extends SystemService {
}
}
void notifyNotificationChannelChanged(ManagedServiceInfo info,
final String pkg, final NotificationChannel channel,
final int modificationType) {
final INotificationListener listener = (INotificationListener) info.service;
try {
listener.onNotificationChannelModification(pkg, channel, modificationType);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
}
}
private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
final String pkg, final NotificationChannelGroup group,
final int modificationType) {
final INotificationListener listener = (INotificationListener) info.service;
try {
listener.onNotificationChannelGroupModification(pkg, group, modificationType);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
}
}
public boolean isListenerPackage(String packageName) {
if (packageName == null) {
return false;

View File

@@ -715,12 +715,12 @@ public class RankingHelper implements RankingConfig {
return new ParceledListSlice<>(new ArrayList<>(groups.values()));
}
public List<String> deleteNotificationChannelGroup(String pkg, int uid,
public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid,
String groupId) {
List<String> deletedChannelIds = new ArrayList<>();
List<NotificationChannel> deletedChannels = new ArrayList<>();
Record r = getRecord(pkg, uid);
if (r == null || TextUtils.isEmpty(groupId)) {
return deletedChannelIds;
return deletedChannels;
}
r.groups.remove(groupId);
@@ -730,11 +730,11 @@ public class RankingHelper implements RankingConfig {
final NotificationChannel nc = r.channels.valueAt(i);
if (groupId.equals(nc.getGroup())) {
nc.setDeleted(true);
deletedChannelIds.add(nc.getId());
deletedChannels.add(nc);
}
}
updateConfig();
return deletedChannelIds;
return deletedChannels;
}
@Override

View File

@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<application>
<uses-library android:name="android.test.runner" />

View File

@@ -16,6 +16,8 @@
package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -26,6 +28,8 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,25 +37,29 @@ import static org.mockito.Mockito.when;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.companion.ICompanionDeviceManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.graphics.Color;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.MessageQueue;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.test.annotation.UiThreadTest;
import android.support.test.InstrumentationRegistry;
import android.testing.TestableLooper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -74,17 +82,24 @@ public class NotificationManagerServiceTest {
private final RankingHelper mRankingHelper = mock(RankingHelper.class);
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
private NotificationManagerService.NotificationListeners mNotificationListeners =
mock(NotificationManagerService.NotificationListeners.class);
private ManagedServices.ManagedServiceInfo mListener =
mNotificationListeners.new ManagedServiceInfo(
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
private ICompanionDeviceManager mCompanionMgr = mock(ICompanionDeviceManager.class);
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
public TestableNotificationManagerService(Context context) { super(context); }
@Override
protected void checkCallerIsSystem() {}
protected boolean isCallerSystem() {
return true;
}
}
@Before
@Test
@UiThreadTest
public void setUp() throws Exception {
mNotificationManagerService = new TestableNotificationManagerService(mContext);
@@ -92,7 +107,7 @@ public class NotificationManagerServiceTest {
// MockPackageManager - default returns ApplicationInfo with matching calling UID
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = uid;
when(mPackageManager.getApplicationInfo(any(), anyInt(), anyInt()))
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
.thenReturn(applicationInfo);
@@ -100,15 +115,10 @@ public class NotificationManagerServiceTest {
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
// Use this testable looper.
mTestableLooper = new TestableLooper(false);
// Mock NotificationListeners to bypass security checks.
final NotificationManagerService.NotificationListeners mockNotificationListeners =
mock(NotificationManagerService.NotificationListeners.class);
when(mockNotificationListeners.checkServiceTokenLocked(any())).thenReturn(
mockNotificationListeners.new ManagedServiceInfo(null,
new ComponentName(PKG, "test_class"), uid, true, null, 0));
when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
mPackageManagerClient, mockLightsManager, mockNotificationListeners);
mPackageManagerClient, mockLightsManager, mNotificationListeners, mCompanionMgr);
// Tests call directly into the Binder.
mBinderService = mNotificationManagerService.getBinderService();
@@ -419,4 +429,206 @@ public class NotificationManagerServiceTest {
verify(mRankingHelper, times(1)).getNotificationChannel(
anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean());
}
@Test
@UiThreadTest
public void testCreateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mNotificationManagerService.setRankingHelper(mRankingHelper);
when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW);
when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(channel2.getId()), anyBoolean()))
.thenReturn(channel2);
reset(mNotificationListeners);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2)));
verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
eq(channel2),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
}
@Test
@UiThreadTest
public void testCreateChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mNotificationManagerService.setRankingHelper(mRankingHelper);
NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
reset(mNotificationListeners);
mBinderService.createNotificationChannelGroups(PKG,
new ParceledListSlice(Arrays.asList(group1, group2)));
verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG),
eq(group1),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG),
eq(group2),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
}
@Test
@UiThreadTest
public void testUpdateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mNotificationManagerService.setRankingHelper(mRankingHelper);
mTestNotificationChannel.setLightColor(Color.CYAN);
when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
reset(mNotificationListeners);
mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel);
verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
}
@Test
@UiThreadTest
public void testDeleteChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mNotificationManagerService.setRankingHelper(mRankingHelper);
when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
reset(mNotificationListeners);
mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId());
verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
}
@Test
@UiThreadTest
public void testDeleteChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
mNotificationManagerService.setRankingHelper(mRankingHelper);
when(mRankingHelper.getNotificationChannelGroup(eq(ncg.getId()), eq(PKG), anyInt()))
.thenReturn(ncg);
reset(mNotificationListeners);
mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId());
verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG),
eq(ncg),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
}
@Test
@UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mBinderService.updateNotificationChannelFromPrivilegedListener(
null, PKG, mTestNotificationChannel);
verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any());
verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG),
eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
}
@Test
@UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
try {
mBinderService.updateNotificationChannelFromPrivilegedListener(
null, PKG, mTestNotificationChannel);
fail("listeners that don't have a companion device shouldn't be able to call this");
} catch (SecurityException e) {
// pass
}
verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG),
eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
}
@Test
@UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG);
verify(mRankingHelper, times(1)).getNotificationChannels(
anyString(), anyInt(), anyBoolean());
}
@Test
@UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
try {
mBinderService.getNotificationChannelsFromPrivilegedListener(null, PKG);
fail("listeners that don't have a companion device shouldn't be able to call this");
} catch (SecurityException e) {
// pass
}
verify(mRankingHelper, never()).getNotificationChannels(
anyString(), anyInt(), anyBoolean());
}
@Test
@UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
associations.add("a");
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG);
verify(mRankingHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt());
}
@Test
@UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
try {
mBinderService.getNotificationChannelGroupsFromPrivilegedListener(null, PKG);
fail("listeners that don't have a companion device shouldn't be able to call this");
} catch (SecurityException e) {
// pass
}
verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
}
}