diff options
10 files changed, 177 insertions, 25 deletions
diff --git a/api/current.txt b/api/current.txt index 0288686e4f34..b96f12207a66 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35171,8 +35171,12 @@ package android.service.notification { ctor public NotificationAssistantService(); method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public void createNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public void deleteNotificationChannel(java.lang.String, java.lang.String); + method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); method public final android.os.IBinder onBind(android.content.Intent); method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } diff --git a/api/system-current.txt b/api/system-current.txt index c4b5987e6084..f0742ca60b0d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -38008,8 +38008,12 @@ package android.service.notification { ctor public NotificationAssistantService(); method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public void createNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public void deleteNotificationChannel(java.lang.String, java.lang.String); + method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); method public final android.os.IBinder onBind(android.content.Intent); method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } diff --git a/api/test-current.txt b/api/test-current.txt index 7ff911981ca5..ce08adfee715 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -35268,8 +35268,12 @@ package android.service.notification { ctor public NotificationAssistantService(); method public final void adjustNotification(android.service.notification.Adjustment); method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>); + method public void createNotificationChannel(java.lang.String, android.app.NotificationChannel); + method public void deleteNotificationChannel(java.lang.String, java.lang.String); + method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String); method public final android.os.IBinder onBind(android.content.Intent); method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean); + method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel); field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 927ef6c35b7a..2c4e7a0871b9 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -99,8 +99,12 @@ interface INotificationManager void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim); void setInterruptionFilter(String pkg, int interruptionFilter); - void applyAdjustmentFromAssistantService(in INotificationListener token, in Adjustment adjustment); - void applyAdjustmentsFromAssistantService(in INotificationListener token, in List<Adjustment> adjustments); + void applyAdjustmentFromAssistant(in INotificationListener token, in Adjustment adjustment); + void applyAdjustmentsFromAssistant(in INotificationListener token, in List<Adjustment> adjustments); + void createNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel); + void updateNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel); + void deleteNotificationChannelFromAssistant(in INotificationListener token, String pkg, String channelId); + ParceledListSlice getNotificationChannelsFromAssistant(in INotificationListener token, String pkg); ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 4e00c643d749..51ba8c728fd6 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -16,7 +16,10 @@ package android.service.notification; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; +import android.app.NotificationChannel; import android.content.Context; import android.content.Intent; import android.os.Handler; @@ -27,6 +30,7 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.os.SomeArgs; +import java.util.ArrayList; import java.util.List; /** @@ -79,9 +83,10 @@ public abstract class NotificationAssistantService extends NotificationListenerS public final void adjustNotification(Adjustment adjustment) { if (!isBound()) return; try { - getNotificationInterface().applyAdjustmentFromAssistantService(mWrapper, adjustment); + getNotificationInterface().applyAdjustmentFromAssistant(mWrapper, adjustment); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); + throw ex.rethrowFromSystemServer(); } } @@ -95,12 +100,77 @@ public abstract class NotificationAssistantService extends NotificationListenerS public final void adjustNotifications(List<Adjustment> adjustments) { if (!isBound()) return; try { - getNotificationInterface().applyAdjustmentsFromAssistantService(mWrapper, adjustments); + getNotificationInterface().applyAdjustmentsFromAssistant(mWrapper, adjustments); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); + throw ex.rethrowFromSystemServer(); } } + /** + * Creates a notification channel that notifications can be posted to for a given package. + * + * @param pkg The package to create a channel for. + * @param channel the channel to attempt to create. + */ + public void createNotificationChannel(@NonNull String pkg, + @NonNull NotificationChannel channel) { + if (!isBound()) return; + try { + getNotificationInterface().createNotificationChannelFromAssistant( + mWrapper, pkg, channel); + } catch (RemoteException e) { + Log.v(TAG, "Unable to contact notification manager", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Updates a notification channel for a given package. + * + * @param pkg The package to the channel belongs to. + * @param channel the channel to attempt to update. + */ + public void updateNotificationChannel(@NonNull String pkg, + @NonNull NotificationChannel channel) { + if (!isBound()) return; + try { + getNotificationInterface().updateNotificationChannelFromAssistant( + 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. + */ + public List<NotificationChannel> getNotificationChannels(@NonNull String pkg) { + if (!isBound()) return null; + try { + return getNotificationInterface().getNotificationChannelsFromAssistant( + mWrapper, pkg).getList(); + } catch (RemoteException e) { + Log.v(TAG, "Unable to contact notification manager", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Deletes the given notification channel. + */ + public void deleteNotificationChannel(@NonNull String pkg, @NonNull String channelId) { + if (!isBound()) return; + try { + getNotificationInterface().deleteNotificationChannelFromAssistant( + mWrapper, pkg, channelId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private class NotificationAssistantServiceWrapper extends NotificationListenerWrapper { @Override public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index f58522b52dea..cbd33cdd145f 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1552,9 +1552,6 @@ public class NotificationManagerService extends SystemService { @Override public void createNotificationChannel(String pkg, NotificationChannel channel, IOnNotificationChannelCreatedListener listener) throws RemoteException { - Preconditions.checkNotNull(channel); - Preconditions.checkNotNull(channel.getId()); - Preconditions.checkNotNull(channel.getName()); checkCallerIsSystemOrSameApp(pkg); mRankingHelper.createNotificationChannel(pkg, Binder.getCallingUid(), channel); savePolicyFile(); @@ -1563,7 +1560,6 @@ public class NotificationManagerService extends SystemService { @Override public NotificationChannel getNotificationChannel(String pkg, String channelId) { - Preconditions.checkNotNull(channelId); checkCallerIsSystemOrSameApp(pkg); return mRankingHelper.getNotificationChannel(pkg, Binder.getCallingUid(), channelId); } @@ -1571,14 +1567,12 @@ public class NotificationManagerService extends SystemService { @Override public NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId) { - Preconditions.checkNotNull(channelId); checkCallerIsSystem(); return mRankingHelper.getNotificationChannel(pkg, uid, channelId); } @Override public void deleteNotificationChannel(String pkg, String channelId) { - Preconditions.checkNotNull(channelId); checkCallerIsSystemOrSameApp(pkg); if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { throw new IllegalArgumentException("Cannot delete default channel"); @@ -1592,8 +1586,6 @@ public class NotificationManagerService extends SystemService { @Override public void updateNotificationChannelForPackage(String pkg, int uid, NotificationChannel channel) { - Preconditions.checkNotNull(channel); - Preconditions.checkNotNull(channel.getId()); checkCallerIsSystem(); if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) { // cancel @@ -2383,7 +2375,7 @@ public class NotificationManagerService extends SystemService { } @Override - public void applyAdjustmentFromAssistantService(INotificationListener token, + public void applyAdjustmentFromAssistant(INotificationListener token, Adjustment adjustment) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { @@ -2398,7 +2390,7 @@ public class NotificationManagerService extends SystemService { } @Override - public void applyAdjustmentsFromAssistantService(INotificationListener token, + public void applyAdjustmentsFromAssistant(INotificationListener token, List<Adjustment> adjustments) throws RemoteException { final long identity = Binder.clearCallingIdentity(); @@ -2414,6 +2406,52 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } } + + @Override + public void createNotificationChannelFromAssistant(INotificationListener token, String pkg, + NotificationChannel channel) throws RemoteException { + ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token); + int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); + mRankingHelper.createNotificationChannel(pkg, uid, channel); + savePolicyFile(); + } + + @Override + public void deleteNotificationChannelFromAssistant(INotificationListener token, String pkg, + String channelId) throws RemoteException { + ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token); + if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) { + throw new IllegalArgumentException("Cannot delete default channel"); + } + + int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, + info.userid, REASON_CHANNEL_BANNED, null); + mRankingHelper.deleteNotificationChannel(pkg, uid, channelId); + savePolicyFile(); + } + + @Override + public void updateNotificationChannelFromAssistant(INotificationListener token, String pkg, + NotificationChannel channel) throws RemoteException { + ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token); + if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) { + // cancel + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true, + info.userid, REASON_CHANNEL_BANNED, null); + } + int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); + mRankingHelper.updateNotificationChannelFromAssistant(pkg, uid, channel); + savePolicyFile(); + } + + @Override + public ParceledListSlice<NotificationChannel> getNotificationChannelsFromAssistant( + INotificationListener token, String pkg) throws RemoteException { + ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token); + int uid = mPackageManager.getPackageUid(pkg, 0, info.userid); + return mRankingHelper.getNotificationChannels(pkg, uid); + } }; private void applyAdjustmentLocked(Adjustment adjustment) { diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java index cb5fb0d0c6f0..882e84c4a3b6 100644 --- a/services/core/java/com/android/server/notification/RankingConfig.java +++ b/services/core/java/com/android/server/notification/RankingConfig.java @@ -34,7 +34,7 @@ public interface RankingConfig { void createNotificationChannel(String pkg, int uid, NotificationChannel channel); void updateNotificationChannel(String pkg, int uid, NotificationChannel channel); - void updateNotificationChannelFromRanker(String pkg, int uid, NotificationChannel channel); + void updateNotificationChannelFromAssistant(String pkg, int uid, NotificationChannel channel); NotificationChannel getNotificationChannel(String pkg, int uid, String channelId); NotificationChannel getNotificationChannelWithFallback(String pkg, int uid, String channelId); void deleteNotificationChannel(String pkg, int uid, String channelId); diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 5073b1bf69a8..89101a80ea12 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -18,6 +18,7 @@ package com.android.server.notification; import static android.app.NotificationManager.IMPORTANCE_NONE; import com.android.internal.R; +import com.android.internal.util.Preconditions; import android.app.Notification; import android.app.NotificationChannel; @@ -451,7 +452,14 @@ public class RankingHelper implements RankingConfig { @Override public void createNotificationChannel(String pkg, int uid, NotificationChannel channel) { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(channel); + Preconditions.checkNotNull(channel.getId()); + Preconditions.checkNotNull(channel.getName()); Record r = getOrCreateRecord(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } if (IMPORTANCE_NONE == r.importance) { throw new IllegalArgumentException("Package blocked"); } @@ -472,7 +480,12 @@ public class RankingHelper implements RankingConfig { @Override public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel) { + Preconditions.checkNotNull(updatedChannel); + Preconditions.checkNotNull(updatedChannel.getId()); Record r = getOrCreateRecord(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } NotificationChannel channel = r.channels.get(updatedChannel.getId()); if (channel == null) { throw new IllegalArgumentException("Channel does not exist"); @@ -485,9 +498,12 @@ public class RankingHelper implements RankingConfig { } @Override - public void updateNotificationChannelFromRanker(String pkg, int uid, + public void updateNotificationChannelFromAssistant(String pkg, int uid, NotificationChannel updatedChannel) { Record r = getOrCreateRecord(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } NotificationChannel channel = r.channels.get(updatedChannel.getId()); if (channel == null) { throw new IllegalArgumentException("Channel does not exist"); @@ -538,7 +554,11 @@ public class RankingHelper implements RankingConfig { @Override public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId) { + Preconditions.checkNotNull(pkg); Record r = getOrCreateRecord(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } if (channelId == null) { channelId = NotificationChannel.DEFAULT_CHANNEL_ID; } @@ -547,7 +567,12 @@ public class RankingHelper implements RankingConfig { @Override public void deleteNotificationChannel(String pkg, int uid, String channelId) { + Preconditions.checkNotNull(pkg); + Preconditions.checkNotNull(channelId); Record r = getRecord(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } if (r != null) { r.channels.remove(channelId); } @@ -555,8 +580,12 @@ public class RankingHelper implements RankingConfig { @Override public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid) { + Preconditions.checkNotNull(pkg); List<NotificationChannel> channels = new ArrayList<>(); - Record r = getOrCreateRecord(pkg, uid); + Record r = getRecord(pkg, uid); + if (r == null) { + throw new IllegalArgumentException("Invalid package"); + } int N = r.channels.size(); for (int i = 0; i < N; i++) { channels.add(r.channels.valueAt(i)); diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java index e4a355f632f4..80c4ccee078c 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -57,8 +57,6 @@ public class NotificationManagerServiceTest { when(mockPackageManager.getApplicationInfo(any(), anyInt(), anyInt())) .thenReturn(applicationInfo); mNotificationManagerService.setPackageManager(mockPackageManager); - - mNotificationManagerService.setRankingHelper(mock(RankingHelper.class)); mNotificationManagerService.setHandler(new Handler(context.getMainLooper())); // Tests call directly into the Binder. @@ -69,6 +67,7 @@ public class NotificationManagerServiceTest { public void testCreateNotificationChannel_SuccessCallsListener() throws Exception { final NotificationChannel channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT); + mNotificationManagerService.setRankingHelper(mock(RankingHelper.class)); final CountDownLatch latch = new CountDownLatch(1); mBinderService.createNotificationChannel("test_pkg", channel, new IOnNotificationChannelCreatedListener.Stub() { diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java index 16d0a75e2657..e6afe763bebf 100644 --- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java @@ -375,7 +375,7 @@ public class RankingHelperTest { final NotificationChannel channel2 = new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); - mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); + mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); // no fields should be changed assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId())); @@ -396,7 +396,7 @@ public class RankingHelperTest { new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); - mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); + mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); // no fields should be changed assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId())); @@ -418,7 +418,7 @@ public class RankingHelperTest { channel2.enableVibration(true); channel2.setVibrationPattern(new long[] {100}); - mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); + mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); // no fields should be changed assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId())); @@ -439,7 +439,7 @@ public class RankingHelperTest { new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); channel2.setLights(true); - mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); + mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); // no fields should be changed assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId())); @@ -460,7 +460,7 @@ public class RankingHelperTest { new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); channel2.setBypassDnd(false); - mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); + mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); // no fields should be changed assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId())); @@ -481,7 +481,7 @@ public class RankingHelperTest { new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); channel2.setSound(new Uri.Builder().scheme("test2").build()); - mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2); + mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); // no fields should be changed assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId())); |