Configurable NAS by using DeviceConfig

The latest plan is only system apps with a certain privilege permission
could become NAS. And DeviceConfig could specify any of these valid
candidate to be the default NAS.

So the logic would be like this:
1. If user has set the NAS manually, NMS will persist the user_set bit
   and never mess with it.
2. If it is not the case, NMS will try the NAS defined in DeviceConfig,
   and then the one defined in config.xml

Also added some new shell commands for easy debugging.

Test: atest NotificationAssistantTest.java
Test: atest NotificationManagerServiceTest.java
Test: Use "device_config put" command to set a valid one. Observe that
      NAS is updated and persisted across reboot.
Test: Repeat the command with an invalid one, observe that NAS is not
      updated.
Test: Go to settings, set a NAS, and repeat the device_config command,
      observe that NAS is not changed.
Test: Go to settings, set NAS to be none. Reboot the device, and "none"
      is persisted.

FIXES: 123566150

Change-Id: Ibf8e498944afd5d1fa8659a856a8abdcce41f092
This commit is contained in:
Tony Mak
2019-03-04 16:04:42 +00:00
parent 084e471703
commit 9a3c1f1dfe
9 changed files with 311 additions and 69 deletions

View File

@@ -81,6 +81,12 @@ public final class SystemUiDeviceConfigFlags {
*/
public static final String SSIN_MAX_NUM_ACTIONS = "ssin_max_num_actions";
/**
* The default component of
* {@link android.service.notification.NotificationAssistantService}.
*/
public static final String NAS_DEFAULT_SERVICE = "nas_default_service";
// Flags related to media notifications
/**

View File

@@ -3698,8 +3698,8 @@
<string translatable="false" name="config_batterySaverDeviceSpecificConfig"></string>
<!-- Package name that should be granted Notification Assistant access -->
<string name="config_defaultAssistantAccessPackage" translatable="false">android.ext.services</string>
<!-- Component name that should be granted Notification Assistant access -->
<string name="config_defaultAssistantAccessComponent" translatable="false">android.ext.services/android.ext.services.notification.Assistant</string>
<bool name="config_supportBluetoothPersistedState">true</bool>

View File

@@ -3532,7 +3532,7 @@
<java-symbol type="string" name="harmful_app_warning_title" />
<java-symbol type="layout" name="harmful_app_warning_dialog" />
<java-symbol type="string" name="config_defaultAssistantAccessPackage" />
<java-symbol type="string" name="config_defaultAssistantAccessComponent" />
<java-symbol type="bool" name="config_supportBluetoothPersistedState" />

View File

@@ -333,6 +333,7 @@ abstract public class ManagedServices {
out.attribute(null, ATT_APPROVED_LIST, allowedItems);
out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
writeExtraAttributes(out, approvedUserId);
out.endTag(null, TAG_MANAGED_SERVICES);
if (!forBackup && isPrimary) {
@@ -345,10 +346,14 @@ abstract public class ManagedServices {
}
}
}
out.endTag(null, getConfig().xmlTag);
}
/**
* Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
*/
protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
protected void migrateToXml() {
loadAllowedComponentsFromSettings();
}
@@ -377,7 +382,7 @@ abstract public class ManagedServices {
? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
final boolean isPrimary =
XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
readExtraAttributes(tag, parser, resolvedUserId);
if (allowedManagedServicePackages == null ||
allowedManagedServicePackages.test(getPackageName(approved))) {
if (mUm.getUserInfo(resolvedUserId) != null) {
@@ -391,6 +396,12 @@ abstract public class ManagedServices {
rebindServices(false, USER_ALL);
}
/**
* Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
*/
protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
throws IOException {}
private void loadAllowedComponentsFromSettings() {
for (UserInfo user : mUm.getUsers()) {
final ContentResolver cr = mContext.getContentResolver();

View File

@@ -153,6 +153,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.Condition;
@@ -190,6 +191,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -515,26 +517,32 @@ public class NotificationManagerService extends SystemService {
}
}
readDefaultAssistant(userId);
setDefaultAssistantForUser(userId);
}
protected void readDefaultAssistant(int userId) {
String defaultAssistantAccess = getContext().getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessPackage);
if (defaultAssistantAccess != null) {
// Gather all notification assistant components for candidate pkg. There should
// only be one
Set<ComponentName> approvedAssistants =
mAssistants.queryPackageForServices(defaultAssistantAccess,
MATCH_DIRECT_BOOT_AWARE
| MATCH_DIRECT_BOOT_UNAWARE, userId);
for (ComponentName cn : approvedAssistants) {
try {
getBinderService().setNotificationAssistantAccessGrantedForUser(
cn, userId, true);
} catch (RemoteException e) {
e.printStackTrace();
}
protected void setDefaultAssistantForUser(int userId) {
List<ComponentName> validAssistants = new ArrayList<>(
mAssistants.queryPackageForServices(
null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId));
List<String> candidateStrs = new ArrayList<>();
candidateStrs.add(DeviceConfig.getProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE));
candidateStrs.add(getContext().getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent));
for (String candidateStr : candidateStrs) {
if (TextUtils.isEmpty(candidateStr)) {
continue;
}
ComponentName candidate = ComponentName.unflattenFromString(candidateStr);
if (candidate != null && validAssistants.contains(candidate)) {
setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true);
Slog.d(TAG, String.format("Set default NAS to be %s in %d", candidateStr, userId));
return;
} else {
Slog.w(TAG, "Invalid default NAS config is found: " + candidateStr);
}
}
}
@@ -594,6 +602,8 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.migrateToXml();
handleSavePolicyFile();
}
mAssistants.resetDefaultAssistantsIfNecessary();
}
private void loadPolicyFile() {
@@ -1740,6 +1750,21 @@ public class NotificationManagerService extends SystemService {
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
private void registerDeviceConfigChange() {
DeviceConfig.addOnPropertyChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI,
getContext().getMainExecutor(),
(namespace, name, value) -> {
if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(namespace)) {
return;
}
if (SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE.equals(name)) {
mAssistants.resetDefaultAssistantsIfNecessary();
}
});
}
private GroupHelper getGroupHelper() {
mAutoGroupAtCount =
getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
@@ -1803,6 +1828,7 @@ public class NotificationManagerService extends SystemService {
mListeners.onBootPhaseAppsCanStart();
mAssistants.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
registerDeviceConfigChange();
}
}
@@ -3733,14 +3759,14 @@ public class NotificationManagerService extends SystemService {
@Override
public void setNotificationAssistantAccessGranted(ComponentName assistant,
boolean granted) throws RemoteException {
boolean granted) {
setNotificationAssistantAccessGrantedForUser(
assistant, getCallingUserHandle().getIdentifier(), granted);
}
@Override
public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
boolean granted) throws RemoteException {
boolean granted) {
Preconditions.checkNotNull(listener);
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
@@ -3766,32 +3792,12 @@ public class NotificationManagerService extends SystemService {
@Override
public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
int userId, boolean granted) throws RemoteException {
int userId, boolean granted) {
checkCallerIsSystemOrShell();
if (assistant == null) {
ComponentName allowedAssistant = CollectionUtils.firstOrNull(
mAssistants.getAllowedComponents(userId));
if (allowedAssistant != null) {
setNotificationAssistantAccessGrantedForUser(allowedAssistant, userId, false);
}
return;
}
mAssistants.setUserSet(userId, true);
final long identity = Binder.clearCallingIdentity();
try {
if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, true, granted);
getContext().sendBroadcastAsUser(new Intent(
NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
.setPackage(assistant.getPackageName())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
handleSavePolicyFile();
}
setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4004,6 +4010,34 @@ public class NotificationManagerService extends SystemService {
}
};
@VisibleForTesting
protected void setNotificationAssistantAccessGrantedForUserInternal(
ComponentName assistant, int userId, boolean granted) {
if (assistant == null) {
ComponentName allowedAssistant = CollectionUtils.firstOrNull(
mAssistants.getAllowedComponents(userId));
if (allowedAssistant != null) {
setNotificationAssistantAccessGrantedForUserInternal(
allowedAssistant, userId, false);
}
return;
}
if (mAllowedManagedServicePackages.test(assistant.getPackageName())) {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, true, granted);
getContext().sendBroadcastAsUser(new Intent(
NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
.setPackage(assistant.getPackageName())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
handleSavePolicyFile();
}
}
private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
if (r == null) {
return;
@@ -7091,6 +7125,13 @@ public class NotificationManagerService extends SystemService {
public class NotificationAssistants extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
private static final String ATT_USER_SET = "user_set";
private final Object mLock = new Object();
@GuardedBy("mLock")
private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
public NotificationAssistants(Context context, Object lock, UserProfiles up,
IPackageManager pm) {
super(context, lock, up, pm);
@@ -7157,6 +7198,30 @@ public class NotificationManagerService extends SystemService {
}
}
boolean hasUserSet(int userId) {
synchronized (mLock) {
return mUserSetMap.getOrDefault(userId, false);
}
}
void setUserSet(int userId, boolean set) {
synchronized (mLock) {
mUserSetMap.put(userId, set);
}
}
@Override
protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {
out.attribute(null, ATT_USER_SET, Boolean.toString(hasUserSet(userId)));
}
@Override
protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
throws IOException {
boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false);
setUserSet(userId, userSet);
}
private void notifySeen(final ManagedServiceInfo info,
final ArrayList<String> keys) {
final INotificationListener assistant = (INotificationListener) info.service;
@@ -7314,13 +7379,13 @@ public class NotificationManagerService extends SystemService {
return !getServices().isEmpty();
}
protected void ensureAssistant() {
protected void resetDefaultAssistantsIfNecessary() {
final List<UserInfo> activeUsers = mUm.getUsers(true);
for (UserInfo userInfo : activeUsers) {
int userId = userInfo.getUserHandle().getIdentifier();
if (getAllowedPackages(userId).isEmpty()) {
if (!hasUserSet(userId)) {
Slog.d(TAG, "Approving default notification assistant for user " + userId);
readDefaultAssistant(userId);
setDefaultAssistantForUser(userId);
}
}
}
@@ -7334,16 +7399,24 @@ public class NotificationManagerService extends SystemService {
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();
}
setNotificationAssistantAccessGrantedForUserInternal(
currentComponent, userId, false);
}
}
super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
}
@Override
public void dump(PrintWriter pw, DumpFilter filter) {
super.dump(pw, filter);
pw.println(" Has user set:");
synchronized (mLock) {
Set<Integer> userIds = mUserSetMap.keySet();
for (int userId : userIds) {
pw.println(" userId=" + userId + " value=" + mUserSetMap.get(userId));
}
}
}
}
public class NotificationListeners extends ManagedServices {
@@ -7895,6 +7968,19 @@ public class NotificationManagerService extends SystemService {
}
}
@VisibleForTesting
void resetAssistantUserSet(int userId) {
mAssistants.setUserSet(userId, false);
handleSavePolicyFile();
}
@VisibleForTesting
@Nullable
ComponentName getApprovedAssistant(int userId) {
List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
return CollectionUtils.firstOrNull(allowedComponents);
}
@VisibleForTesting
protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
// only use for testing: mimic receive broadcast that package is (un)suspended

View File

@@ -58,6 +58,8 @@ public class NotificationShellCmd extends ShellCommand {
+ " disallow_dnd PACKAGE [user_id (current user if not specified)]\n"
+ " suspend_package PACKAGE\n"
+ " unsuspend_package PACKAGE\n"
+ " reset_assistant_user_set [user_id (current user if not specified)]\n"
+ " get_approved_assistant [user_id (current user if not specified)]\n"
+ " post [--help | flags] TAG TEXT";
private static final String NOTIFY_USAGE =
@@ -199,8 +201,29 @@ public class NotificationShellCmd extends ShellCommand {
mDirectService.simulatePackageDistractionBroadcast(
Integer.parseInt(getNextArgRequired()),
getNextArgRequired().split(","));
break;
}
case "reset_assistant_user_set": {
int userId = ActivityManager.getCurrentUser();
if (peekNextArg() != null) {
userId = Integer.parseInt(getNextArgRequired());
}
mDirectService.resetAssistantUserSet(userId);
break;
}
case "get_approved_assistant": {
int userId = ActivityManager.getCurrentUser();
if (peekNextArg() != null) {
userId = Integer.parseInt(getNextArgRequired());
}
ComponentName approvedAssistant = mDirectService.getApprovedAssistant(userId);
if (approvedAssistant == null) {
pw.println("null");
} else {
pw.println(approvedAssistant.flattenToString());
}
break;
}
break;
case "post":
case "notify":
doNotify(pw);

View File

@@ -22,6 +22,7 @@ android_test {
"platform-test-annotations",
"hamcrest-library",
"testables",
"truth-prebuilt",
],
libs: [

View File

@@ -114,10 +114,10 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
@Test
public void testXmlUpgrade() {
mAssistants.ensureAssistant();
mAssistants.resetDefaultAssistantsIfNecessary();
//once per user
verify(mNm, times(mUm.getUsers().size())).readDefaultAssistant(anyInt());
verify(mNm, times(mUm.getUsers().size())).setDefaultAssistantForUser(anyInt());
}
@Test
@@ -132,7 +132,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
parser.nextTag();
mAssistants.readXml(parser, null, false, UserHandle.USER_ALL);
verify(mNm, never()).readDefaultAssistant(anyInt());
verify(mNm, never()).setDefaultAssistantForUser(anyInt());
verify(mAssistants, times(1)).addApprovedList(
new ComponentName("b", "b").flattenToString(),10, true);
}
@@ -143,13 +143,13 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
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());
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
any(ComponentName.class), eq(mZero.id), anyBoolean());
mAssistants.setPackageOrComponentEnabled(component2.flattenToString(), mZero.id, true,
true);
verify(mINm, times(1)).setNotificationAssistantAccessGrantedForUser(component1, mZero.id,
false);
verify(mNm, times(1)).setNotificationAssistantAccessGrantedForUserInternal(
component1, mZero.id, false);
}
@Test
@@ -159,7 +159,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase {
true);
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
true);
verify(mINm, never()).setNotificationAssistantAccessGrantedForUser(any(ComponentName.class),
eq(mZero.id), anyBoolean());
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
any(ComponentName.class), eq(mZero.id), anyBoolean());
}
}

View File

@@ -98,7 +98,9 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
@@ -111,9 +113,13 @@ import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.text.Html;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import androidx.annotation.Nullable;
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -142,6 +148,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -153,6 +160,13 @@ import java.util.function.Consumer;
@RunWithLooper
public class NotificationManagerServiceTest extends UiServiceTestCase {
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
private static final String CLEAR_DEVICE_CONFIG_KEY_CMD =
"device_config delete " + DeviceConfig.NAMESPACE_SYSTEMUI + " "
+ SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE;
private static final String SET_DEFAULT_ASSISTANT_DEVICE_CONFIG_CMD =
"device_config put " + DeviceConfig.NAMESPACE_SYSTEMUI + " "
+ SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE;
private final int mUid = Binder.getCallingUid();
private TestableNotificationManagerService mService;
private INotificationManager mBinderService;
@@ -208,6 +222,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
AppOpsManager mAppOpsManager;
@Mock
private UserManagerService mUserMangerService;
@Mock
private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
mNotificationAssistantAccessGrantedCallback;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -215,6 +232,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
boolean isSystemUid = true;
int countLogSmartSuggestionsVisible = 0;
UserManagerService mUserManagerService;
@Nullable
NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
TestableNotificationManagerService(Context context, UserManagerService userManagerService) {
super(context);
@@ -258,6 +277,26 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
UserManagerService getUserManagerService() {
return mUserManagerService;
}
@Override
protected void setNotificationAssistantAccessGrantedForUserInternal(
ComponentName assistant, int userId, boolean granted) {
if (mNotificationAssistantAccessGrantedCallback != null) {
mNotificationAssistantAccessGrantedCallback.onGranted(assistant, userId, granted);
return;
}
super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
}
private void setNotificationAssistantAccessGrantedCallback(
@Nullable NotificationAssistantAccessGrantedCallback callback) {
this.mNotificationAssistantAccessGrantedCallback = callback;
}
interface NotificationAssistantAccessGrantedCallback {
void onGranted(ComponentName assistant, int userId, boolean granted);
}
}
private class TestableToastCallback extends ITransientNotification.Stub {
@@ -352,6 +391,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@After
public void tearDown() throws Exception {
mFile.delete();
clearDeviceConfig();
}
public void waitForIdle() {
@@ -2029,6 +2069,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), true, true);
verify(mAssistants).setUserSet(10, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -2518,7 +2559,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mListeners, times(1)).migrateToXml();
verify(mConditionProviders, times(1)).migrateToXml();
verify(mAssistants, times(1)).migrateToXml();
verify(mAssistants, never()).ensureAssistant();
verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
}
@Test
@@ -2538,7 +2579,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mListeners, times(2)).migrateToXml();
verify(mConditionProviders, times(2)).migrateToXml();
verify(mAssistants, times(2)).migrateToXml();
verify(mAssistants, never()).ensureAssistant();
verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary();
}
@Test
@@ -4101,4 +4142,78 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture());
assertNotNull(captor.getValue());
}
@Test
public void setDefaultAssistantForUser_fromConfigXml() {
clearDeviceConfig();
ComponentName xmlConfig = new ComponentName("config", "xml");
when(mResources
.getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(xmlConfig.flattenToString());
when(mContext.getResources()).thenReturn(mResources);
when(mAssistants.queryPackageForServices(eq(null), anyInt(), eq(0)))
.thenReturn(Collections.singleton(xmlConfig));
mService.setNotificationAssistantAccessGrantedCallback(
mNotificationAssistantAccessGrantedCallback);
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
.onGranted(eq(xmlConfig), eq(0), eq(true));
}
@Test
public void setDefaultAssistantForUser_fromDeviceConfig() {
ComponentName xmlConfig = new ComponentName("xml", "config");
ComponentName deviceConfig = new ComponentName("device", "config");
setDefaultAssistantInDeviceConfig(deviceConfig.flattenToString());
when(mResources
.getString(com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(xmlConfig.flattenToString());
when(mContext.getResources()).thenReturn(mResources);
when(mAssistants.queryPackageForServices(eq(null), anyInt(), eq(0)))
.thenReturn(new ArraySet<>(Arrays.asList(xmlConfig, deviceConfig)));
mService.setNotificationAssistantAccessGrantedCallback(
mNotificationAssistantAccessGrantedCallback);
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
.onGranted(eq(deviceConfig), eq(0), eq(true));
}
@Test
public void setDefaultAssistantForUser_deviceConfigInvalid() {
ComponentName xmlConfig = new ComponentName("xml", "config");
ComponentName deviceConfig = new ComponentName("device", "config");
setDefaultAssistantInDeviceConfig(deviceConfig.flattenToString());
when(mResources
.getString(com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(xmlConfig.flattenToString());
when(mContext.getResources()).thenReturn(mResources);
// Only xmlConfig is valid, deviceConfig is not.
when(mAssistants.queryPackageForServices(eq(null), anyInt(), eq(0)))
.thenReturn(Collections.singleton(xmlConfig));
mService.setNotificationAssistantAccessGrantedCallback(
mNotificationAssistantAccessGrantedCallback);
mService.setDefaultAssistantForUser(0);
verify(mNotificationAssistantAccessGrantedCallback)
.onGranted(eq(xmlConfig), eq(0), eq(true));
}
private void clearDeviceConfig() {
DeviceConfig.resetToDefaults(
Settings.RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_SYSTEMUI);
}
private void setDefaultAssistantInDeviceConfig(String componentName) {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE,
componentName,
false);
}
}