13985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney/*
23985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * Copyright (C) 2017 The Android Open Source Project
33985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney *
43985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * Licensed under the Apache License, Version 2.0 (the "License");
53985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * you may not use this file except in compliance with the License.
63985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * You may obtain a copy of the License at
73985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney *
83985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney *      http://www.apache.org/licenses/LICENSE-2.0
93985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney *
103985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * Unless required by applicable law or agreed to in writing, software
113985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * distributed under the License is distributed on an "AS IS" BASIS,
123985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * See the License for the specific language governing permissions and
143985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney * limitations under the License.
153985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney */
163985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
173985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneypackage com.android.systemui.statusbar;
183985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
192e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wrenimport static org.junit.Assert.assertArrayEquals;
203985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport static org.mockito.ArgumentMatchers.any;
212e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wrenimport static org.mockito.Mockito.doAnswer;
223985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport static org.mockito.Mockito.never;
233985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport static org.mockito.Mockito.times;
243985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport static org.mockito.Mockito.verify;
253985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport static org.mockito.Mockito.when;
263985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
273985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.app.Notification;
283985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.os.Handler;
293985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.os.Looper;
302e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wrenimport android.os.RemoteException;
313985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.os.UserHandle;
323985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.service.notification.StatusBarNotification;
333985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.support.test.filters.SmallTest;
343985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.testing.AndroidTestingRunner;
353985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport android.testing.TestableLooper;
363985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
373985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport com.android.internal.statusbar.IStatusBarService;
383985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport com.android.internal.statusbar.NotificationVisibility;
393985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport com.android.systemui.SysuiTestCase;
403985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
413985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport com.google.android.collect.Lists;
423985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
433985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport org.junit.Before;
443985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport org.junit.Test;
453985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport org.junit.runner.RunWith;
463985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport org.mockito.Mock;
473985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport org.mockito.Mockito;
483985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneyimport org.mockito.MockitoAnnotations;
492e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wrenimport org.mockito.stubbing.Answer;
502e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren
512e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wrenimport java.util.concurrent.ConcurrentLinkedQueue;
523985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
533985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney@SmallTest
543985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney@RunWith(AndroidTestingRunner.class)
556dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk@TestableLooper.RunWithLooper(setAsMainLooper = true)
563985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtneypublic class NotificationLoggerTest extends SysuiTestCase {
573985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    private static final String TEST_PACKAGE_NAME = "test";
583985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    private static final int TEST_UID = 0;
593985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
603985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Mock private NotificationPresenter mPresenter;
612b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney    @Mock private NotificationListContainer mListContainer;
623985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Mock private IStatusBarService mBarService;
633985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Mock private NotificationData mNotificationData;
643985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Mock private ExpandableNotificationRow mRow;
653985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
668f56b0e3452dcc940319708061a3a22a4d994027Eliot Courtney    // Dependency mocks:
678f56b0e3452dcc940319708061a3a22a4d994027Eliot Courtney    @Mock private NotificationEntryManager mEntryManager;
688f56b0e3452dcc940319708061a3a22a4d994027Eliot Courtney    @Mock private NotificationListener mListener;
698f56b0e3452dcc940319708061a3a22a4d994027Eliot Courtney
703985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    private NotificationData.Entry mEntry;
713985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    private StatusBarNotification mSbn;
723985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    private TestableNotificationLogger mLogger;
732e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren    private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
743985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
753985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Before
762e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren    public void setUp() throws RemoteException {
773985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        MockitoAnnotations.initMocks(this);
788f56b0e3452dcc940319708061a3a22a4d994027Eliot Courtney        mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
798f56b0e3452dcc940319708061a3a22a4d994027Eliot Courtney        mDependency.injectTestDependency(NotificationListener.class, mListener);
803985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
81a6d8cf294dfb587f130fdecc5e6897e75de7bf45Eliot Courtney        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
823985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
833985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
843985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney                0, new Notification(), UserHandle.CURRENT, null, 0);
853985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        mEntry = new NotificationData.Entry(mSbn);
863985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        mEntry.row = mRow;
873985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
886c313d3224c878d832db3ed833f4a3dd3786fb1fEliot Courtney        mLogger = new TestableNotificationLogger(mBarService);
894a96b36fd9857cd3d3534ed0396ec3d7155a324cEliot Courtney        mLogger.setUpWithEntryManager(mEntryManager, mListContainer);
903985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    }
913985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
923985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Test
933985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
942e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        NotificationVisibility[] newlyVisibleKeys = {
952e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                NotificationVisibility.obtain(mEntry.key, 0, 1, true)
962e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        };
972e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        NotificationVisibility[] noLongerVisibleKeys = {};
982e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        doAnswer((Answer) invocation -> {
992e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                    try {
1002e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                        assertArrayEquals(newlyVisibleKeys,
1012e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                                (NotificationVisibility[]) invocation.getArguments()[0]);
1022e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                        assertArrayEquals(noLongerVisibleKeys,
1032e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                                (NotificationVisibility[]) invocation.getArguments()[1]);
1042e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                    } catch (AssertionError error) {
1052e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                        mErrorQueue.offer(error);
1062e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                    }
1072e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                    return null;
1082e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                }
1092e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class),
1102e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren                any(NotificationVisibility[].class));
1112e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren
1122b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney        when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
1133985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
1142b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney        mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
1156dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk        TestableLooper.get(this).processAllMessages();
1163985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        waitForUiOffloadThread();
1173985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1182e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        if(!mErrorQueue.isEmpty()) {
1192e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren            throw mErrorQueue.poll();
1202e89e8d893acfe571ad6f5555baccb1b5e55abb7Chris Wren        }
1213985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1223985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        // |mEntry| won't change visibility, so it shouldn't be reported again:
1233985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        Mockito.reset(mBarService);
1242b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney        mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
1256dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk        TestableLooper.get(this).processAllMessages();
1263985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        waitForUiOffloadThread();
1273985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1283985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        verify(mBarService, never()).onNotificationVisibilityChanged(any(), any());
1293985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    }
1303985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1313985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    @Test
1323985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    public void testStoppingNotificationLoggingReportsCurrentNotifications()
1333985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney            throws Exception {
1342b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney        when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
1353985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
1362b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney        mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
1376dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk        TestableLooper.get(this).processAllMessages();
1383985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        waitForUiOffloadThread();
1393985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        Mockito.reset(mBarService);
1403985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1413985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        mLogger.stopNotificationLogging();
1423985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        waitForUiOffloadThread();
1433985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        // The visibility objects are recycled by NotificationLogger, so we can't use specific
1443985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        // matchers here.
1453985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
1463985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    }
1473985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1483985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    private class TestableNotificationLogger extends NotificationLogger {
1493985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1506c313d3224c878d832db3ed833f4a3dd3786fb1fEliot Courtney        public TestableNotificationLogger(IStatusBarService barService) {
1513985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney            mBarService = barService;
1526dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk            // Make this on the current thread so we can wait for it during tests.
1536dceace0eddd08156e6b71c17e3de4ed5f4f2f41Jason Monk            mHandler = Handler.createAsync(Looper.myLooper());
1543985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        }
1553985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1562b4c3a08fcfcb60c527a1a372318e5ef4ce2d49cEliot Courtney        public OnChildLocationsChangedListener
1573985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney                getChildLocationsChangedListenerForTest() {
1583985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney            return mNotificationLocationsChangedListener;
1593985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        }
1603985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney
1613985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        public Handler getHandlerForTest() {
1623985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney            return mHandler;
1633985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney        }
1643985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney    }
1653985ad5773cd4573525cbfb00e132b960a83ef48Eliot Courtney}
166