1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.phone; 18 19 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 20 import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; 21 22 import static junit.framework.Assert.assertFalse; 23 import static junit.framework.Assert.assertTrue; 24 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.platform.test.annotations.DisableFlags; 29 import android.testing.TestableLooper.RunWithLooper; 30 import android.view.Display; 31 import android.view.View; 32 import android.view.ViewPropertyAnimator; 33 import android.view.WindowInsets; 34 import android.view.WindowManager; 35 36 import androidx.lifecycle.Observer; 37 import androidx.test.ext.junit.runners.AndroidJUnit4; 38 import androidx.test.filters.SmallTest; 39 40 import com.android.systemui.SysuiTestCase; 41 import com.android.systemui.statusbar.CommandQueue; 42 import com.android.systemui.statusbar.notification.collection.NotifLiveData; 43 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore; 44 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor; 45 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.mockito.ArgumentCaptor; 50 import org.mockito.Captor; 51 import org.mockito.Mock; 52 import org.mockito.MockitoAnnotations; 53 54 import java.util.Objects; 55 56 @SmallTest 57 @RunWith(AndroidJUnit4.class) 58 @RunWithLooper 59 @DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME) 60 public class LegacyLightsOutNotifControllerTest extends SysuiTestCase { 61 private static final int LIGHTS_ON = 0; 62 private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS; 63 64 @Mock private NotifLiveData<Boolean> mHasActiveNotifs; 65 @Mock private NotifLiveDataStore mNotifLiveDataStore; 66 @Mock private CommandQueue mCommandQueue; 67 @Mock private WindowManager mWindowManager; 68 @Mock private Display mDisplay; 69 70 @Captor private ArgumentCaptor<Observer<Boolean>> mObserverCaptor; 71 @Captor private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksCaptor; 72 73 private View mLightsOutView; 74 private LegacyLightsOutNotifController mLightsOutNotifController; 75 private int mDisplayId; 76 private Observer<Boolean> mHaActiveNotifsObserver; 77 private CommandQueue.Callbacks mCallbacks; 78 79 @Before setUp()80 public void setUp() throws Exception { 81 MockitoAnnotations.initMocks(this); 82 mDisplayId = mContext.getDisplayId(); 83 mLightsOutView = new View(mContext); 84 when(mWindowManager.getDefaultDisplay()).thenReturn(mDisplay); 85 when(mDisplay.getDisplayId()).thenReturn(mDisplayId); 86 when(mNotifLiveDataStore.getHasActiveNotifs()).thenReturn(mHasActiveNotifs); 87 when(mHasActiveNotifs.getValue()).thenReturn(false); 88 89 mLightsOutNotifController = new LegacyLightsOutNotifController( 90 mLightsOutView, 91 mWindowManager, 92 mNotifLiveDataStore, 93 mCommandQueue); 94 mLightsOutNotifController.init(); 95 mLightsOutNotifController.onViewAttached(); 96 97 // Capture the entry listener object so we can simulate events in tests below 98 verify(mHasActiveNotifs).addSyncObserver(mObserverCaptor.capture()); 99 mHaActiveNotifsObserver = Objects.requireNonNull(mObserverCaptor.getValue()); 100 101 // Capture the callback object so we can simulate callback events in tests below 102 verify(mCommandQueue).addCallback(mCallbacksCaptor.capture()); 103 mCallbacks = Objects.requireNonNull(mCallbacksCaptor.getValue()); 104 } 105 106 @Test testAreLightsOut_lightsOut()107 public void testAreLightsOut_lightsOut() { 108 mCallbacks.onSystemBarAttributesChanged( 109 mDisplayId /* display id */, 110 LIGHTS_OUT /* appearance */, 111 null /* appearanceRegions */, 112 false /* navbarColorManagedByIme */, 113 BEHAVIOR_DEFAULT, 114 WindowInsets.Type.defaultVisible(), 115 null /* packageName */, 116 null /* letterboxDetails */); 117 assertTrue(mLightsOutNotifController.areLightsOut()); 118 } 119 120 @Test testAreLightsOut_lightsOn()121 public void testAreLightsOut_lightsOn() { 122 mCallbacks.onSystemBarAttributesChanged( 123 mDisplayId /* display id */, 124 LIGHTS_ON /* appearance */, 125 null /* appearanceRegions */, 126 false /* navbarColorManagedByIme */, 127 BEHAVIOR_DEFAULT, 128 WindowInsets.Type.defaultVisible(), 129 null /* packageName */, 130 null /* letterboxDetails */); 131 assertFalse(mLightsOutNotifController.areLightsOut()); 132 } 133 134 @Test testIsShowingDot_visible()135 public void testIsShowingDot_visible() { 136 mLightsOutView.setVisibility(View.VISIBLE); 137 mLightsOutView.setAlpha(1.0f); 138 assertTrue(mLightsOutNotifController.isShowingDot()); 139 } 140 141 @Test testIsShowingDot_gone()142 public void testIsShowingDot_gone() { 143 mLightsOutView.setVisibility(View.GONE); 144 mLightsOutView.setAlpha(0f); 145 assertFalse(mLightsOutNotifController.isShowingDot()); 146 } 147 148 @Test testLightsOut_withNotifs_onSystemBarAttributesChanged()149 public void testLightsOut_withNotifs_onSystemBarAttributesChanged() { 150 // GIVEN active visible notifications 151 when(mHasActiveNotifs.getValue()).thenReturn(true); 152 153 // WHEN lights out 154 mCallbacks.onSystemBarAttributesChanged( 155 mDisplayId /* display id */, 156 LIGHTS_OUT /* appearance */, 157 null /* appearanceRegions */, 158 false /* navbarColorManagedByIme */, 159 BEHAVIOR_DEFAULT, 160 WindowInsets.Type.defaultVisible(), 161 null /* packageName */, 162 null /* letterboxDetails */); 163 164 // THEN we should show dot 165 assertTrue(mLightsOutNotifController.shouldShowDot()); 166 assertIsShowingDot(true); 167 } 168 169 @Test testLightsOut_withoutNotifs_onSystemBarAttributesChanged()170 public void testLightsOut_withoutNotifs_onSystemBarAttributesChanged() { 171 // GIVEN no active visible notifications 172 when(mHasActiveNotifs.getValue()).thenReturn(false); 173 174 // WHEN lights out 175 mCallbacks.onSystemBarAttributesChanged( 176 mDisplayId /* display id */, 177 LIGHTS_OUT /* appearance */, 178 null /* appearanceRegions */, 179 false /* navbarColorManagedByIme */, 180 BEHAVIOR_DEFAULT, 181 WindowInsets.Type.defaultVisible(), 182 null /* packageName */, 183 null /* letterboxDetails */); 184 185 // THEN we shouldn't show the dot 186 assertFalse(mLightsOutNotifController.shouldShowDot()); 187 assertIsShowingDot(false); 188 } 189 190 @Test testLightsOn_afterLightsOut_onSystemBarAttributesChanged()191 public void testLightsOn_afterLightsOut_onSystemBarAttributesChanged() { 192 // GIVEN active visible notifications 193 when(mHasActiveNotifs.getValue()).thenReturn(true); 194 195 // WHEN lights on 196 mCallbacks.onSystemBarAttributesChanged( 197 mDisplayId /* display id */, 198 LIGHTS_ON /* appearance */, 199 null /* appearanceRegions */, 200 false /* navbarColorManagedByIme */, 201 BEHAVIOR_DEFAULT, 202 WindowInsets.Type.defaultVisible(), 203 null /* packageName */, 204 null /* letterboxDetails */); 205 206 // THEN we shouldn't show the dot 207 assertFalse(mLightsOutNotifController.shouldShowDot()); 208 assertIsShowingDot(false); 209 } 210 211 @Test testEntryAdded()212 public void testEntryAdded() { 213 // GIVEN no visible notifications and lights out 214 when(mHasActiveNotifs.getValue()).thenReturn(false); 215 mLightsOutNotifController.mAppearance = LIGHTS_OUT; 216 mLightsOutNotifController.updateLightsOutView(); 217 assertIsShowingDot(false); 218 219 // WHEN an active notification is added 220 when(mHasActiveNotifs.getValue()).thenReturn(true); 221 assertTrue(mLightsOutNotifController.shouldShowDot()); 222 mHaActiveNotifsObserver.onChanged(true); 223 224 // THEN we should see the dot view 225 assertIsShowingDot(true); 226 } 227 228 @Test testEntryRemoved()229 public void testEntryRemoved() { 230 // GIVEN a visible notification and lights out 231 when(mHasActiveNotifs.getValue()).thenReturn(true); 232 mLightsOutNotifController.mAppearance = LIGHTS_OUT; 233 mLightsOutNotifController.updateLightsOutView(); 234 assertIsShowingDot(true); 235 236 // WHEN all active notifications are removed 237 when(mHasActiveNotifs.getValue()).thenReturn(false); 238 assertFalse(mLightsOutNotifController.shouldShowDot()); 239 mHaActiveNotifsObserver.onChanged(false); 240 241 // THEN we shouldn't see the dot view 242 assertIsShowingDot(false); 243 } 244 assertIsShowingDot(boolean isShowing)245 private void assertIsShowingDot(boolean isShowing) { 246 // cancel the animation so we can check the end state 247 final ViewPropertyAnimator animation = mLightsOutView.animate(); 248 if (animation != null) { 249 animation.cancel(); 250 } 251 252 if (isShowing) { 253 assertTrue(mLightsOutNotifController.isShowingDot()); 254 } else { 255 assertFalse(mLightsOutNotifController.isShowingDot()); 256 } 257 } 258 } 259