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:
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -22,6 +22,7 @@ android_test {
|
||||
"platform-test-annotations",
|
||||
"hamcrest-library",
|
||||
"testables",
|
||||
"truth-prebuilt",
|
||||
],
|
||||
|
||||
libs: [
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user