1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.Mockito.doAnswer; 22 import static org.mockito.Mockito.never; 23 import static org.mockito.Mockito.times; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.app.Notification; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.RemoteException; 31 import android.os.UserHandle; 32 import android.service.notification.StatusBarNotification; 33 import android.support.test.filters.SmallTest; 34 import android.testing.AndroidTestingRunner; 35 import android.testing.TestableLooper; 36 37 import com.android.internal.statusbar.IStatusBarService; 38 import com.android.internal.statusbar.NotificationVisibility; 39 import com.android.systemui.SysuiTestCase; 40 41 import com.google.android.collect.Lists; 42 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.mockito.Mock; 47 import org.mockito.Mockito; 48 import org.mockito.MockitoAnnotations; 49 import org.mockito.stubbing.Answer; 50 51 import java.util.concurrent.ConcurrentLinkedQueue; 52 53 @SmallTest 54 @RunWith(AndroidTestingRunner.class) 55 @TestableLooper.RunWithLooper(setAsMainLooper = true) 56 public class NotificationLoggerTest extends SysuiTestCase { 57 private static final String TEST_PACKAGE_NAME = "test"; 58 private static final int TEST_UID = 0; 59 60 @Mock private NotificationPresenter mPresenter; 61 @Mock private NotificationListContainer mListContainer; 62 @Mock private IStatusBarService mBarService; 63 @Mock private NotificationData mNotificationData; 64 @Mock private ExpandableNotificationRow mRow; 65 66 // Dependency mocks: 67 @Mock private NotificationEntryManager mEntryManager; 68 @Mock private NotificationListener mListener; 69 70 private NotificationData.Entry mEntry; 71 private StatusBarNotification mSbn; 72 private TestableNotificationLogger mLogger; 73 private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>(); 74 75 @Before 76 public void setUp() throws RemoteException { 77 MockitoAnnotations.initMocks(this); 78 mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); 79 mDependency.injectTestDependency(NotificationListener.class, mListener); 80 81 when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); 82 83 mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 84 0, new Notification(), UserHandle.CURRENT, null, 0); 85 mEntry = new NotificationData.Entry(mSbn); 86 mEntry.row = mRow; 87 88 mLogger = new TestableNotificationLogger(mBarService); 89 mLogger.setUpWithEntryManager(mEntryManager, mListContainer); 90 } 91 92 @Test 93 public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception { 94 NotificationVisibility[] newlyVisibleKeys = { 95 NotificationVisibility.obtain(mEntry.key, 0, 1, true) 96 }; 97 NotificationVisibility[] noLongerVisibleKeys = {}; 98 doAnswer((Answer) invocation -> { 99 try { 100 assertArrayEquals(newlyVisibleKeys, 101 (NotificationVisibility[]) invocation.getArguments()[0]); 102 assertArrayEquals(noLongerVisibleKeys, 103 (NotificationVisibility[]) invocation.getArguments()[1]); 104 } catch (AssertionError error) { 105 mErrorQueue.offer(error); 106 } 107 return null; 108 } 109 ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class), 110 any(NotificationVisibility[].class)); 111 112 when(mListContainer.isInVisibleLocation(any())).thenReturn(true); 113 when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry)); 114 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); 115 TestableLooper.get(this).processAllMessages(); 116 waitForUiOffloadThread(); 117 118 if(!mErrorQueue.isEmpty()) { 119 throw mErrorQueue.poll(); 120 } 121 122 // |mEntry| won't change visibility, so it shouldn't be reported again: 123 Mockito.reset(mBarService); 124 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); 125 TestableLooper.get(this).processAllMessages(); 126 waitForUiOffloadThread(); 127 128 verify(mBarService, never()).onNotificationVisibilityChanged(any(), any()); 129 } 130 131 @Test 132 public void testStoppingNotificationLoggingReportsCurrentNotifications() 133 throws Exception { 134 when(mListContainer.isInVisibleLocation(any())).thenReturn(true); 135 when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry)); 136 mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged(); 137 TestableLooper.get(this).processAllMessages(); 138 waitForUiOffloadThread(); 139 Mockito.reset(mBarService); 140 141 mLogger.stopNotificationLogging(); 142 waitForUiOffloadThread(); 143 // The visibility objects are recycled by NotificationLogger, so we can't use specific 144 // matchers here. 145 verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any()); 146 } 147 148 private class TestableNotificationLogger extends NotificationLogger { 149 150 public TestableNotificationLogger(IStatusBarService barService) { 151 mBarService = barService; 152 // Make this on the current thread so we can wait for it during tests. 153 mHandler = Handler.createAsync(Looper.myLooper()); 154 } 155 156 public OnChildLocationsChangedListener 157 getChildLocationsChangedListenerForTest() { 158 return mNotificationLocationsChangedListener; 159 } 160 161 public Handler getHandlerForTest() { 162 return mHandler; 163 } 164 } 165 } 166