blob: b8e25ab436914f89155c0f8eef82db680f009694 [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.systemui.statusbar.policy;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
import android.content.Context;
import android.content.Intent;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.AlertingNotificationManagerTest;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
private static final int TEST_A11Y_AUTO_DISMISS_TIME = 600;
private static final int TEST_A11Y_TIMEOUT_TIME = 5_000;
private AccessibilityManagerWrapper mAccessibilityMgr;
private HeadsUpManager mHeadsUpManager;
private boolean mLivesPastNormalTime;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@Mock private HeadsUpManager.HeadsUpEntry mAlertEntry;
@Mock private NotificationEntry mEntry;
@Mock private StatusBarNotification mSbn;
@Mock private Notification mNotification;
@Mock private HeadsUpManagerLogger mLogger;
private final class TestableHeadsUpManager extends HeadsUpManager {
TestableHeadsUpManager(Context context, HeadsUpManagerLogger logger) {
super(context, logger);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
}
}
protected AlertingNotificationManager createAlertingNotificationManager() {
return mHeadsUpManager;
}
@Before
public void setUp() {
initMocks(this);
mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
mDependency.injectTestDependency(UiEventLogger.class, mUiEventLoggerFake);
when(mEntry.getSbn()).thenReturn(mSbn);
when(mSbn.getNotification()).thenReturn(mNotification);
mHeadsUpManager = new TestableHeadsUpManager(mContext, mLogger);
super.setUp();
mHeadsUpManager.mHandler.removeCallbacksAndMessages(null);
mHeadsUpManager.mHandler = mTestHandler;
}
@After
public void tearDown() {
mTestHandler.removeCallbacksAndMessages(null);
}
@Test
public void testHunRemovedLogging() {
mAlertEntry.mEntry = mEntry;
mHeadsUpManager.onAlertEntryRemoved(mAlertEntry);
verify(mLogger, times(1)).logNotificationActuallyRemoved(eq(mEntry));
}
@Test
public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)
.getRecommendedTimeoutMillis(anyInt(), anyInt());
mHeadsUpManager.showNotification(mEntry);
Runnable pastNormalTimeRunnable =
() -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.getKey());
mTestHandler.postDelayed(pastNormalTimeRunnable,
(TEST_A11Y_AUTO_DISMISS_TIME + TEST_AUTO_DISMISS_TIME) / 2);
mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_A11Y_TIMEOUT_TIME);
TestableLooper.get(this).processMessages(2);
assertFalse("Test timed out", mTimedOut);
assertTrue("Heads up should live long enough", mLivesPastNormalTime);
assertFalse(mHeadsUpManager.isAlerting(mEntry.getKey()));
}
@Test
public void testCompareTo_withNullEntries() {
NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
mHeadsUpManager.showNotification(alertEntry);
assertThat(mHeadsUpManager.compare(alertEntry, null)).isLessThan(0);
assertThat(mHeadsUpManager.compare(null, alertEntry)).isGreaterThan(0);
assertThat(mHeadsUpManager.compare(null, null)).isEqualTo(0);
}
@Test
public void testCompareTo_withNonAlertEntries() {
NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag("nae1").build();
NotificationEntry nonAlertEntry2 = new NotificationEntryBuilder().setTag("nae2").build();
NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
mHeadsUpManager.showNotification(alertEntry);
assertThat(mHeadsUpManager.compare(alertEntry, nonAlertEntry1)).isLessThan(0);
assertThat(mHeadsUpManager.compare(nonAlertEntry1, alertEntry)).isGreaterThan(0);
assertThat(mHeadsUpManager.compare(nonAlertEntry1, nonAlertEntry2)).isEqualTo(0);
}
@Test
public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
HeadsUpManager.HeadsUpEntry ongoingCall = mHeadsUpManager.new HeadsUpEntry();
ongoingCall.setEntry(new NotificationEntryBuilder()
.setSbn(createNewSbn(0,
new Notification.Builder(mContext, "")
.setCategory(Notification.CATEGORY_CALL)
.setOngoing(true)))
.build());
HeadsUpManager.HeadsUpEntry activeRemoteInput = mHeadsUpManager.new HeadsUpEntry();
activeRemoteInput.setEntry(new NotificationEntryBuilder()
.setSbn(createNewNotification(1))
.build());
activeRemoteInput.remoteInputActive = true;
assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0);
}
@Test
public void testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() {
HeadsUpManager.HeadsUpEntry incomingCall = mHeadsUpManager.new HeadsUpEntry();
Person person = new Person.Builder().setName("person").build();
PendingIntent intent = mock(PendingIntent.class);
incomingCall.setEntry(new NotificationEntryBuilder()
.setSbn(createNewSbn(0,
new Notification.Builder(mContext, "")
.setStyle(Notification.CallStyle
.forIncomingCall(person, intent, intent))))
.build());
HeadsUpManager.HeadsUpEntry activeRemoteInput = mHeadsUpManager.new HeadsUpEntry();
activeRemoteInput.setEntry(new NotificationEntryBuilder()
.setSbn(createNewNotification(1))
.build());
activeRemoteInput.remoteInputActive = true;
assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
assertThat(activeRemoteInput.compareTo(incomingCall)).isGreaterThan(0);
}
@Test
public void testPinEntry_logsPeek() {
// Needs full screen intent in order to be pinned
final PendingIntent fullScreenIntent = PendingIntent.getActivity(mContext, 0,
new Intent(), PendingIntent.FLAG_MUTABLE);
HeadsUpManager.HeadsUpEntry entryToPin = mHeadsUpManager.new HeadsUpEntry();
entryToPin.setEntry(new NotificationEntryBuilder()
.setSbn(createNewSbn(0,
new Notification.Builder(mContext, "")
.setFullScreenIntent(fullScreenIntent, true)))
.build());
// Note: the standard way to show a notification would be calling showNotification rather
// than onAlertEntryAdded. However, in practice showNotification in effect adds
// the notification and then updates it; in order to not log twice, the entry needs
// to have a functional ExpandableNotificationRow that can keep track of whether it's
// pinned or not (via isRowPinned()). That feels like a lot to pull in to test this one bit.
mHeadsUpManager.onAlertEntryAdded(entryToPin);
assertEquals(1, mUiEventLoggerFake.numLogs());
assertEquals(HeadsUpManager.NotificationPeekEvent.NOTIFICATION_PEEK.getId(),
mUiEventLoggerFake.eventId(0));
}
}