blob: f7c26091a7f416ec90c718901ac5b88e1f681d59 [file] [log] [blame]
/*
* Copyright (C) 2019 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 android.os.UserHandle.MIN_SECONDARY_USER_ID;
import static android.os.UserHandle.USER_SYSTEM;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
import android.content.pm.UserInfo;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.UserManager;
import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.UiServiceTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class NotificationHistoryManagerTest extends UiServiceTestCase {
@Mock
UserManager mUserManager;
@Mock
NotificationHistoryDatabase mDb;
@Mock
Handler mHandler;
List<UserInfo> mUsers;
NotificationHistoryManager mHistoryManager;
private HistoricalNotification getHistoricalNotification(String packageName, int index) {
String expectedChannelName = "channelName" + index;
String expectedChannelId = "channelId" + index;
int expectedUid = 1123456 + index;
int expectedUserId = index;
long expectedPostTime = 987654321 + index;
String expectedTitle = "title" + index;
String expectedText = "text" + index;
Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
index);
return new HistoricalNotification.Builder()
.setPackage(packageName)
.setChannelName(expectedChannelName)
.setChannelId(expectedChannelId)
.setUid(expectedUid)
.setUserId(expectedUserId)
.setPostedTimeMs(expectedPostTime)
.setTitle(expectedTitle)
.setText(expectedText)
.setIcon(expectedIcon)
.build();
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
getContext().addMockSystemService(UserManager.class, mUserManager);
mUsers = new ArrayList<>();
UserInfo userSystem = new UserInfo();
userSystem.id = USER_SYSTEM;
mUsers.add(userSystem);
UserInfo userAll = new UserInfo();
userAll.id = MIN_SECONDARY_USER_ID;
mUsers.add(userAll);
mUsers.add(userAll);
when(mUserManager.getUsers()).thenReturn(mUsers);
for (UserInfo info : mUsers) {
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, info.id);
}
NotificationHistoryDatabaseFactory.setTestingNotificationHistoryDatabase(mDb);
mHistoryManager = new NotificationHistoryManager(getContext(), mHandler);
mHistoryManager.onBootPhaseAppsCanStart();
}
@After
public void tearDown() {
mHistoryManager.onDestroy();
}
@Test
public void testOnUserUnlocked() {
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
mHistoryManager.onUserUnlocked(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isTrue();
verify(mDb, times(1)).init();
}
@Test
public void testOnUserUnlocked_historyDisabled() {
// create a history
mHistoryManager.onUserUnlocked(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
// lock user
mHistoryManager.onUserStopped(USER_SYSTEM);
// turn off history
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
// unlock user, verify that history is disabled
mHistoryManager.onUserUnlocked(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
verify(mDb, times(1)).disableHistory();
}
@Test
public void testOnUserUnlocked_historyDisabledThenEnabled() {
// create a history
mHistoryManager.onUserUnlocked(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
// lock user
mHistoryManager.onUserStopped(USER_SYSTEM);
// turn off history
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
// turn on history
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
// unlock user, verify that history is NOT disabled
mHistoryManager.onUserUnlocked(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
verify(mDb, never()).disableHistory();
}
@Test
public void testOnUserUnlocked_cleansUpRemovedPackages() {
String pkg = "pkg";
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
mHistoryManager.onUserUnlocked(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isTrue();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isTrue();
verify(mDb, times(1)).onPackageRemoved(pkg);
}
@Test
public void testOnUserStopped_userExists() {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.onUserStopped(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
}
@Test
public void testOnUserStopped_userDoesNotExist() {
mHistoryManager.onUserStopped(USER_SYSTEM);
// no crash
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
}
@Test
public void testOnUserRemoved_userExists() {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.onUserRemoved(USER_SYSTEM);
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
}
@Test
public void testOnUserRemoved_userDoesNotExist() {
mHistoryManager.onUserRemoved(USER_SYSTEM);
// no crash
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
}
@Test
public void testOnUserRemoved_cleanupPendingPackages() {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.onUserStopped(USER_SYSTEM);
String pkg = "pkg";
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
mHistoryManager.onUserRemoved(USER_SYSTEM);
assertThat(mHistoryManager.getPendingPackageRemovalsForUser(USER_SYSTEM)).isNull();
}
@Test
public void testOnPackageRemoved_userUnlocked() {
String pkg = "pkg";
NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory);
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
verify(userHistory, times(1)).onPackageRemoved(pkg);
}
@Test
public void testOnPackageRemoved_userLocked() {
String pkg = "pkg";
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
assertThat(mHistoryManager.getPendingPackageRemovalsForUser(USER_SYSTEM)).contains(pkg);
}
@Test
public void testOnPackageRemoved_historyDisabled() {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
String pkg = "pkg";
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
assertThat(mHistoryManager.getPendingPackageRemovalsForUser(USER_SYSTEM))
.isNull();
}
@Test
public void testOnPackageRemoved_multiUser() {
String pkg = "pkg";
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
verify(userHistorySystem, times(1)).onPackageRemoved(pkg);
verify(userHistoryAll, never()).onPackageRemoved(pkg);
}
@Test
public void testDeleteNotificationHistoryItem_userUnlocked() {
String pkg = "pkg";
long time = 235;
NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory);
mHistoryManager.deleteNotificationHistoryItem(pkg, 1, time);
verify(userHistory, times(1)).deleteNotificationHistoryItem(pkg, time);
}
@Test
public void testDeleteConversation_userUnlocked() {
String pkg = "pkg";
String convo = "convo";
NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory);
mHistoryManager.deleteConversation(pkg, 1, convo);
verify(userHistory, times(1)).deleteConversation(pkg, convo);
}
@Test
public void testTriggerWriteToDisk() {
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.triggerWriteToDisk();
verify(userHistorySystem, times(1)).forceWriteToDisk();
verify(userHistoryAll, times(1)).forceWriteToDisk();
}
@Test
public void testTriggerWriteToDisk_onlyUnlockedUsers() {
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.onUserStopped(MIN_SECONDARY_USER_ID);
mHistoryManager.triggerWriteToDisk();
verify(userHistorySystem, times(1)).forceWriteToDisk();
verify(userHistoryAll, never()).forceWriteToDisk();
}
@Test
public void testTriggerWriteToDisk_historyDisabled() {
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
mHistoryManager.triggerWriteToDisk();
verify(userHistorySystem, never()).forceWriteToDisk();
}
@Test
public void testAddNotification_userLocked_noCrash() {
HistoricalNotification hn = getHistoricalNotification("pkg", 1);
mHistoryManager.addNotification(hn);
}
@Test
public void testAddNotification_historyDisabled() {
HistoricalNotification hn = getHistoricalNotification("pkg", 1);
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, hn.getUserId());
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
mHistoryManager.onUserUnlocked(hn.getUserId());
mHistoryManager.addNotification(hn);
verify(mDb, never()).addNotification(any());
}
@Test
public void testAddNotification() {
HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
HistoricalNotification hnAll = getHistoricalNotification("pkg", MIN_SECONDARY_USER_ID);
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.addNotification(hnSystem);
mHistoryManager.addNotification(hnAll);
verify(userHistorySystem, times(1)).addNotification(hnSystem);
verify(userHistoryAll, times(1)).addNotification(hnAll);
}
@Test
public void testReadNotificationHistory() {
HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
HistoricalNotification hnAll = getHistoricalNotification("pkg", MIN_SECONDARY_USER_ID);
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
NotificationHistory nhSystem = mock(NotificationHistory.class);
ArrayList<HistoricalNotification> nhSystemList = new ArrayList<>();
nhSystemList.add(hnSystem);
when(nhSystem.getNotificationsToWrite()).thenReturn(nhSystemList);
when(userHistorySystem.readNotificationHistory()).thenReturn(nhSystem);
mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
NotificationHistory nhAll = mock(NotificationHistory.class);
ArrayList<HistoricalNotification> nhAllList = new ArrayList<>();
nhAllList.add(hnAll);
when(nhAll.getNotificationsToWrite()).thenReturn(nhAllList);
when(userHistoryAll.readNotificationHistory()).thenReturn(nhAll);
// ensure read history returns both historical notifs
NotificationHistory nh = mHistoryManager.readNotificationHistory(
new int[] {USER_SYSTEM, MIN_SECONDARY_USER_ID});
assertThat(nh.getNotificationsToWrite()).contains(hnSystem);
assertThat(nh.getNotificationsToWrite()).contains(hnAll);
}
@Test
public void testReadNotificationHistory_historyDisabled() {
HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
NotificationHistory nhSystem = mock(NotificationHistory.class);
ArrayList<HistoricalNotification> nhSystemList = new ArrayList<>();
nhSystemList.add(hnSystem);
when(nhSystem.getNotificationsToWrite()).thenReturn(nhSystemList);
when(mDb.readNotificationHistory()).thenReturn(nhSystem);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
NotificationHistory nh =
mHistoryManager.readNotificationHistory(new int[] {USER_SYSTEM,});
assertThat(nh.getNotificationsToWrite()).isEmpty();
}
@Test
public void testReadFilteredNotificationHistory_userLocked() {
NotificationHistory nh =
mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "", "", 1000);
assertThat(nh.getNotificationsToWrite()).isEmpty();
}
@Test
public void testReadFilteredNotificationHistory_historyDisabled() {
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
NotificationHistory nh =
mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "", "", 1000);
assertThat(nh.getNotificationsToWrite()).isEmpty();
}
@Test
public void readFilteredNotificationHistory() {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "pkg", "chn", 1000);
verify(mDb, times(1)).readNotificationHistory("pkg", "chn", 1000);
}
@Test
public void testIsHistoryEnabled() {
assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isTrue();
mHistoryManager.onUserUnlocked(USER_SYSTEM);
Settings.Secure.putIntForUser(getContext().getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
}
}