diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index 813787e8f9d02..1cbc3c2848748 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -29,7 +29,6 @@
android:layout_width="@dimen/dream_overlay_notification_indicator_size"
android:layout_height="@dimen/dream_overlay_notification_indicator_size"
android:visibility="gone"
- android:contentDescription="@string/dream_overlay_status_bar_notification_indicator"
app:dotColor="@android:color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@@ -68,7 +67,7 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
- android:src="@drawable/ic_remove_circle"
+ android:src="@drawable/ic_qs_dnd_on"
android:tint="@android:color/white"
android:visibility="gone"
android:contentDescription="@string/dream_overlay_status_bar_priority_mode" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index df16b0d45228d..6ec6c23849626 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2421,6 +2421,9 @@
Assistant guest mode enabled
Camera and mic are off
-
- There are notifications
+
+ {count, plural,
+ =1 {# notification}
+ other {# notifications}
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index 2d969206b4685..d2ab61149d261 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -16,23 +16,44 @@
package com.android.systemui.dreams;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageView;
import androidx.constraintlayout.widget.ConstraintLayout;
-import com.android.internal.util.Preconditions;
import com.android.systemui.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
/**
* {@link DreamOverlayStatusBarView} is the view responsible for displaying the status bar in a
* dream. The status bar displays conditional status icons such as "priority mode" and "no wifi".
*/
public class DreamOverlayStatusBarView extends ConstraintLayout {
- private ImageView mWifiStatusView;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "STATUS_ICON_" }, value = {
+ STATUS_ICON_NOTIFICATIONS,
+ STATUS_ICON_WIFI_UNAVAILABLE,
+ STATUS_ICON_ALARM_SET,
+ STATUS_ICON_MIC_CAMERA_DISABLED,
+ STATUS_ICON_PRIORITY_MODE_ON
+ })
+ public @interface StatusIconType {}
+ public static final int STATUS_ICON_NOTIFICATIONS = 0;
+ public static final int STATUS_ICON_WIFI_UNAVAILABLE = 1;
+ public static final int STATUS_ICON_ALARM_SET = 2;
+ public static final int STATUS_ICON_MIC_CAMERA_DISABLED = 3;
+ public static final int STATUS_ICON_PRIORITY_MODE_ON = 4;
+
+ private final Map mStatusIcons = new HashMap<>();
public DreamOverlayStatusBarView(Context context) {
this(context, null);
@@ -55,16 +76,35 @@ public class DreamOverlayStatusBarView extends ConstraintLayout {
protected void onFinishInflate() {
super.onFinishInflate();
- mWifiStatusView = Preconditions.checkNotNull(findViewById(R.id.dream_overlay_wifi_status),
- "R.id.dream_overlay_wifi_status must not be null");
+ mStatusIcons.put(STATUS_ICON_WIFI_UNAVAILABLE,
+ fetchStatusIconForResId(R.id.dream_overlay_wifi_status));
+ mStatusIcons.put(STATUS_ICON_ALARM_SET,
+ fetchStatusIconForResId(R.id.dream_overlay_alarm_set));
+ mStatusIcons.put(STATUS_ICON_MIC_CAMERA_DISABLED,
+ fetchStatusIconForResId(R.id.dream_overlay_camera_mic_off));
+ mStatusIcons.put(STATUS_ICON_NOTIFICATIONS,
+ fetchStatusIconForResId(R.id.dream_overlay_notification_indicator));
+ mStatusIcons.put(STATUS_ICON_PRIORITY_MODE_ON,
+ fetchStatusIconForResId(R.id.dream_overlay_priority_mode));
}
- /**
- * Whether to show the wifi status icon.
- * @param show True if the wifi status icon should be shown.
- */
- void showWifiStatus(boolean show) {
- // Only show the wifi status icon when wifi isn't available.
- mWifiStatusView.setVisibility(show ? View.VISIBLE : View.GONE);
+ void showIcon(@StatusIconType int iconType, boolean show) {
+ showIcon(iconType, show, null);
+ }
+
+ void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) {
+ View icon = mStatusIcons.get(iconType);
+ if (icon == null) {
+ return;
+ }
+ if (show && contentDescription != null) {
+ icon.setContentDescription(contentDescription);
+ }
+ icon.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+
+ private View fetchStatusIconForResId(int resId) {
+ final View statusIcon = findViewById(resId);
+ return Objects.requireNonNull(statusIcon);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 32b2309ee83b9..a25a7423770ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,19 +16,35 @@
package com.android.systemui.dreams;
-import android.annotation.IntDef;
+import android.app.AlarmManager;
+import android.content.res.Resources;
+import android.hardware.SensorPrivacyManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.NotificationListenerService.RankingMap;
+import android.service.notification.StatusBarNotification;
+import android.text.format.DateFormat;
+import android.util.PluralsMessageFormatter;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
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.NextAlarmController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.time.DateFormatUtil;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.util.Locale;
+import java.util.Map;
import javax.inject.Inject;
@@ -37,19 +53,15 @@ import javax.inject.Inject;
*/
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayStatusBarViewController extends ViewController {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "WIFI_STATUS_" }, value = {
- WIFI_STATUS_UNKNOWN,
- WIFI_STATUS_UNAVAILABLE,
- WIFI_STATUS_AVAILABLE
- })
- private @interface WifiStatus {}
- private static final int WIFI_STATUS_UNKNOWN = 0;
- private static final int WIFI_STATUS_UNAVAILABLE = 1;
- private static final int WIFI_STATUS_AVAILABLE = 2;
-
private final ConnectivityManager mConnectivityManager;
private final TouchInsetManager.TouchInsetSession mTouchInsetSession;
+ private final NextAlarmController mNextAlarmController;
+ private final AlarmManager mAlarmManager;
+ private final Resources mResources;
+ private final DateFormatUtil mDateFormatUtil;
+ private final IndividualSensorPrivacyController mSensorPrivacyController;
+ private final NotificationListener mNotificationListener;
+ private final ZenModeController mZenModeController;
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
@@ -59,61 +71,183 @@ public class DreamOverlayStatusBarViewController extends ViewController updateMicCameraBlockedStatusIcon();
+
+ private final NextAlarmController.NextAlarmChangeCallback mNextAlarmCallback =
+ 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() {
+ @Override
+ public void onZenChanged(int zen) {
+ updatePriorityModeStatusIcon();
+ }
+ };
@Inject
public DreamOverlayStatusBarViewController(
DreamOverlayStatusBarView view,
+ @Main Resources resources,
ConnectivityManager connectivityManager,
- TouchInsetManager.TouchInsetSession touchInsetSession) {
+ TouchInsetManager.TouchInsetSession touchInsetSession,
+ AlarmManager alarmManager,
+ NextAlarmController nextAlarmController,
+ DateFormatUtil dateFormatUtil,
+ IndividualSensorPrivacyController sensorPrivacyController,
+ NotificationListener notificationListener,
+ ZenModeController zenModeController) {
super(view);
+ mResources = resources;
mConnectivityManager = connectivityManager;
mTouchInsetSession = touchInsetSession;
+ mAlarmManager = alarmManager;
+ mNextAlarmController = nextAlarmController;
+ mDateFormatUtil = dateFormatUtil;
+ mSensorPrivacyController = sensorPrivacyController;
+ mNotificationListener = notificationListener;
+ 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
protected void onViewAttached() {
- mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+ updateNotificationsStatusIcon();
+
+ mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
+ updateWifiUnavailableStatusIcon();
+
+ mNextAlarmController.addCallback(mNextAlarmCallback);
+ updateAlarmStatusIcon();
+
+ mSensorPrivacyController.addCallback(mSensorCallback);
+ updateMicCameraBlockedStatusIcon();
+
+ mZenModeController.addCallback(mZenModeCallback);
+ updatePriorityModeStatusIcon();
- NetworkCapabilities capabilities =
- mConnectivityManager.getNetworkCapabilities(
- mConnectivityManager.getActiveNetwork());
- onWifiAvailabilityChanged(
- capabilities != null
- && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
mTouchInsetSession.addViewToTracking(mView);
}
@Override
protected void onViewDetached() {
+ mZenModeController.removeCallback(mZenModeCallback);
+ mSensorPrivacyController.removeCallback(mSensorCallback);
+ mNextAlarmController.removeCallback(mNextAlarmCallback);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
mTouchInsetSession.clear();
}
- /**
- * Wifi availability has changed. Update the wifi status icon as appropriate.
- * @param available Whether wifi is available.
- */
- private void onWifiAvailabilityChanged(boolean available) {
- final int newWifiStatus = available ? WIFI_STATUS_AVAILABLE : WIFI_STATUS_UNAVAILABLE;
- if (mWifiStatus != newWifiStatus) {
- mWifiStatus = newWifiStatus;
- mView.showWifiStatus(mWifiStatus == WIFI_STATUS_UNAVAILABLE);
+ private void updateWifiUnavailableStatusIcon() {
+ final NetworkCapabilities capabilities =
+ mConnectivityManager.getNetworkCapabilities(
+ mConnectivityManager.getActiveNetwork());
+ final boolean available = capabilities != null
+ && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ mView.showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, !available);
+ }
+
+ private void updateAlarmStatusIcon() {
+ final AlarmManager.AlarmClockInfo alarm =
+ mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
+ final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
+ mView.showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET,
+ hasAlarm,
+ hasAlarm ? buildAlarmContentDescription(alarm) : null);
+ }
+
+ private String buildAlarmContentDescription(AlarmManager.AlarmClockInfo alarm) {
+ final String skeleton = mDateFormatUtil.is24HourFormat() ? "EHm" : "Ehma";
+ final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
+ final String dateString = DateFormat.format(pattern, alarm.getTriggerTime()).toString();
+
+ return mResources.getString(R.string.accessibility_quick_settings_alarm, dateString);
+ }
+
+ private void updateMicCameraBlockedStatusIcon() {
+ final boolean micBlocked = mSensorPrivacyController
+ .isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE);
+ final boolean cameraBlocked = mSensorPrivacyController
+ .isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA);
+ mView.showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED,
+ 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;
+ mView.showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS,
+ notificationCount > 0,
+ notificationCount > 0
+ ? buildNotificationsContentDescription(notificationCount)
+ : null);
+ }
+
+ private String buildNotificationsContentDescription(int notificationCount) {
+ return PluralsMessageFormatter.format(
+ mResources,
+ Map.of("count", notificationCount),
+ R.string.dream_overlay_status_bar_notification_indicator);
+ }
+
+ private void updatePriorityModeStatusIcon() {
+ mView.showIcon(
+ DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON,
+ mZenModeController.getZen() != Settings.Global.ZEN_MODE_OFF);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index ad8d44d62a5c6..a32ff801e8248 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -17,19 +17,34 @@
package com.android.systemui.dreams;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
+import android.content.res.Resources;
+import android.hardware.SensorPrivacyManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.touch.TouchInsetManager;
+import com.android.systemui.util.time.DateFormatUtil;
import org.junit.Before;
import org.junit.Test;
@@ -41,6 +56,8 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
+ private static final String NOTIFICATION_INDICATOR_FORMATTER_STRING =
+ "{count, plural, =1 {# notification} other {# notifications}}";
@Mock
DreamOverlayStatusBarView mView;
@@ -52,14 +69,55 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
Network mNetwork;
@Mock
TouchInsetManager.TouchInsetSession mTouchSession;
+ @Mock
+ Resources mResources;
+ @Mock
+ AlarmManager mAlarmManager;
+ @Mock
+ AlarmManager.AlarmClockInfo mAlarmClockInfo;
+ @Mock
+ NextAlarmController mNextAlarmController;
+ @Mock
+ DateFormatUtil mDateFormatUtil;
+ @Mock
+ IndividualSensorPrivacyController mSensorPrivacyController;
+ @Mock
+ StatusBarNotification mStatusBarNotification;
+ @Mock
+ NotificationListenerService.RankingMap mRankingMap;
+ @Mock
+ NotificationListener mNotificationListener;
+ @Mock
+ ZenModeController mZenModeController;
DreamOverlayStatusBarViewController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mController = new DreamOverlayStatusBarViewController(mView, mConnectivityManager,
- mTouchSession);
+
+ when(mResources.getString(R.string.dream_overlay_status_bar_notification_indicator))
+ .thenReturn(NOTIFICATION_INDICATOR_FORMATTER_STRING);
+
+ mController = new DreamOverlayStatusBarViewController(
+ mView,
+ mResources,
+ mConnectivityManager,
+ mTouchSession,
+ mAlarmManager,
+ mNextAlarmController,
+ mDateFormatUtil,
+ mSensorPrivacyController,
+ mNotificationListener,
+ mZenModeController);
+ }
+
+ @Test
+ public void testOnViewAttachedAddsCallbacks() {
+ mController.onViewAttached();
+ verify(mNextAlarmController).addCallback(any());
+ verify(mSensorPrivacyController).addCallback(any());
+ verify(mZenModeController).addCallback(any());
}
@Test
@@ -71,28 +129,97 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
}
@Test
- public void testOnViewAttachedShowsWifiStatusWhenWifiUnavailable() {
+ public void testOnViewAttachedShowsWifiIconWhenWifiUnavailable() {
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(false);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showWifiStatus(true);
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
}
@Test
- public void testOnViewAttachedHidesWifiStatusWhenWifiAvailable() {
+ public void testOnViewAttachedHidesWifiIconWhenWifiAvailable() {
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(true);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
- verify(mView).showWifiStatus(false);
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
}
@Test
- public void testOnViewAttachedShowsWifiStatusWhenNetworkCapabilitiesUnavailable() {
+ public void testOnViewAttachedShowsWifiIconWhenNetworkCapabilitiesUnavailable() {
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(null);
mController.onViewAttached();
- verify(mView).showWifiStatus(true);
+ }
+
+ @Test
+ public void testOnViewAttachedShowsAlarmIconWhenAlarmExists() {
+ when(mAlarmClockInfo.getTriggerTime()).thenReturn(1L);
+ when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(mAlarmClockInfo);
+ mController.onViewAttached();
+ verify(mView).showIcon(
+ eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(true), any());
+ }
+
+ @Test
+ public void testOnViewAttachedHidesAlarmIconWhenNoAlarmExists() {
+ when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(null);
+ mController.onViewAttached();
+ verify(mView).showIcon(
+ eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(false), isNull());
+ }
+
+ @Test
+ public void testOnViewAttachedShowsMicCameraIconWhenDisabled() {
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE))
+ .thenReturn(true);
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
+ .thenReturn(true);
+ mController.onViewAttached();
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ }
+
+ @Test
+ public void testOnViewAttachedHidesMicCameraIconWhenEnabled() {
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE))
+ .thenReturn(false);
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
+ .thenReturn(false);
+ mController.onViewAttached();
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ }
+
+ @Test
+ public void testOnViewAttachedShowsNotificationsIconWhenNotificationsExist() {
+ StatusBarNotification[] notifications = { mStatusBarNotification };
+ when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
+ mController.onViewAttached();
+ verify(mView).showIcon(
+ eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
+ }
+
+ @Test
+ public void testOnViewAttachedHidesNotificationsIconWhenNoNotificationsExist() {
+ when(mNotificationListener.getActiveNotifications()).thenReturn(null);
+ mController.onViewAttached();
+ verify(mView).showIcon(
+ eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), isNull());
+ }
+
+ @Test
+ public void testOnViewAttachedShowsPriorityModeIconWhenEnabled() {
+ when(mZenModeController.getZen()).thenReturn(
+ Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mController.onViewAttached();
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ }
+
+ @Test
+ public void testOnViewAttachedHidesPriorityModeIconWhenDisabled() {
+ when(mZenModeController.getZen()).thenReturn(
+ Settings.Global.ZEN_MODE_OFF);
+ mController.onViewAttached();
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
}
@Test
@@ -103,10 +230,19 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
}
@Test
- public void testWifiStatusHiddenWhenWifiBecomesAvailable() {
- // Make sure wifi starts out unavailable when onViewAttached is called.
+ public void testOnViewDetachedRemovesCallbacks() {
+ mController.onViewDetached();
+ verify(mNextAlarmController).removeCallback(any());
+ verify(mSensorPrivacyController).removeCallback(any());
+ verify(mZenModeController).removeCallback(any());
+ }
+
+ @Test
+ public void testWifiIconHiddenWhenWifiBecomesAvailable() {
+ // Make sure wifi starts out unavailable when onViewAttached is called, and then returns
+ // true on the second query.
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
- .thenReturn(false);
+ .thenReturn(false).thenReturn(true);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
@@ -114,14 +250,15 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onAvailable(mNetwork);
- verify(mView).showWifiStatus(false);
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
}
@Test
- public void testWifiStatusShownWhenWifiBecomesUnavailable() {
- // Make sure wifi starts out available when onViewAttached is called.
+ public void testWifiIconShownWhenWifiBecomesUnavailable() {
+ // Make sure wifi starts out available when onViewAttached is called, then returns false
+ // on the second query.
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
- .thenReturn(true);
+ .thenReturn(true).thenReturn(false);
when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(mNetworkCapabilities);
mController.onViewAttached();
@@ -129,11 +266,11 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mConnectivityManager).registerNetworkCallback(any(), callbackCapture.capture());
callbackCapture.getValue().onLost(mNetwork);
- verify(mView).showWifiStatus(true);
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, true);
}
@Test
- public void testWifiStatusHiddenWhenCapabilitiesChange() {
+ public void testWifiIconHiddenWhenCapabilitiesChange() {
// Make sure wifi starts out unavailable when onViewAttached is called.
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(false);
@@ -146,6 +283,102 @@ public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
.thenReturn(true);
callbackCapture.getValue().onCapabilitiesChanged(mNetwork, mNetworkCapabilities);
- verify(mView).showWifiStatus(false);
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_WIFI_UNAVAILABLE, false);
+ }
+
+ @Test
+ public void testNotificationsIconShownWhenNotificationAdded() {
+ mController.onViewAttached();
+
+ StatusBarNotification[] notifications = { mStatusBarNotification };
+ when(mNotificationListener.getActiveNotifications()).thenReturn(notifications);
+
+ final ArgumentCaptor callbackCapture =
+ ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class);
+ verify(mNotificationListener).addNotificationHandler(callbackCapture.capture());
+ callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap);
+
+ verify(mView).showIcon(
+ eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(true), any());
+ }
+
+ @Test
+ public void testNotificationsIconHiddenWhenLastNotificationRemoved() {
+ StatusBarNotification[] notifications = { mStatusBarNotification };
+ when(mNotificationListener.getActiveNotifications()).thenReturn(notifications)
+ .thenReturn(null);
+ mController.onViewAttached();
+
+ final ArgumentCaptor callbackCapture =
+ ArgumentCaptor.forClass(NotificationListener.NotificationHandler.class);
+ verify(mNotificationListener).addNotificationHandler(callbackCapture.capture());
+ callbackCapture.getValue().onNotificationPosted(mStatusBarNotification, mRankingMap);
+
+ verify(mView).showIcon(
+ eq(DreamOverlayStatusBarView.STATUS_ICON_NOTIFICATIONS), eq(false), any());
+ }
+
+ @Test
+ public void testMicCameraIconShownWhenSensorsBlocked() {
+ mController.onViewAttached();
+
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE))
+ .thenReturn(true);
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
+ .thenReturn(true);
+
+ final ArgumentCaptor callbackCapture =
+ ArgumentCaptor.forClass(IndividualSensorPrivacyController.Callback.class);
+ verify(mSensorPrivacyController).addCallback(callbackCapture.capture());
+ callbackCapture.getValue().onSensorBlockedChanged(
+ SensorPrivacyManager.Sensors.MICROPHONE, true);
+
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, true);
+ }
+
+ @Test
+ public void testMicCameraIconHiddenWhenSensorsNotBlocked() {
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.MICROPHONE))
+ .thenReturn(true).thenReturn(false);
+ when(mSensorPrivacyController.isSensorBlocked(SensorPrivacyManager.Sensors.CAMERA))
+ .thenReturn(true).thenReturn(false);
+ mController.onViewAttached();
+
+ final ArgumentCaptor callbackCapture =
+ ArgumentCaptor.forClass(IndividualSensorPrivacyController.Callback.class);
+ verify(mSensorPrivacyController).addCallback(callbackCapture.capture());
+ callbackCapture.getValue().onSensorBlockedChanged(
+ SensorPrivacyManager.Sensors.MICROPHONE, false);
+
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_MIC_CAMERA_DISABLED, false);
+ }
+
+ @Test
+ public void testPriorityModeIconShownWhenZenModeEnabled() {
+ mController.onViewAttached();
+
+ when(mZenModeController.getZen()).thenReturn(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
+
+ final ArgumentCaptor callbackCapture =
+ ArgumentCaptor.forClass(ZenModeController.Callback.class);
+ verify(mZenModeController).addCallback(callbackCapture.capture());
+ callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS);
+
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, true);
+ }
+
+ @Test
+ public void testPriorityModeIconHiddenWhenZenModeDisabled() {
+ when(mZenModeController.getZen()).thenReturn(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS)
+ .thenReturn(Settings.Global.ZEN_MODE_OFF);
+ mController.onViewAttached();
+
+
+ final ArgumentCaptor callbackCapture =
+ ArgumentCaptor.forClass(ZenModeController.Callback.class);
+ verify(mZenModeController).addCallback(callbackCapture.capture());
+ callbackCapture.getValue().onZenChanged(Settings.Global.ZEN_MODE_OFF);
+
+ verify(mView).showIcon(DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false);
}
}