diff options
9 files changed, 448 insertions, 67 deletions
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index ab63b06cffa9..c1515fc30b60 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -116,6 +116,7 @@ import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -306,6 +307,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, SuperStatusBarViewFactory superStatusBarViewFactory, + LightsOutNotifController lightsOutNotifController, /* Car Settings injected components. */ CarNavigationBarController carNavigationBarController) { super( @@ -376,6 +378,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt pluginManager, remoteInputUriController, dividerOptional, + lightsOutNotifController, superStatusBarViewFactory); mScrimController = scrimController; mCarNavigationBarController = carNavigationBarController; diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index 7de2212eef4d..9b91843576ce 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -71,6 +71,7 @@ import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.LockscreenWallpaper; import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -175,6 +176,7 @@ public class CarStatusBarModule { RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, SuperStatusBarViewFactory superStatusBarViewFactory, + LightsOutNotifController lightsOutNotifController, CarNavigationBarController carNavigationBarController) { return new CarStatusBar( context, @@ -244,6 +246,7 @@ public class CarStatusBarModule { remoteInputUriController, dividerOptional, superStatusBarViewFactory, + lightsOutNotifController, carNavigationBarController); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java new file mode 100644 index 000000000000..93887a6617f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2019 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.phone; + +import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.annotation.Nullable; +import android.view.View; +import android.view.WindowInsetsController; +import android.view.WindowManager; +import android.view.animation.AccelerateInterpolator; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.statusbar.NotificationVisibility; +import com.android.internal.view.AppearanceRegion; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.notification.NotificationEntryListener; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Apps can request a low profile mode {@link View.SYSTEM_UI_FLAG_LOW_PROFILE} + * where status bar and navigation icons dim. In this mode, a notification dot appears + * where the notification icons would appear if they would be shown outside of this mode. + * + * This controller shows and hides the notification dot in the status bar to indicate + * whether there are notifications when the device is in {@link View.SYSTEM_UI_FLAG_LOW_PROFILE}. + */ +@Singleton +public class LightsOutNotifController { + private final CommandQueue mCommandQueue; + private final NotificationEntryManager mEntryManager; + private final WindowManager mWindowManager; + + /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */ + @VisibleForTesting @WindowInsetsController.Appearance int mAppearance; + + private int mDisplayId; + private View mLightsOutNotifView; + + @Inject + LightsOutNotifController(WindowManager windowManager, + NotificationEntryManager entryManager, + CommandQueue commandQueue) { + mWindowManager = windowManager; + mEntryManager = entryManager; + mCommandQueue = commandQueue; + } + + /** + * Sets the notification dot view after it is created in the StatusBar. + * This is the view this controller will show and hide depending on whether: + * 1. there are active notifications + * 2. an app has requested {@link View.SYSTEM_UI_FLAG_LOW_PROFILE} + */ + void setLightsOutNotifView(View lightsOutNotifView) { + destroy(); + mLightsOutNotifView = lightsOutNotifView; + + if (mLightsOutNotifView != null) { + mLightsOutNotifView.setVisibility(View.GONE); + mLightsOutNotifView.setAlpha(0f); + init(); + } + } + + private void destroy() { + mEntryManager.removeNotificationEntryListener(mEntryListener); + mCommandQueue.removeCallback(mCallback); + } + + private void init() { + mDisplayId = mWindowManager.getDefaultDisplay().getDisplayId(); + mEntryManager.addNotificationEntryListener(mEntryListener); + mCommandQueue.addCallback(mCallback); + + updateLightsOutView(); + } + + private boolean hasActiveNotifications() { + return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty(); + } + + @VisibleForTesting + void updateLightsOutView() { + if (mLightsOutNotifView == null) { + return; + } + + final boolean showDot = shouldShowDot(); + if (showDot != isShowingDot()) { + if (showDot) { + mLightsOutNotifView.setAlpha(0f); + mLightsOutNotifView.setVisibility(View.VISIBLE); + } + + mLightsOutNotifView.animate() + .alpha(showDot ? 1 : 0) + .setDuration(showDot ? 750 : 250) + .setInterpolator(new AccelerateInterpolator(2.0f)) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator a) { + mLightsOutNotifView.setAlpha(showDot ? 1 : 0); + mLightsOutNotifView.setVisibility(showDot ? View.VISIBLE : View.GONE); + } + }) + .start(); + } + } + + @VisibleForTesting + boolean isShowingDot() { + return mLightsOutNotifView.getVisibility() == View.VISIBLE + && mLightsOutNotifView.getAlpha() == 1.0f; + } + + @VisibleForTesting + boolean shouldShowDot() { + return hasActiveNotifications() && areLightsOut(); + } + + @VisibleForTesting + boolean areLightsOut() { + return 0 != (mAppearance & APPEARANCE_LOW_PROFILE_BARS); + } + + private final CommandQueue.Callbacks mCallback = new CommandQueue.Callbacks() { + @Override + public void onSystemBarAppearanceChanged(int displayId, + @WindowInsetsController.Appearance int appearance, + AppearanceRegion[] appearanceRegions, + boolean navbarColorManagedByIme) { + if (displayId != mDisplayId) { + return; + } + mAppearance = appearance; + updateLightsOutView(); + } + }; + + private final NotificationEntryListener mEntryListener = new NotificationEntryListener() { + // Cares about notifications post-filtering + @Override + public void onNotificationAdded(NotificationEntry entry) { + updateLightsOutView(); + } + + @Override + public void onPostEntryUpdated(NotificationEntry entry) { + updateLightsOutView(); + } + + @Override + public void onEntryRemoved(@Nullable NotificationEntry entry, + NotificationVisibility visibility, boolean removedByUser) { + updateLightsOutView(); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java index 70cd43a5e17a..f359fe7cfec4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java @@ -142,12 +142,6 @@ public interface ShadeController { void onLaunchAnimationCancelled(); /** - * When notifications update, give the shade controller a chance to do thing in response to - * the new data set - */ - void updateAreThereNotifications(); - - /** * Callback to notify the shade controller that a {@link ActivatableNotificationView} has become * inactive */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 57dcf77b9d6b..6be881669146 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -47,8 +47,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARE import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING; import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -117,7 +115,6 @@ import android.view.WindowInsetsController.Appearance; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; -import android.view.animation.AccelerateInterpolator; import android.widget.DateTimeView; import com.android.internal.annotations.VisibleForTesting; @@ -399,6 +396,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final RemoteInputUriController mRemoteInputUriController; private final Optional<Divider> mDividerOptional; private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; + private final LightsOutNotifController mLightsOutNotifController; // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window @@ -704,6 +702,7 @@ public class StatusBar extends SystemUI implements DemoMode, PluginManager pluginManager, RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, + LightsOutNotifController lightsOutNotifController, SuperStatusBarViewFactory superStatusBarViewFactory) { super(context); mFeatureFlags = featureFlags; @@ -774,7 +773,7 @@ public class StatusBar extends SystemUI implements DemoMode, mDividerOptional = dividerOptional; mSuperStatusBarViewFactory = superStatusBarViewFactory; - + mLightsOutNotifController = lightsOutNotifController; mBubbleExpandListener = (isExpanding, key) -> { mEntryManager.updateNotifications("onBubbleExpandChanged"); @@ -928,7 +927,6 @@ public class StatusBar extends SystemUI implements DemoMode, mConfigurationController.addCallback(this); // set the initial view visibility - Dependency.get(InitController.class).addPostInitTask(this::updateAreThereNotifications); int disabledFlags1 = result.mDisabledFlags1; int disabledFlags2 = result.mDisabledFlags2; Dependency.get(InitController.class).addPostInitTask( @@ -1057,8 +1055,10 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController, mKeyguardBypassController, mKeyguardStateController, mWakeUpCoordinator, mCommandQueue); mHeadsUpAppearanceController.readFrom(oldController); + + mLightsOutNotifController.setLightsOutNotifView( + mStatusBarView.findViewById(R.id.notification_lights_out)); mStatusBarWindowViewController.setStatusBarView(mStatusBarView); - updateAreThereNotifications(); checkBarModes(); }).getFragmentManager() .beginTransaction() @@ -1546,38 +1546,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - public void updateAreThereNotifications() { - if (SPEW) { - final boolean clearable = hasActiveNotifications() && - mNotificationPanel.hasActiveClearableNotifications(); - Log.d(TAG, "updateAreThereNotifications: N=" + - mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" + - hasActiveNotifications() + " clearable=" + clearable); - } - - if (mStatusBarView != null) { - final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); - final boolean showDot = hasActiveNotifications() && !areLightsOn(); - if (showDot != (nlo.getAlpha() == 1.0f)) { - if (showDot) { - nlo.setAlpha(0f); - nlo.setVisibility(View.VISIBLE); - } - nlo.animate() - .alpha(showDot ? 1 : 0) - .setDuration(showDot ? 750 : 250) - .setInterpolator(new AccelerateInterpolator(2.0f)) - .setListener(showDot ? null : new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator _a) { - nlo.setVisibility(View.GONE); - } - }) - .start(); - } - } - } - private void updateReportRejectedTouchVisibility() { if (mReportRejectedTouch == null) { return; @@ -2306,14 +2274,8 @@ public class StatusBar extends SystemUI implements DemoMode, return; } boolean barModeChanged = false; - final int diff = mAppearance ^ appearance; if (mAppearance != appearance) { mAppearance = appearance; - - // update low profile - if ((diff & APPEARANCE_LOW_PROFILE_BARS) != 0) { - updateAreThereNotifications(); - } barModeChanged = updateBarMode(barMode(mTransientShown, appearance)); } mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged, @@ -2494,10 +2456,6 @@ public class StatusBar extends SystemUI implements DemoMode, return mAppImmersive; } - private boolean areLightsOn() { - return 0 == (mAppearance & APPEARANCE_LOW_PROFILE_BARS); - } - public static String viewInfo(View v) { return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() + ") " + v.getWidth() + "x" + v.getHeight() + "]"; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java index 9e0eb3570b59..2364c336b7b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java @@ -161,6 +161,7 @@ public class StatusBarModule { PluginManager pluginManager, RemoteInputUriController remoteInputUriController, Optional<Divider> dividerOptional, + LightsOutNotifController lightsOutNotifController, SuperStatusBarViewFactory superStatusBarViewFactory) { return new StatusBar( context, @@ -230,6 +231,7 @@ public class StatusBarModule { pluginManager, remoteInputUriController, dividerOptional, + lightsOutNotifController, superStatusBarViewFactory); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 02e5ebfe5705..38ff86227733 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -79,7 +79,8 @@ import java.util.ArrayList; public class StatusBarNotificationPresenter implements NotificationPresenter, ConfigurationController.ConfigurationListener, - NotificationRowBinderImpl.BindRowCallback { + NotificationRowBinderImpl.BindRowCallback, + CommandQueue.Callbacks { private final LockscreenGestureLogger mLockscreenGestureLogger = Dependency.get(LockscreenGestureLogger.class); @@ -185,17 +186,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, Dependency.get(InitController.class).addPostInitTask(() -> { NotificationEntryListener notificationEntryListener = new NotificationEntryListener() { @Override - public void onNotificationAdded(NotificationEntry entry) { - // Recalculate the position of the sliding windows and the titles. - mShadeController.updateAreThereNotifications(); - } - - @Override - public void onPostEntryUpdated(NotificationEntry entry) { - mShadeController.updateAreThereNotifications(); - } - - @Override public void onEntryRemoved( @Nullable NotificationEntry entry, NotificationVisibility visibility, @@ -333,7 +323,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } } } - mShadeController.updateAreThereNotifications(); } public boolean hasActiveNotifications() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java new file mode 100644 index 000000000000..64c1b510cbf9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2019 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.phone; + +import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.Display; +import android.view.View; +import android.view.ViewPropertyAnimator; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.notification.NotificationEntryListener; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public class LightsOutNotifControllerTest extends SysuiTestCase { + private static final int LIGHTS_ON = 0; + private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS; + + @Mock private NotificationEntryManager mEntryManager; + @Mock private NotificationData mNotificationData; + @Mock private CommandQueue mCommandQueue; + @Mock private WindowManager mWindowManager; + @Mock private Display mDisplay; + + @Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor; + @Captor private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksCaptor; + + private View mLightsOutView; + private LightsOutNotifController mLightsOutNotifController; + private ArrayList<NotificationEntry> mActiveNotifications = new ArrayList<>(); + private int mDisplayId; + private NotificationEntryListener mEntryListener; + private CommandQueue.Callbacks mCallbacks; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mDisplayId = mContext.getDisplayId(); + mLightsOutView = new View(mContext); + when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); + when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications); + when(mWindowManager.getDefaultDisplay()).thenReturn(mDisplay); + when(mDisplay.getDisplayId()).thenReturn(mDisplayId); + + mLightsOutNotifController = new LightsOutNotifController(mWindowManager, mEntryManager, + mCommandQueue); + mLightsOutNotifController.setLightsOutNotifView(mLightsOutView); + + // Capture the entry listener object so we can simulate events in tests below + verify(mEntryManager).addNotificationEntryListener(mListenerCaptor.capture()); + mEntryListener = checkNotNull(mListenerCaptor.getValue()); + + // Capture the callback object so we can simulate callback events in tests below + verify(mCommandQueue).addCallback(mCallbacksCaptor.capture()); + mCallbacks = checkNotNull(mCallbacksCaptor.getValue()); + } + + @Test + public void testAreLightsOut_lightsOut() { + mCallbacks.onSystemBarAppearanceChanged( + mDisplayId /* display id */, + LIGHTS_OUT /* appearance */, + null /* appearanceRegions */, + false /* navbarColorManagedByIme */); + assertTrue(mLightsOutNotifController.areLightsOut()); + } + + @Test + public void testAreLightsOut_lightsOn() { + mCallbacks.onSystemBarAppearanceChanged( + mDisplayId /* display id */, + LIGHTS_ON /* appearance */, + null /* appearanceRegions */, + false /* navbarColorManagedByIme */); + assertFalse(mLightsOutNotifController.areLightsOut()); + } + + @Test + public void testIsShowingDot_visible() { + mLightsOutView.setVisibility(View.VISIBLE); + mLightsOutView.setAlpha(1.0f); + assertTrue(mLightsOutNotifController.isShowingDot()); + } + + @Test + public void testIsShowingDot_gone() { + mLightsOutView.setVisibility(View.GONE); + mLightsOutView.setAlpha(0f); + assertFalse(mLightsOutNotifController.isShowingDot()); + } + + @Test + public void testLightsOut_withNotifs_onSystemBarAppearanceChanged() { + // GIVEN active visible notifications + mActiveNotifications.add(mock(NotificationEntry.class)); + + // WHEN lights out + mCallbacks.onSystemBarAppearanceChanged( + mDisplayId /* display id */, + LIGHTS_OUT /* appearance */, + null /* appearanceRegions */, + false /* navbarColorManagedByIme */); + + // THEN we should show dot + assertTrue(mLightsOutNotifController.shouldShowDot()); + assertIsShowingDot(true); + } + + @Test + public void testLightsOut_withoutNotifs_onSystemBarAppearanceChanged() { + // GIVEN no active visible notifications + mActiveNotifications.clear(); + + // WHEN lights out + mCallbacks.onSystemBarAppearanceChanged( + mDisplayId /* display id */, + LIGHTS_OUT /* appearance */, + null /* appearanceRegions */, + false /* navbarColorManagedByIme */); + + // THEN we shouldn't show the dot + assertFalse(mLightsOutNotifController.shouldShowDot()); + assertIsShowingDot(false); + } + + @Test + public void testLightsOn_afterLightsOut_onSystemBarAppearanceChanged() { + // GIVEN active visible notifications + mActiveNotifications.add(mock(NotificationEntry.class)); + + // WHEN lights on + mCallbacks.onSystemBarAppearanceChanged( + mDisplayId /* display id */, + LIGHTS_ON /* appearance */, + null /* appearanceRegions */, + false /* navbarColorManagedByIme */); + + // THEN we shouldn't show the dot + assertFalse(mLightsOutNotifController.shouldShowDot()); + assertIsShowingDot(false); + } + + @Test + public void testEntryAdded() { + // GIVEN no visible notifications and lights out + mActiveNotifications.clear(); + mLightsOutNotifController.mAppearance = LIGHTS_OUT; + mLightsOutNotifController.updateLightsOutView(); + assertIsShowingDot(false); + + // WHEN an active notification is added + mActiveNotifications.add(mock(NotificationEntry.class)); + assertTrue(mLightsOutNotifController.shouldShowDot()); + mEntryListener.onNotificationAdded(mock(NotificationEntry.class)); + + // THEN we should see the dot view + assertIsShowingDot(true); + } + + @Test + public void testEntryRemoved() { + // GIVEN a visible notification and lights out + mActiveNotifications.add(mock(NotificationEntry.class)); + mLightsOutNotifController.mAppearance = LIGHTS_OUT; + mLightsOutNotifController.updateLightsOutView(); + assertIsShowingDot(true); + + // WHEN all active notifications are removed + mActiveNotifications.clear(); + assertFalse(mLightsOutNotifController.shouldShowDot()); + mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false); + + // THEN we shouldn't see the dot view + assertIsShowingDot(false); + } + + @Test + public void testEntryUpdated() { + // GIVEN no visible notifications and lights out + mActiveNotifications.clear(); + mLightsOutNotifController.mAppearance = LIGHTS_OUT; + mLightsOutNotifController.updateLightsOutView(); + assertIsShowingDot(false); + + // WHEN an active notification is added + mActiveNotifications.add(mock(NotificationEntry.class)); + assertTrue(mLightsOutNotifController.shouldShowDot()); + mEntryListener.onPostEntryUpdated(mock(NotificationEntry.class)); + + // THEN we should see the dot view + assertIsShowingDot(true); + } + + private void assertIsShowingDot(boolean isShowing) { + // cancel the animation so we can check the end state + final ViewPropertyAnimator animation = mLightsOutView.animate(); + if (animation != null) { + animation.cancel(); + } + + if (isShowing) { + assertTrue(mLightsOutNotifController.isShowingDot()); + } else { + assertFalse(mLightsOutNotifController.isShowingDot()); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 1db926dfd196..7d6f006eb833 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -237,6 +237,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private PluginManager mPluginManager; @Mock private Divider mDivider; @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory; + @Mock private LightsOutNotifController mLightsOutNotifController; @Before public void setup() throws Exception { @@ -376,6 +377,7 @@ public class StatusBarTest extends SysuiTestCase { mPluginManager, mRemoteInputUriController, Optional.of(mDivider), + mLightsOutNotifController, mSuperStatusBarViewFactory); when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn( |