Loading api/system-current.txt +7 −0 Original line number Diff line number Diff line Loading @@ -501,6 +501,13 @@ package android.app { method public org.json.JSONObject toJson() throws org.json.JSONException; } public class NotificationManager { method @Nullable public android.content.ComponentName getAllowedNotificationAssistant(); method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(android.os.UserHandle); method public void setNotificationAssistantAccessGranted(android.content.ComponentName, boolean); method public void setNotificationAssistantAccessGrantedForUser(android.content.ComponentName, android.os.UserHandle, boolean); } public final class StatsManager { method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException; method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]); Loading core/java/android/app/INotificationManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -154,6 +154,8 @@ interface INotificationManager void setNotificationAssistantAccessGrantedForUser(in ComponentName assistant, int userId, boolean enabled); List<String> getEnabledNotificationListenerPackages(); List<ComponentName> getEnabledNotificationListeners(int userId); ComponentName getAllowedNotificationAssistantForUser(int userId); ComponentName getAllowedNotificationAssistant(); int getZenMode(); ZenModeConfig getZenModeConfig(); Loading core/java/android/app/NotificationManager.java +75 −0 Original line number Diff line number Diff line Loading @@ -1155,6 +1155,19 @@ public class NotificationManager { } } /** * Checks whether the user has approved a given * {@link android.service.notification.NotificationAssistantService}. * * <p> * The assistant service must belong to the calling app. * * <p> * Apps can request notification assistant access by sending the user to the activity that * matches the system intent action * TODO: STOPSHIP: Add correct intent * {@link android.provider.Settings#ACTION_MANAGE_DEFAULT_APPS_SETTINGS}. */ public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { INotificationManager service = getService(); try { Loading Loading @@ -1266,6 +1279,45 @@ public class NotificationManager { } } /** * Grants/revokes Notification Assistant access to {@code assistant} for current user. * * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to * current assistant * @param granted Grant/revoke access * @hide */ @SystemApi public void setNotificationAssistantAccessGranted(ComponentName assistant, boolean granted) { INotificationManager service = getService(); try { service.setNotificationAssistantAccessGranted(assistant, granted); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Grants/revokes Notification Assistant access to {@code assistant} for given user. * * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to * current assistant * @param user handle to associate assistant with * @param granted Grant/revoke access * @hide */ @SystemApi public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, UserHandle user, boolean granted) { INotificationManager service = getService(); try { service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(), granted); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public List<ComponentName> getEnabledNotificationListeners(int userId) { INotificationManager service = getService(); Loading @@ -1276,6 +1328,29 @@ public class NotificationManager { } } /** @hide */ @SystemApi public @Nullable ComponentName getAllowedNotificationAssistantForUser(UserHandle user) { INotificationManager service = getService(); try { return service.getAllowedNotificationAssistantForUser(user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ @SystemApi public @Nullable ComponentName getAllowedNotificationAssistant() { INotificationManager service = getService(); try { return service.getAllowedNotificationAssistant(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private Context mContext; private static void checkRequired(String name, Object value) { Loading services/core/java/com/android/server/notification/NotificationManagerService.java +45 −1 Original line number Diff line number Diff line Loading @@ -198,6 +198,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; Loading Loading @@ -3654,6 +3655,22 @@ public class NotificationManagerService extends SystemService { return mListeners.getAllowedComponents(userId); } @Override public ComponentName getAllowedNotificationAssistantForUser(int userId) { checkCallerIsSystem(); List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); if (allowedComponents.size() > 1) { throw new IllegalStateException( "At most one NotificationAssistant: " + allowedComponents.size()); } return CollectionUtils.firstOrNull(allowedComponents); } @Override public ComponentName getAllowedNotificationAssistant() { return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier()); } @Override public boolean isNotificationListenerAccessGranted(ComponentName listener) { Preconditions.checkNotNull(listener); Loading Loading @@ -3722,8 +3739,15 @@ public class NotificationManagerService extends SystemService { @Override public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, int userId, boolean granted) throws RemoteException { Preconditions.checkNotNull(assistant); checkCallerIsSystemOrShell(); if (assistant == null) { ComponentName allowedAssistant = CollectionUtils.firstOrNull( mAssistants.getAllowedComponents(userId)); if (allowedAssistant != null) { setNotificationAssistantAccessGrantedForUser(allowedAssistant, userId, false); } return; } final long identity = Binder.clearCallingIdentity(); try { if (mAllowedManagedServicePackages.test(assistant.getPackageName())) { Loading Loading @@ -7264,6 +7288,26 @@ public class NotificationManagerService extends SystemService { } } } @Override protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, boolean isPrimary, boolean enabled) { // Ensures that only one component is enabled at a time if (enabled) { List<ComponentName> allowedComponents = getAllowedComponents(userId); if (!allowedComponents.isEmpty()) { ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents); if (currentComponent.flattenToString().equals(pkgOrComponent)) return; try { getBinderService().setNotificationAssistantAccessGrantedForUser( currentComponent, userId, false); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled); } } public class NotificationListeners extends ManagedServices { Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +30 −5 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.INotificationManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.IPackageManager; Loading @@ -36,22 +37,17 @@ import android.os.UserManager; import android.util.IntArray; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; import com.android.server.UiServiceTestCase; import com.android.server.notification.NotificationManagerService.NotificationAssistants; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; Loading @@ -65,6 +61,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase { private UserManager mUm; @Mock NotificationManagerService mNm; @Mock private INotificationManager mINm; NotificationAssistants mAssistants; Loading @@ -83,6 +81,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { getContext().setMockPackageManager(mPm); getContext().addMockSystemService(Context.USER_SERVICE, mUm); mAssistants = spy(mNm.new NotificationAssistants(getContext(), mLock, mUserProfiles, miPm)); when(mNm.getBinderService()).thenReturn(mINm); List<ResolveInfo> approved = new ArrayList<>(); ResolveInfo resolve = new ResolveInfo(); Loading Loading @@ -136,4 +135,30 @@ public class NotificationAssistantsTest extends UiServiceTestCase { verify(mAssistants, times(1)).addApprovedList( new ComponentName("b", "b").flattenToString(),10, true); } @Test public void testSetPackageOrComponentEnabled_onlyOnePackage() throws Exception { ComponentName component1 = ComponentName.unflattenFromString("package/Component1"); ComponentName component2 = ComponentName.unflattenFromString("package/Component2"); mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true); verify(mINm, never()).setNotificationAssistantAccessGrantedForUser(any(ComponentName.class), eq(mZero.id), anyBoolean()); mAssistants.setPackageOrComponentEnabled(component2.flattenToString(), mZero.id, true, true); verify(mINm, times(1)).setNotificationAssistantAccessGrantedForUser(component1, mZero.id, false); } @Test public void testSetPackageOrComponentEnabled_samePackage() throws Exception { ComponentName component1 = ComponentName.unflattenFromString("package/Component1"); mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true); mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true); verify(mINm, never()).setNotificationAssistantAccessGrantedForUser(any(ComponentName.class), eq(mZero.id), anyBoolean()); } } Loading
api/system-current.txt +7 −0 Original line number Diff line number Diff line Loading @@ -501,6 +501,13 @@ package android.app { method public org.json.JSONObject toJson() throws org.json.JSONException; } public class NotificationManager { method @Nullable public android.content.ComponentName getAllowedNotificationAssistant(); method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(android.os.UserHandle); method public void setNotificationAssistantAccessGranted(android.content.ComponentName, boolean); method public void setNotificationAssistantAccessGrantedForUser(android.content.ComponentName, android.os.UserHandle, boolean); } public final class StatsManager { method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException; method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]); Loading
core/java/android/app/INotificationManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -154,6 +154,8 @@ interface INotificationManager void setNotificationAssistantAccessGrantedForUser(in ComponentName assistant, int userId, boolean enabled); List<String> getEnabledNotificationListenerPackages(); List<ComponentName> getEnabledNotificationListeners(int userId); ComponentName getAllowedNotificationAssistantForUser(int userId); ComponentName getAllowedNotificationAssistant(); int getZenMode(); ZenModeConfig getZenModeConfig(); Loading
core/java/android/app/NotificationManager.java +75 −0 Original line number Diff line number Diff line Loading @@ -1155,6 +1155,19 @@ public class NotificationManager { } } /** * Checks whether the user has approved a given * {@link android.service.notification.NotificationAssistantService}. * * <p> * The assistant service must belong to the calling app. * * <p> * Apps can request notification assistant access by sending the user to the activity that * matches the system intent action * TODO: STOPSHIP: Add correct intent * {@link android.provider.Settings#ACTION_MANAGE_DEFAULT_APPS_SETTINGS}. */ public boolean isNotificationAssistantAccessGranted(ComponentName assistant) { INotificationManager service = getService(); try { Loading Loading @@ -1266,6 +1279,45 @@ public class NotificationManager { } } /** * Grants/revokes Notification Assistant access to {@code assistant} for current user. * * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to * current assistant * @param granted Grant/revoke access * @hide */ @SystemApi public void setNotificationAssistantAccessGranted(ComponentName assistant, boolean granted) { INotificationManager service = getService(); try { service.setNotificationAssistantAccessGranted(assistant, granted); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Grants/revokes Notification Assistant access to {@code assistant} for given user. * * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to * current assistant * @param user handle to associate assistant with * @param granted Grant/revoke access * @hide */ @SystemApi public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, UserHandle user, boolean granted) { INotificationManager service = getService(); try { service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(), granted); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ public List<ComponentName> getEnabledNotificationListeners(int userId) { INotificationManager service = getService(); Loading @@ -1276,6 +1328,29 @@ public class NotificationManager { } } /** @hide */ @SystemApi public @Nullable ComponentName getAllowedNotificationAssistantForUser(UserHandle user) { INotificationManager service = getService(); try { return service.getAllowedNotificationAssistantForUser(user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** @hide */ @SystemApi public @Nullable ComponentName getAllowedNotificationAssistant() { INotificationManager service = getService(); try { return service.getAllowedNotificationAssistant(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private Context mContext; private static void checkRequired(String name, Object value) { Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +45 −1 Original line number Diff line number Diff line Loading @@ -198,6 +198,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; Loading Loading @@ -3654,6 +3655,22 @@ public class NotificationManagerService extends SystemService { return mListeners.getAllowedComponents(userId); } @Override public ComponentName getAllowedNotificationAssistantForUser(int userId) { checkCallerIsSystem(); List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId); if (allowedComponents.size() > 1) { throw new IllegalStateException( "At most one NotificationAssistant: " + allowedComponents.size()); } return CollectionUtils.firstOrNull(allowedComponents); } @Override public ComponentName getAllowedNotificationAssistant() { return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier()); } @Override public boolean isNotificationListenerAccessGranted(ComponentName listener) { Preconditions.checkNotNull(listener); Loading Loading @@ -3722,8 +3739,15 @@ public class NotificationManagerService extends SystemService { @Override public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, int userId, boolean granted) throws RemoteException { Preconditions.checkNotNull(assistant); checkCallerIsSystemOrShell(); if (assistant == null) { ComponentName allowedAssistant = CollectionUtils.firstOrNull( mAssistants.getAllowedComponents(userId)); if (allowedAssistant != null) { setNotificationAssistantAccessGrantedForUser(allowedAssistant, userId, false); } return; } final long identity = Binder.clearCallingIdentity(); try { if (mAllowedManagedServicePackages.test(assistant.getPackageName())) { Loading Loading @@ -7264,6 +7288,26 @@ public class NotificationManagerService extends SystemService { } } } @Override protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, boolean isPrimary, boolean enabled) { // Ensures that only one component is enabled at a time if (enabled) { List<ComponentName> allowedComponents = getAllowedComponents(userId); if (!allowedComponents.isEmpty()) { ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents); if (currentComponent.flattenToString().equals(pkgOrComponent)) return; try { getBinderService().setNotificationAssistantAccessGrantedForUser( currentComponent, userId, false); } catch (RemoteException e) { e.rethrowFromSystemServer(); } } } super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled); } } public class NotificationListeners extends ManagedServices { Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +30 −5 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.INotificationManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.IPackageManager; Loading @@ -36,22 +37,17 @@ import android.os.UserManager; import android.util.IntArray; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; import com.android.server.UiServiceTestCase; import com.android.server.notification.NotificationManagerService.NotificationAssistants; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlSerializer; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; Loading @@ -65,6 +61,8 @@ public class NotificationAssistantsTest extends UiServiceTestCase { private UserManager mUm; @Mock NotificationManagerService mNm; @Mock private INotificationManager mINm; NotificationAssistants mAssistants; Loading @@ -83,6 +81,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { getContext().setMockPackageManager(mPm); getContext().addMockSystemService(Context.USER_SERVICE, mUm); mAssistants = spy(mNm.new NotificationAssistants(getContext(), mLock, mUserProfiles, miPm)); when(mNm.getBinderService()).thenReturn(mINm); List<ResolveInfo> approved = new ArrayList<>(); ResolveInfo resolve = new ResolveInfo(); Loading Loading @@ -136,4 +135,30 @@ public class NotificationAssistantsTest extends UiServiceTestCase { verify(mAssistants, times(1)).addApprovedList( new ComponentName("b", "b").flattenToString(),10, true); } @Test public void testSetPackageOrComponentEnabled_onlyOnePackage() throws Exception { ComponentName component1 = ComponentName.unflattenFromString("package/Component1"); ComponentName component2 = ComponentName.unflattenFromString("package/Component2"); mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true); verify(mINm, never()).setNotificationAssistantAccessGrantedForUser(any(ComponentName.class), eq(mZero.id), anyBoolean()); mAssistants.setPackageOrComponentEnabled(component2.flattenToString(), mZero.id, true, true); verify(mINm, times(1)).setNotificationAssistantAccessGrantedForUser(component1, mZero.id, false); } @Test public void testSetPackageOrComponentEnabled_samePackage() throws Exception { ComponentName component1 = ComponentName.unflattenFromString("package/Component1"); mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true); mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true, true); verify(mINm, never()).setNotificationAssistantAccessGrantedForUser(any(ComponentName.class), eq(mZero.id), anyBoolean()); } }