Fix an ANR caused by the dream overlay status bar.
Specifically, this ANR happened when attempting to compute the notification count in order to show a notification icon. The new strategy reacts to notification additions/subtractions rather than attempting to fetch all notifications every time the notifications change. Test: atest DreamOverlayStatusBarViewControllerTest, DreamOverlayNotificationCountProviderTest Bug: 225967369 Change-Id: Ied9453e8788448f957e5b70c7dae08022a993cc1
This commit is contained in:
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.dreams;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
|
import com.android.systemui.statusbar.NotificationListener;
|
||||||
|
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
|
||||||
|
import com.android.systemui.statusbar.policy.CallbackController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* {@link DreamOverlayNotificationCountProvider} provides the current notification count to
|
||||||
|
* registered callbacks.
|
||||||
|
*/
|
||||||
|
@SysUISingleton
|
||||||
|
public class DreamOverlayNotificationCountProvider
|
||||||
|
implements CallbackController<DreamOverlayNotificationCountProvider.Callback> {
|
||||||
|
private final Set<String> mNotificationKeys = new HashSet<>();
|
||||||
|
private final List<Callback> mCallbacks = new ArrayList<>();
|
||||||
|
|
||||||
|
private final NotificationHandler mNotificationHandler = new NotificationHandler() {
|
||||||
|
@Override
|
||||||
|
public void onNotificationPosted(
|
||||||
|
StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
|
||||||
|
mNotificationKeys.add(sbn.getKey());
|
||||||
|
reportNotificationCountChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotificationRemoved(
|
||||||
|
StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
|
||||||
|
mNotificationKeys.remove(sbn.getKey());
|
||||||
|
reportNotificationCountChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotificationRemoved(
|
||||||
|
StatusBarNotification sbn,
|
||||||
|
NotificationListenerService.RankingMap rankingMap,
|
||||||
|
int reason) {
|
||||||
|
mNotificationKeys.remove(sbn.getKey());
|
||||||
|
reportNotificationCountChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotificationRankingUpdate(NotificationListenerService.RankingMap rankingMap) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotificationsInitialized() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DreamOverlayNotificationCountProvider(
|
||||||
|
NotificationListener notificationListener) {
|
||||||
|
notificationListener.addNotificationHandler(mNotificationHandler);
|
||||||
|
Arrays.stream(notificationListener.getActiveNotifications())
|
||||||
|
.forEach(sbn -> mNotificationKeys.add(sbn.getKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addCallback(@NonNull Callback callback) {
|
||||||
|
if (!mCallbacks.contains(callback)) {
|
||||||
|
mCallbacks.add(callback);
|
||||||
|
callback.onNotificationCountChanged(mNotificationKeys.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCallback(@NonNull Callback callback) {
|
||||||
|
mCallbacks.remove(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportNotificationCountChanged() {
|
||||||
|
final int notificationCount = mNotificationKeys.size();
|
||||||
|
mCallbacks.forEach(callback -> callback.onNotificationCountChanged(notificationCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback to be registered with {@link DreamOverlayNotificationCountProvider} to receive
|
||||||
|
* changes to the current notification count.
|
||||||
|
*/
|
||||||
|
public interface Callback {
|
||||||
|
/**
|
||||||
|
* Called when the notification count has changed.
|
||||||
|
* @param count The current notification count.
|
||||||
|
*/
|
||||||
|
void onNotificationCountChanged(int count);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,16 +27,12 @@ import android.net.NetworkCapabilities;
|
|||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.notification.NotificationListenerService.RankingMap;
|
|
||||||
import android.service.notification.StatusBarNotification;
|
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.util.PluralsMessageFormatter;
|
import android.util.PluralsMessageFormatter;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
|
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
|
||||||
import com.android.systemui.statusbar.NotificationListener;
|
|
||||||
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
|
|
||||||
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
|
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
|
||||||
import com.android.systemui.statusbar.policy.NextAlarmController;
|
import com.android.systemui.statusbar.policy.NextAlarmController;
|
||||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||||
@@ -62,7 +58,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
private final Resources mResources;
|
private final Resources mResources;
|
||||||
private final DateFormatUtil mDateFormatUtil;
|
private final DateFormatUtil mDateFormatUtil;
|
||||||
private final IndividualSensorPrivacyController mSensorPrivacyController;
|
private final IndividualSensorPrivacyController mSensorPrivacyController;
|
||||||
private final NotificationListener mNotificationListener;
|
private final DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
|
||||||
private final ZenModeController mZenModeController;
|
private final ZenModeController mZenModeController;
|
||||||
private final Executor mMainExecutor;
|
private final Executor mMainExecutor;
|
||||||
|
|
||||||
@@ -96,35 +92,6 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback =
|
private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback =
|
||||||
nextAlarm -> updateAlarmStatusIcon();
|
nextAlarm -> updateAlarmStatusIcon();
|
||||||
|
|
||||||
private final NotificationHandler mNotificationHandler = new NotificationHandler() {
|
|
||||||
@Override
|
|
||||||
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
|
|
||||||
updateNotificationsStatusIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
|
|
||||||
updateNotificationsStatusIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNotificationRemoved(
|
|
||||||
StatusBarNotification sbn,
|
|
||||||
RankingMap rankingMap,
|
|
||||||
int reason) {
|
|
||||||
updateNotificationsStatusIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNotificationRankingUpdate(RankingMap rankingMap) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNotificationsInitialized() {
|
|
||||||
updateNotificationsStatusIcon();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final ZenModeController.Callback mZenModeCallback = new ZenModeController.Callback() {
|
private final ZenModeController.Callback mZenModeCallback = new ZenModeController.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onZenChanged(int zen) {
|
public void onZenChanged(int zen) {
|
||||||
@@ -132,6 +99,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final DreamOverlayNotificationCountProvider.Callback mNotificationCountCallback =
|
||||||
|
notificationCount -> showIcon(
|
||||||
|
DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
|
||||||
|
notificationCount > 0,
|
||||||
|
notificationCount > 0
|
||||||
|
? buildNotificationsContentDescription(notificationCount)
|
||||||
|
: null);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public DreamOverlayStatusBarViewController(
|
public DreamOverlayStatusBarViewController(
|
||||||
DreamOverlayStatusBarView view,
|
DreamOverlayStatusBarView view,
|
||||||
@@ -143,7 +118,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
NextAlarmController nextAlarmController,
|
NextAlarmController nextAlarmController,
|
||||||
DateFormatUtil dateFormatUtil,
|
DateFormatUtil dateFormatUtil,
|
||||||
IndividualSensorPrivacyController sensorPrivacyController,
|
IndividualSensorPrivacyController sensorPrivacyController,
|
||||||
NotificationListener notificationListener,
|
DreamOverlayNotificationCountProvider dreamOverlayNotificationCountProvider,
|
||||||
ZenModeController zenModeController) {
|
ZenModeController zenModeController) {
|
||||||
super(view);
|
super(view);
|
||||||
mResources = resources;
|
mResources = resources;
|
||||||
@@ -154,20 +129,14 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
mNextAlarmController = nextAlarmController;
|
mNextAlarmController = nextAlarmController;
|
||||||
mDateFormatUtil = dateFormatUtil;
|
mDateFormatUtil = dateFormatUtil;
|
||||||
mSensorPrivacyController = sensorPrivacyController;
|
mSensorPrivacyController = sensorPrivacyController;
|
||||||
mNotificationListener = notificationListener;
|
mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider;
|
||||||
mZenModeController = zenModeController;
|
mZenModeController = zenModeController;
|
||||||
|
|
||||||
// Handlers can be added to NotificationListener, but apparently they can't be removed. So
|
|
||||||
// add the handler here in the constructor rather than in onViewAttached to avoid confusion.
|
|
||||||
mNotificationListener.addNotificationHandler(mNotificationHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onViewAttached() {
|
protected void onViewAttached() {
|
||||||
mIsAttached = true;
|
mIsAttached = true;
|
||||||
|
|
||||||
updateNotificationsStatusIcon();
|
|
||||||
|
|
||||||
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
|
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
|
||||||
updateWifiUnavailableStatusIcon();
|
updateWifiUnavailableStatusIcon();
|
||||||
|
|
||||||
@@ -180,6 +149,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
mZenModeController.addCallback(mZenModeCallback);
|
mZenModeController.addCallback(mZenModeCallback);
|
||||||
updatePriorityModeStatusIcon();
|
updatePriorityModeStatusIcon();
|
||||||
|
|
||||||
|
mDreamOverlayNotificationCountProvider.addCallback(mNotificationCountCallback);
|
||||||
mTouchInsetSession.addViewToTracking(mView);
|
mTouchInsetSession.addViewToTracking(mView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +159,7 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
mSensorPrivacyController.removeCallback(mSensorCallback);
|
mSensorPrivacyController.removeCallback(mSensorCallback);
|
||||||
mNextAlarmController.removeCallback(mNextAlarmCallback);
|
mNextAlarmController.removeCallback(mNextAlarmCallback);
|
||||||
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
|
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
|
||||||
|
mDreamOverlayNotificationCountProvider.removeCallback(mNotificationCountCallback);
|
||||||
mTouchInsetSession.clear();
|
mTouchInsetSession.clear();
|
||||||
|
|
||||||
mIsAttached = false;
|
mIsAttached = false;
|
||||||
@@ -231,24 +202,6 @@ public class DreamOverlayStatusBarViewController extends ViewController<DreamOve
|
|||||||
micBlocked && cameraBlocked);
|
micBlocked && cameraBlocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNotificationsStatusIcon() {
|
|
||||||
if (mView == null) {
|
|
||||||
// It is possible for this method to be called before the view is attached, which makes
|
|
||||||
// null-checking necessary.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StatusBarNotification[] notifications =
|
|
||||||
mNotificationListener.getActiveNotifications();
|
|
||||||
final int notificationCount = notifications != null ? notifications.length : 0;
|
|
||||||
showIcon(
|
|
||||||
DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
|
|
||||||
notificationCount > 0,
|
|
||||||
notificationCount > 0
|
|
||||||
? buildNotificationsContentDescription(notificationCount)
|
|
||||||
: null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildNotificationsContentDescription(int notificationCount) {
|
private String buildNotificationsContentDescription(int notificationCount) {
|
||||||
return PluralsMessageFormatter.format(
|
return PluralsMessageFormatter.format(
|
||||||
mResources,
|
mResources,
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.dreams;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.service.notification.NotificationListenerService;
|
||||||
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.statusbar.NotificationListener;
|
||||||
|
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
|
||||||
|
@Mock
|
||||||
|
NotificationListener mNotificationListener;
|
||||||
|
@Mock
|
||||||
|
DreamOverlayNotificationCountProvider.Callback mCallback;
|
||||||
|
@Mock
|
||||||
|
StatusBarNotification mNotification1;
|
||||||
|
@Mock
|
||||||
|
StatusBarNotification mNotification2;
|
||||||
|
@Mock
|
||||||
|
NotificationListenerService.RankingMap mRankingMap;
|
||||||
|
|
||||||
|
private DreamOverlayNotificationCountProvider mProvider;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
when(mNotification1.getKey()).thenReturn("key1");
|
||||||
|
when(mNotification2.getKey()).thenReturn("key2");
|
||||||
|
|
||||||
|
final StatusBarNotification[] notifications = {mNotification1};
|
||||||
|
when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
|
||||||
|
mProvider = new DreamOverlayNotificationCountProvider(mNotificationListener);
|
||||||
|
mProvider.addCallback(mCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostingNotificationCallsCallbackWithNotificationCount() {
|
||||||
|
final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor =
|
||||||
|
ArgumentCaptor.forClass(NotificationHandler.class);
|
||||||
|
verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture());
|
||||||
|
handlerArgumentCaptor.getValue().onNotificationPosted(mNotification2, mRankingMap);
|
||||||
|
verify(mCallback).onNotificationCountChanged(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemovingNotificationCallsCallbackWithZeroNotificationCount() {
|
||||||
|
final ArgumentCaptor<NotificationHandler> handlerArgumentCaptor =
|
||||||
|
ArgumentCaptor.forClass(NotificationHandler.class);
|
||||||
|
verify(mNotificationListener).addNotificationHandler(handlerArgumentCaptor.capture());
|
||||||
|
handlerArgumentCaptor.getValue().onNotificationRemoved(mNotification1, mRankingMap);
|
||||||
|
verify(mCallback).onNotificationCountChanged(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,15 +31,12 @@ import android.net.Network;
|
|||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.service.notification.NotificationListenerService;
|
|
||||||
import android.service.notification.StatusBarNotification;
|
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.statusbar.NotificationListener;
|
|
||||||
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
|
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
|
||||||
import com.android.systemui.statusbar.policy.NextAlarmController;
|
import com.android.systemui.statusbar.policy.NextAlarmController;
|
||||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||||
@@ -84,13 +81,9 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
IndividualSensorPrivacyController mSensorPrivacyController;
|
IndividualSensorPrivacyController mSensorPrivacyController;
|
||||||
@Mock
|
@Mock
|
||||||
StatusBarNotification mStatusBarNotification;
|
|
||||||
@Mock
|
|
||||||
NotificationListenerService.RankingMap mRankingMap;
|
|
||||||
@Mock
|
|
||||||
NotificationListener mNotificationListener;
|
|
||||||
@Mock
|
|
||||||
ZenModeController mZenModeController;
|
ZenModeController mZenModeController;
|
||||||
|
@Mock
|
||||||
|
DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
|
||||||
|
|
||||||
private final Executor mMainExecutor = Runnable::run;
|
private final Executor mMainExecutor = Runnable::run;
|
||||||
|
|
||||||
@@ -113,7 +106,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
mNextAlarmController,
|
mNextAlarmController,
|
||||||
mDateFormatUtil,
|
mDateFormatUtil,
|
||||||
mSensorPrivacyController,
|
mSensorPrivacyController,
|
||||||
mNotificationListener,
|
mDreamOverlayNotificationCountProvider,
|
||||||
mZenModeController);
|
mZenModeController);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +116,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
verify(mNextAlarmController).addCallback(any());
|
verify(mNextAlarmController).addCallback(any());
|
||||||
verify(mSensorPrivacyController).addCallback(any());
|
verify(mSensorPrivacyController).addCallback(any());
|
||||||
verify(mZenModeController).addCallback(any());
|
verify(mZenModeController).addCallback(any());
|
||||||
|
verify(mDreamOverlayNotificationCountProvider).addCallback(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -202,17 +196,26 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnViewAttachedShowsNotificationsIconWhenNotificationsExist() {
|
public void testOnViewAttachedShowsNotificationsIconWhenNotificationsExist() {
|
||||||
StatusBarNotification[] notifications = { mStatusBarNotification };
|
|
||||||
when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
|
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
|
||||||
|
final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
|
||||||
|
ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
|
||||||
|
verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
|
||||||
|
callbackCapture.getValue().onNotificationCountChanged(1);
|
||||||
|
|
||||||
verify(mView).showIcon(
|
verify(mView).showIcon(
|
||||||
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
|
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnViewAttachedHidesNotificationsIconWhenNoNotificationsExist() {
|
public void testOnViewAttachedHidesNotificationsIconWhenNoNotificationsExist() {
|
||||||
when(mNotificationListener.getActiveNotifications()).thenReturn(null);
|
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
|
||||||
|
final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
|
||||||
|
ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
|
||||||
|
verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
|
||||||
|
callbackCapture.getValue().onNotificationCountChanged(0);
|
||||||
|
|
||||||
verify(mView).showIcon(
|
verify(mView).showIcon(
|
||||||
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull());
|
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull());
|
||||||
}
|
}
|
||||||
@@ -248,6 +251,7 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
verify(mNextAlarmController).removeCallback(any());
|
verify(mNextAlarmController).removeCallback(any());
|
||||||
verify(mSensorPrivacyController).removeCallback(any());
|
verify(mSensorPrivacyController).removeCallback(any());
|
||||||
verify(mZenModeController).removeCallback(any());
|
verify(mZenModeController).removeCallback(any());
|
||||||
|
verify(mDreamOverlayNotificationCountProvider).removeCallback(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -309,13 +313,10 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
public void testNotificationsIconShownWhenNotificationAdded() {
|
public void testNotificationsIconShownWhenNotificationAdded() {
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
|
||||||
StatusBarNotification[] notifications = { mStatusBarNotification };
|
final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
|
||||||
when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
|
ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
|
||||||
|
verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
|
||||||
final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture =
|
callbackCapture.getValue().onNotificationCountChanged(1);
|
||||||
ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class);
|
|
||||||
verify(mNotificationListener).addNotificationHandler(callbackCapture.capture());
|
|
||||||
callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap);
|
|
||||||
|
|
||||||
verify(mView).showIcon(
|
verify(mView).showIcon(
|
||||||
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
|
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
|
||||||
@@ -323,15 +324,12 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotificationsIconHiddenWhenLastNotificationRemoved() {
|
public void testNotificationsIconHiddenWhenLastNotificationRemoved() {
|
||||||
StatusBarNotification[] notifications = { mStatusBarNotification };
|
|
||||||
when(mNotificationListener.getActiveNotifications()).thenReturn(notifications)
|
|
||||||
.thenReturn(null);
|
|
||||||
mController.onViewAttached();
|
mController.onViewAttached();
|
||||||
|
|
||||||
final ArgumentCaptor<NotificationListener.NotificationHandler> callbackCapture =
|
final ArgumentCaptor<DreamOverlayNotificationCountProvider.Callback> callbackCapture =
|
||||||
ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class);
|
ArgumentCaptor.forClass(DreamOverlayNotificationCountProvider.Callback.class);
|
||||||
verify(mNotificationListener).addNotificationHandler(callbackCapture.capture());
|
verify(mDreamOverlayNotificationCountProvider).addCallback(callbackCapture.capture());
|
||||||
callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap);
|
callbackCapture.getValue().onNotificationCountChanged(0);
|
||||||
|
|
||||||
verify(mView).showIcon(
|
verify(mView).showIcon(
|
||||||
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any());
|
eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any());
|
||||||
|
|||||||
Reference in New Issue
Block a user