blob: 054a401d41af4f1adff8600ed6b077a3b9d13dd6 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.notification;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
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;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.testing.TestableContext;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.TypedXmlPullParser;
import android.util.Xml;
import com.android.internal.util.function.TriPredicate;
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.MockitoAnnotations;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class NotificationAssistantsTest extends UiServiceTestCase {
@Mock
private PackageManager mPm;
@Mock
private IPackageManager miPm;
@Mock
private UserManager mUm;
@Mock
NotificationManagerService mNm;
@Mock
private INotificationManager mINm;
NotificationAssistants mAssistants;
@Mock
private ManagedServices.UserProfiles mUserProfiles;
private TestableContext mContext = spy(getContext());
Object mLock = new Object();
UserInfo mZero = new UserInfo(0, "zero", 0);
UserInfo mTen = new UserInfo(10, "ten", 0);
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext.setMockPackageManager(mPm);
mContext.addMockSystemService(Context.USER_SERVICE, mUm);
mAssistants = spy(mNm.new NotificationAssistants(mContext, mLock, mUserProfiles, miPm));
when(mNm.getBinderService()).thenReturn(mINm);
mContext.ensureTestableResources();
List<ResolveInfo> approved = new ArrayList<>();
ResolveInfo resolve = new ResolveInfo();
approved.add(resolve);
ServiceInfo info = new ServiceInfo();
info.packageName = "a";
info.name="a";
resolve.serviceInfo = info;
when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt()))
.thenReturn(approved);
List<UserInfo> users = new ArrayList<>();
users.add(mZero);
users.add(mTen);
users.add(new UserInfo(11, "11", 0));
users.add(new UserInfo(12, "12", 0));
for (UserInfo user : users) {
when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
}
when(mUm.getUsers()).thenReturn(users);
when(mUm.getAliveUsers()).thenReturn(users);
IntArray profileIds = new IntArray();
profileIds.add(0);
profileIds.add(11);
profileIds.add(10);
profileIds.add(12);
when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
when(mNm.isNASMigrationDone(anyInt())).thenReturn(true);
}
@Test
public void testXmlUpgrade() {
mAssistants.resetDefaultAssistantsIfNecessary();
//once per user
verify(mNm, times(mUm.getUsers().size())).setDefaultAssistantForUser(anyInt());
}
@Test
public void testReadXml_userDisabled() throws Exception {
String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">"
+ "<service_listing approved=\"\" user=\"0\" primary=\"true\""
+ "user_changed=\"true\"/>"
+ "</enabled_assistants>";
final TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
TriPredicate<String, Integer, String> allowedManagedServicePackages =
mNm::canUseManagedServices;
parser.nextTag();
mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
ArrayMap<Boolean, ArraySet<String>> approved = mAssistants.mApproved.get(0);
// approved should not be null
assertNotNull(approved);
assertEquals(new ArraySet<>(), approved.get(true));
}
@Test
public void testReadXml_upgradeUserSet() throws Exception {
String xml = "<enabled_assistants version=\"3\" defaults=\"b/b\">"
+ "<service_listing approved=\"\" user=\"0\" primary=\"true\""
+ "user_set_services=\"b/b\"/>"
+ "</enabled_assistants>";
final TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
TriPredicate<String, Integer, String> allowedManagedServicePackages =
mNm::canUseManagedServices;
parser.nextTag();
mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
verify(mAssistants, times(1)).upgradeUserSet();
assertTrue(mAssistants.mIsUserChanged.get(0));
}
@Test
public void testReadXml_multiApproved() throws Exception {
String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">"
+ "<service_listing approved=\"a/a:b/b\" user=\"0\" primary=\"true\""
+ "user_changed=\"true\"/>"
+ "</enabled_assistants>";
final TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
mAssistants.readXml(parser, null, false, UserHandle.USER_ALL);
assertEquals(1, mAssistants.getAllowedComponents(0).size());
assertEquals(new ArrayList(Arrays.asList(new ComponentName("a", "a"))),
mAssistants.getAllowedComponents(0));
}
@Test
public void testXmlUpgradeExistingApprovedComponents() throws Exception {
String xml = "<enabled_assistants version=\"2\" defaults=\"b\\b\">"
+ "<service_listing approved=\"b/b\" user=\"10\" primary=\"true\" />"
+ "</enabled_assistants>";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
mAssistants.readXml(parser, null, false, UserHandle.USER_ALL);
verify(mNm, never()).setDefaultAssistantForUser(anyInt());
verify(mAssistants, times(1)).addApprovedList(
new ComponentName("b", "b").flattenToString(), 10, true, null);
}
@Test
public void testXmlMigratingAllowedAdjustments() throws Exception {
// Old tag, need migration
String xml = "<q_allowed_adjustments types=\"adj_1\"/>";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
mAssistants.readExtraTag("q_allowed_adjustments", parser);
assertTrue(mAssistants.isAdjustmentAllowed("adj_1"));
assertEquals(mNm.DEFAULT_ALLOWED_ADJUSTMENTS.length + 1,
mAssistants.getAllowedAssistantAdjustments().size());
// New TAG
xml = "<s_allowed_adjustments types=\"adj_2\"/>";
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.toString().getBytes())), null);
parser.nextTag();
mAssistants.readExtraTag("s_allowed_adjustments", parser);
assertTrue(mAssistants.isAdjustmentAllowed("adj_2"));
assertEquals(1, mAssistants.getAllowedAssistantAdjustments().size());
}
@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, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
any(ComponentName.class), eq(mZero.id), anyBoolean(), anyBoolean());
mAssistants.setPackageOrComponentEnabled(component2.flattenToString(), mZero.id, true,
true, true);
verify(mNm, times(1)).setNotificationAssistantAccessGrantedForUserInternal(
component1, mZero.id, false, true);
}
@Test
public void testSetPackageOrComponentEnabled_samePackage() throws Exception {
ComponentName component1 = ComponentName.unflattenFromString("package/Component1");
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
true, true);
mAssistants.setPackageOrComponentEnabled(component1.flattenToString(), mZero.id, true,
true, true);
verify(mNm, never()).setNotificationAssistantAccessGrantedForUserInternal(
any(ComponentName.class), eq(mZero.id), anyBoolean(), anyBoolean());
}
@Test
public void testLoadDefaultsFromConfig() {
ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
doReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent, newDefaultComponent)))
.when(mAssistants).queryPackageForServices(any(), anyInt(), anyInt());
// Test loadDefaultsFromConfig() add the config value to mDefaultComponents instead of
// mDefaultFromConfig
when(mContext.getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(oldDefaultComponent.flattenToString());
mAssistants.loadDefaultsFromConfig();
assertEquals(new ArraySet<>(Arrays.asList(oldDefaultComponent)),
mAssistants.getDefaultComponents());
assertNull(mAssistants.mDefaultFromConfig);
// Test loadDefaultFromConfig(false) only updates the mDefaultFromConfig
when(mContext.getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(newDefaultComponent.flattenToString());
mAssistants.loadDefaultsFromConfig(false);
assertEquals(new ArraySet<>(Arrays.asList(oldDefaultComponent)),
mAssistants.getDefaultComponents());
assertEquals(newDefaultComponent, mAssistants.getDefaultFromConfig());
// Test resetDefaultFromConfig updates the mDefaultComponents to new config value
mAssistants.resetDefaultFromConfig();
assertEquals(new ArraySet<>(Arrays.asList(newDefaultComponent)),
mAssistants.getDefaultComponents());
assertEquals(newDefaultComponent, mAssistants.getDefaultFromConfig());
}
@Test
public void testNASSettingUpgrade_userNotSet_differentDefaultNAS() {
ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2");
when(mNm.isNASMigrationDone(anyInt())).thenReturn(false);
doReturn(new ArraySet<>(Arrays.asList(newDefaultComponent)))
.when(mAssistants).queryPackageForServices(any(), anyInt(), anyInt());
when(mContext.getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(newDefaultComponent.flattenToString());
// User hasn't set the default NAS, set the oldNAS as the default with userSet=false here.
mAssistants.setPackageOrComponentEnabled(oldDefaultComponent.flattenToString(),
mZero.id, true, true /*enabled*/, false /*userSet*/);
// The migration for userSet==false happens in resetDefaultAssistantsIfNecessary
mAssistants.resetDefaultAssistantsIfNecessary();
// Verify the migration happened: setDefaultAssistantForUser should be called to
// update defaults
verify(mNm, times(1)).setNASMigrationDone(eq(mZero.id));
verify(mNm, times(1)).setDefaultAssistantForUser(eq(mZero.id));
assertEquals(new ArraySet<>(Arrays.asList(newDefaultComponent)),
mAssistants.getDefaultComponents());
when(mNm.isNASMigrationDone(anyInt())).thenReturn(true);
// Test resetDefaultAssistantsIfNecessary again since it will be called on every reboot
mAssistants.resetDefaultAssistantsIfNecessary();
// The migration should not happen again, the invoke time for migration should not increase
verify(mNm, times(1)).setNASMigrationDone(eq(mZero.id));
// The invoke time outside migration part should increase by 1
verify(mNm, times(2)).setDefaultAssistantForUser(eq(mZero.id));
}
@Test
public void testNASSettingUpgrade_userNotSet_sameDefaultNAS() {
ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1");
when(mNm.isNASMigrationDone(anyInt())).thenReturn(false);
doReturn(new ArraySet<>(Arrays.asList(defaultComponent)))
.when(mAssistants).queryPackageForServices(any(), anyInt(), anyInt());
when(mContext.getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn(defaultComponent.flattenToString());
// User hasn't set the default NAS, set the oldNAS as the default with userSet=false here.
mAssistants.setPackageOrComponentEnabled(defaultComponent.flattenToString(),
mZero.id, true, true /*enabled*/, false /*userSet*/);
// The migration for userSet==false happens in resetDefaultAssistantsIfNecessary
mAssistants.resetDefaultAssistantsIfNecessary();
verify(mNm, times(1)).setNASMigrationDone(eq(mZero.id));
verify(mNm, times(1)).setDefaultAssistantForUser(eq(mZero.id));
assertEquals(new ArraySet<>(Arrays.asList(defaultComponent)),
mAssistants.getDefaultComponents());
}
@Test
public void testNASSettingUpgrade_userNotSet_defaultNASNone() {
ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1");
when(mNm.isNASMigrationDone(anyInt())).thenReturn(false);
doReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent)))
.when(mAssistants).queryPackageForServices(any(), anyInt(), anyInt());
// New default is none
when(mContext.getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent))
.thenReturn("");
// User hasn't set the default NAS, set the oldNAS as the default with userSet=false here.
mAssistants.setPackageOrComponentEnabled(oldDefaultComponent.flattenToString(),
mZero.id, true, true /*enabled*/, false /*userSet*/);
// The migration for userSet==false happens in resetDefaultAssistantsIfNecessary
mAssistants.resetDefaultAssistantsIfNecessary();
verify(mNm, times(1)).setNASMigrationDone(eq(mZero.id));
verify(mNm, times(1)).setDefaultAssistantForUser(eq(mZero.id));
assertEquals(new ArraySet<>(), mAssistants.getDefaultComponents());
}
}