summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/tests
diff options
context:
space:
mode:
authorChris Wren <cwren@android.com>2014-11-12 17:43:41 -0500
committerChris Wren <cwren@android.com>2015-02-04 17:16:16 -0500
commit930eccaf44239d010cbafb246651697996f567b5 (patch)
tree558e9148c81b9fd23ce70bdf9063a0ccbb125f0e /packages/SystemUI/tests
parent37a6ad9755cbf49929f089523c99ad187f22b63b (diff)
downloadframeworks_base-930eccaf44239d010cbafb246651697996f567b5.zip
frameworks_base-930eccaf44239d010cbafb246651697996f567b5.tar.gz
frameworks_base-930eccaf44239d010cbafb246651697996f567b5.tar.bz2
Don't let the heads up close too quickly.
The public API of HeadsUpNotificaitonView was not well suited to the new requirements, so it changed slightly. Old API: - showNotification: show or update a notification - clear: close the window and forget the notification - release: send the notification to the shade and forget about it. - releaseAndClose: release and close the window - dismiss: clear the notification if clearable, or release it New API: - showNotification: show a new notification - updateNotification: show a new version of the same notification - removeNotification: respond to a cancel - release: send the notification to the shade at some point - releaseImmediately: send the notification to the shade right now The new API makes updating vs. posting and removing vs. releasing more explicit. There is a new internal concept: lingering. The heads up lingers after an event that would have closed it if the minimum visibility time has not been satisfied. In the case that the notification was deleted, the heads up may be visible, but mHeadsUp will be null. In this case, touches on the notification views are disabled. More responsibility for control of the heads of policy was moved into the HeadsUpNotificaitonView class. This should continue on master. Some changes to support testing. Added a test to cover all the edge cases for minimum visibility time: 1. extend visibility when canceled too soon 2. extend when updated with a low-priority version, fast update. 3. extend when updated with a low-priority version, slow update. 4. don't extend the visibility in any other case TODO: Policy parts of HeadsUpNotificationView should be split out into a separate HeadsUpNotificationPolicy class, and even more of the policy should be lifted from status bar that new class. Bug: 17878008 Change-Id: I192419d0685dd022ee7edcd792e346a4f39c6adb
Diffstat (limited to 'packages/SystemUI/tests')
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java261
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java7
3 files changed, 294 insertions, 5 deletions
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
new file mode 100644
index 0000000..3fdb3d2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.test.AndroidTestCase;
+
+/**
+ * Base class that does System UI specific setup.
+ */
+public class SysuiTestCase extends AndroidTestCase {
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // Mockito stuff.
+ System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+ Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java
new file mode 100644
index 0000000..e8a80d9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpNotificationTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2014 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 org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.*;
+import android.service.notification.StatusBarNotification;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test the Heads Up Notification.
+ *
+ * Specifically the policy that a notificaiton must remain visibile for a minimum period of time.
+ */
+public class HeadsUpNotificationTest extends SysuiTestCase {
+ private static final String TAG = "HeadsUpNotificationTest";
+
+ private static int TOUCH_SENSITIVITY = 100;
+ private static int NOTIFICATION_DECAY = 10000;
+ private static int MINIMUM_DISPLAY_TIME = 3000;
+ private static int SNOOZE_TIME = 60000;
+ private static long TOO_SOON = 1000L; // less than MINIMUM_DISPLAY_TIME
+ private static long LATER = 5000L; // more than MINIMUM_DISPLAY_TIME
+ private static long REMAINING_VISIBILITY = MINIMUM_DISPLAY_TIME - TOO_SOON;
+
+ protected HeadsUpNotificationView mHeadsUp;
+
+ @Mock protected PhoneStatusBar mMockStatusBar;
+ @Mock private HeadsUpNotificationView.Clock mClock;
+ @Mock private SwipeHelper mMockSwipeHelper;
+ @Mock private HeadsUpNotificationView.EdgeSwipeHelper mMockEdgeSwipeHelper;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ MockitoAnnotations.initMocks(this);
+
+ mHeadsUp = new HeadsUpNotificationView(mContext,
+ mClock, mMockSwipeHelper, mMockEdgeSwipeHelper,
+ NOTIFICATION_DECAY, MINIMUM_DISPLAY_TIME, TOUCH_SENSITIVITY, SNOOZE_TIME);
+ mHeadsUp.setBar(mMockStatusBar);
+ }
+
+ private NotificationData.Entry makeNotification(String key) {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getKey()).thenReturn(key);
+ return new NotificationData.Entry(sbn, null);
+ }
+
+ public void testPostAndDecay() {
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpOpen();
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar).scheduleHeadsUpDecay(decayArg.capture());
+ // New notification gets a full decay time.
+ assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+ }
+
+ public void testPostAndDeleteTooSoon() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ mHeadsUp.removeNotification(a.key);
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar).scheduleHeadsUpDecay(decayArg.capture());
+ // Leave the window up for the balance of the minumum time.
+ assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+ }
+
+ public void testPostAndDeleteLater() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(LATER);
+ mHeadsUp.removeNotification(a.key);
+ // Delete closes immediately if the minimum time window is satisfied.
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+ }
+
+ // This is a bad test. It should not care that there is a call to scheduleHeadsUpClose(),
+ // but it happens that there will be one, so it is important that it happen before the
+ // call to scheduleHeadsUpOpen(), so that the final state is open.
+ // Maybe mMockStatusBar should instead be a fake that tracks the open/closed state.
+ public void testPostAndReplaceTooSoon() {
+ InOrder callOrder = inOrder(mMockStatusBar);
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ NotificationData.Entry b = makeNotification("b");
+ mHeadsUp.showNotification(b);
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+ // New notification gets a full decay time.
+ assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+
+ // Make sure close was called before open, so that the heads up stays open.
+ callOrder.verify(mMockStatusBar).scheduleHeadsUpClose();
+ callOrder.verify(mMockStatusBar).scheduleHeadsUpOpen();
+ }
+
+ public void testPostAndUpdateAlertAgain() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ mHeadsUp.updateNotification(a, true);
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+ // Alert again gets a full decay time.
+ assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+ }
+
+ public void testPostAndUpdateAlertAgainFastFail() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ NotificationData.Entry a_prime = makeNotification("a");
+ mHeadsUp.updateNotification(a_prime, true);
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+ // Alert again gets a full decay time.
+ assertEquals(NOTIFICATION_DECAY, (long) decayArg.getValue());
+ }
+
+ public void testPostAndUpdateNoAlertAgain() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ mHeadsUp.updateNotification(a, false);
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+ }
+
+ public void testPostAndUpdateNoAlertAgainFastFail() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ NotificationData.Entry a_prime = makeNotification("a");
+ mHeadsUp.updateNotification(a_prime, false);
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+ }
+
+ public void testPostAndUpdateLowPriorityTooSoon() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ mHeadsUp.release();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+ // Down grade on update leaves the window up for the balance of the minumum time.
+ assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+ }
+
+ public void testPostAndUpdateLowPriorityTooSoonFastFail() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(TOO_SOON);
+ NotificationData.Entry a_prime = makeNotification("a");
+ mHeadsUp.updateNotification(a_prime, false);
+ mHeadsUp.release();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpClose();
+ ArgumentCaptor<Long> decayArg = ArgumentCaptor.forClass(Long.class);
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpDecay(decayArg.capture());
+ // Down grade on update leaves the window up for the balance of the minumum time.
+ assertEquals(REMAINING_VISIBILITY, (long) decayArg.getValue());
+ }
+
+ public void testPostAndUpdateLowPriorityLater() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(LATER);
+ mHeadsUp.release();
+ // Down grade on update closes immediately if the minimum time window is satisfied.
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+ }
+
+ public void testPostAndUpdateLowPriorityLaterFastFail() {
+ when(mClock.currentTimeMillis()).thenReturn(0L);
+ NotificationData.Entry a = makeNotification("a");
+ mHeadsUp.showNotification(a);
+ reset(mMockStatusBar);
+
+ when(mClock.currentTimeMillis()).thenReturn(LATER);
+ NotificationData.Entry a_prime = makeNotification("a");
+ mHeadsUp.updateNotification(a_prime, false);
+ mHeadsUp.release();
+ // Down grade on update closes immediately if the minimum time window is satisfied.
+ Mockito.verify(mMockStatusBar, times(1)).scheduleHeadsUpClose();
+ Mockito.verify(mMockStatusBar, never()).scheduleHeadsUpDecay(anyInt());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 260dea0..5d88407 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -29,11 +29,11 @@ import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
import android.util.Log;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.cdma.EriInfo;
+import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
import com.android.systemui.statusbar.policy.NetworkControllerImpl.SignalCluster;
@@ -46,7 +46,7 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
-public class NetworkControllerBaseTest extends AndroidTestCase {
+public class NetworkControllerBaseTest extends SysuiTestCase {
private static final String TAG = "NetworkControllerBaseTest";
protected static final int DEFAULT_LEVEL = 2;
protected static final int DEFAULT_SIGNAL_STRENGTH =
@@ -76,9 +76,6 @@ public class NetworkControllerBaseTest extends AndroidTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- // Mockito stuff.
- System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
- Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
mMockWm = mock(WifiManager.class);
mMockTm = mock(TelephonyManager.class);