1 /* 2 * Copyright (C) 2022 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.complication; 18 19 import static com.android.systemui.complication.Complication.COMPLICATION_TYPE_HOME_CONTROLS; 20 import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.res.Resources; 33 import android.testing.AndroidTestingRunner; 34 import android.view.View; 35 36 import androidx.test.filters.SmallTest; 37 38 import com.android.internal.logging.UiEventLogger; 39 import com.android.systemui.SysuiTestCase; 40 import com.android.systemui.animation.view.LaunchableImageView; 41 import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent; 42 import com.android.systemui.condition.SelfExecutingMonitor; 43 import com.android.systemui.controls.ControlsServiceInfo; 44 import com.android.systemui.controls.controller.ControlsController; 45 import com.android.systemui.controls.controller.StructureInfo; 46 import com.android.systemui.controls.dagger.ControlsComponent; 47 import com.android.systemui.controls.management.ControlsListingController; 48 import com.android.systemui.dreams.DreamOverlayStateController; 49 import com.android.systemui.plugins.ActivityStarter; 50 import com.android.systemui.shared.condition.Monitor; 51 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.mockito.ArgumentCaptor; 56 import org.mockito.Captor; 57 import org.mockito.Mock; 58 import org.mockito.MockitoAnnotations; 59 60 import java.util.ArrayList; 61 import java.util.List; 62 import java.util.Optional; 63 64 @SmallTest 65 @RunWith(AndroidTestingRunner.class) 66 public class DreamHomeControlsComplicationTest extends SysuiTestCase { 67 @Mock 68 private DreamHomeControlsComplication mComplication; 69 70 @Mock 71 private DreamOverlayStateController mDreamOverlayStateController; 72 73 @Mock 74 private Context mContext; 75 76 @Mock 77 private Resources mResources; 78 79 @Mock 80 private ControlsComponent mControlsComponent; 81 82 @Mock 83 private ControlsController mControlsController; 84 85 @Mock 86 private ControlsListingController mControlsListingController; 87 88 @Mock 89 private DreamHomeControlsComplicationComponent.Factory mComponentFactory; 90 91 @Captor 92 private ArgumentCaptor<ControlsListingController.ControlsListingCallback> mCallbackCaptor; 93 94 @Mock 95 private LaunchableImageView mHomeControlsView; 96 97 @Mock 98 private ActivityStarter mActivityStarter; 99 100 @Mock 101 private UiEventLogger mUiEventLogger; 102 103 @Captor 104 private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor; 105 106 private Monitor mMonitor; 107 108 @Before setup()109 public void setup() { 110 MockitoAnnotations.initMocks(this); 111 112 when(mContext.getString(anyInt())).thenReturn(""); 113 when(mControlsComponent.getControlsController()).thenReturn( 114 Optional.of(mControlsController)); 115 when(mControlsComponent.getControlsListingController()).thenReturn( 116 Optional.of(mControlsListingController)); 117 when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE); 118 119 mMonitor = SelfExecutingMonitor.createInstance(); 120 } 121 122 @Test complicationType()123 public void complicationType() { 124 final DreamHomeControlsComplication complication = 125 new DreamHomeControlsComplication(mResources, mComponentFactory); 126 assertThat(complication.getRequiredTypeAvailability()).isEqualTo( 127 COMPLICATION_TYPE_HOME_CONTROLS); 128 } 129 130 @Test complicationAvailability_serviceNotAvailable_noFavorites_doNotAddComplication()131 public void complicationAvailability_serviceNotAvailable_noFavorites_doNotAddComplication() { 132 final DreamHomeControlsComplication.Registrant registrant = 133 new DreamHomeControlsComplication.Registrant(mComplication, 134 mDreamOverlayStateController, mControlsComponent, mMonitor); 135 registrant.start(); 136 137 setHaveFavorites(false); 138 setServiceAvailable(false); 139 140 verify(mDreamOverlayStateController, never()).addComplication(mComplication); 141 } 142 143 @Test complicationAvailability_serviceAvailable_noFavorites_doNotAddComplication()144 public void complicationAvailability_serviceAvailable_noFavorites_doNotAddComplication() { 145 final DreamHomeControlsComplication.Registrant registrant = 146 new DreamHomeControlsComplication.Registrant(mComplication, 147 mDreamOverlayStateController, mControlsComponent, mMonitor); 148 registrant.start(); 149 150 setHaveFavorites(false); 151 setServiceAvailable(true); 152 153 verify(mDreamOverlayStateController, never()).addComplication(mComplication); 154 } 155 156 @Test complicationAvailability_serviceAvailable_noFavorites_panel_addComplication()157 public void complicationAvailability_serviceAvailable_noFavorites_panel_addComplication() { 158 final DreamHomeControlsComplication.Registrant registrant = 159 new DreamHomeControlsComplication.Registrant(mComplication, 160 mDreamOverlayStateController, mControlsComponent, mMonitor); 161 registrant.start(); 162 163 setHaveFavorites(false); 164 setServiceWithPanel(); 165 166 verify(mDreamOverlayStateController).addComplication(mComplication); 167 } 168 169 @Test complicationAvailability_serviceNotAvailable_haveFavorites_doNotAddComplication()170 public void complicationAvailability_serviceNotAvailable_haveFavorites_doNotAddComplication() { 171 final DreamHomeControlsComplication.Registrant registrant = 172 new DreamHomeControlsComplication.Registrant(mComplication, 173 mDreamOverlayStateController, mControlsComponent, mMonitor); 174 registrant.start(); 175 176 setHaveFavorites(true); 177 setServiceAvailable(false); 178 179 verify(mDreamOverlayStateController, never()).addComplication(mComplication); 180 } 181 182 @Test complicationAvailability_serviceAvailable_haveFavorites_addComplication()183 public void complicationAvailability_serviceAvailable_haveFavorites_addComplication() { 184 final DreamHomeControlsComplication.Registrant registrant = 185 new DreamHomeControlsComplication.Registrant(mComplication, 186 mDreamOverlayStateController, mControlsComponent, mMonitor); 187 registrant.start(); 188 189 setHaveFavorites(true); 190 setServiceAvailable(true); 191 192 verify(mDreamOverlayStateController).addComplication(mComplication); 193 } 194 195 @Test complicationAvailability_checkAvailabilityWhenDreamOverlayBecomesActive()196 public void complicationAvailability_checkAvailabilityWhenDreamOverlayBecomesActive() { 197 final DreamHomeControlsComplication.Registrant registrant = 198 new DreamHomeControlsComplication.Registrant(mComplication, 199 mDreamOverlayStateController, mControlsComponent, mMonitor); 200 registrant.start(); 201 202 setServiceAvailable(true); 203 setHaveFavorites(false); 204 205 // Complication not available on start. 206 verify(mDreamOverlayStateController, never()).addComplication(mComplication); 207 208 // Favorite controls added, complication should be available now. 209 setHaveFavorites(true); 210 211 // Dream overlay becomes active. 212 setDreamOverlayActive(true); 213 214 // Verify complication is added. 215 verify(mDreamOverlayStateController).addComplication(mComplication); 216 } 217 218 /** 219 * Ensures clicking home controls chip logs UiEvent. 220 */ 221 @Test testClick_logsUiEvent()222 public void testClick_logsUiEvent() { 223 final DreamHomeControlsComplication.DreamHomeControlsChipViewController viewController = 224 new DreamHomeControlsComplication.DreamHomeControlsChipViewController( 225 mHomeControlsView, 226 mActivityStarter, 227 mContext, 228 mControlsComponent, 229 mUiEventLogger); 230 viewController.onViewAttached(); 231 232 final ArgumentCaptor<View.OnClickListener> clickListenerCaptor = 233 ArgumentCaptor.forClass(View.OnClickListener.class); 234 verify(mHomeControlsView).setOnClickListener(clickListenerCaptor.capture()); 235 236 clickListenerCaptor.getValue().onClick(mHomeControlsView); 237 verify(mUiEventLogger).log(DreamOverlayUiEvent.DREAM_HOME_CONTROLS_TAPPED); 238 } 239 setHaveFavorites(boolean value)240 private void setHaveFavorites(boolean value) { 241 final List<StructureInfo> favorites = mock(List.class); 242 when(favorites.isEmpty()).thenReturn(!value); 243 when(mControlsController.getFavorites()).thenReturn(favorites); 244 } 245 setServiceAvailable(boolean value)246 private void setServiceAvailable(boolean value) { 247 final List<ControlsServiceInfo> serviceInfos = mock(List.class); 248 when(mControlsListingController.getCurrentServices()).thenReturn(serviceInfos); 249 when(serviceInfos.isEmpty()).thenReturn(!value); 250 triggerControlsListingCallback(serviceInfos); 251 } 252 setServiceWithPanel()253 private void setServiceWithPanel() { 254 final List<ControlsServiceInfo> serviceInfos = new ArrayList<>(); 255 ControlsServiceInfo csi = mock(ControlsServiceInfo.class); 256 serviceInfos.add(csi); 257 when(csi.getPanelActivity()).thenReturn(new ComponentName("a", "b")); 258 when(mControlsListingController.getCurrentServices()).thenReturn(serviceInfos); 259 triggerControlsListingCallback(serviceInfos); 260 } 261 setDreamOverlayActive(boolean value)262 private void setDreamOverlayActive(boolean value) { 263 when(mDreamOverlayStateController.isOverlayActive()).thenReturn(value); 264 verify(mDreamOverlayStateController).addCallback(mStateCallbackCaptor.capture()); 265 mStateCallbackCaptor.getValue().onStateChanged(); 266 } 267 triggerControlsListingCallback(List<ControlsServiceInfo> serviceInfos)268 private void triggerControlsListingCallback(List<ControlsServiceInfo> serviceInfos) { 269 verify(mControlsListingController).addCallback(mCallbackCaptor.capture()); 270 mCallbackCaptor.getValue().onServicesUpdated(serviceInfos); 271 } 272 } 273