1 /* 2 * Copyright (C) 2020 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.car.systembar; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 22 import static com.google.common.truth.Truth.assertThat; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyInt; 26 import static org.mockito.ArgumentMatchers.argThat; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.never; 29 import static org.mockito.Mockito.reset; 30 import static org.mockito.Mockito.spy; 31 import static org.mockito.Mockito.verify; 32 import static org.mockito.Mockito.when; 33 34 import android.app.ActivityManager; 35 import android.app.ActivityTaskManager; 36 import android.content.Intent; 37 import android.graphics.drawable.Drawable; 38 import android.os.RemoteException; 39 import android.testing.AndroidTestingRunner; 40 import android.view.LayoutInflater; 41 import android.view.View; 42 import android.widget.ImageView; 43 import android.widget.LinearLayout; 44 45 import androidx.test.filters.SmallTest; 46 47 import com.android.systemui.SysuiTestCase; 48 import com.android.systemui.car.CarSystemUiTest; 49 import com.android.systemui.statusbar.AlphaOptimizedImageView; 50 import com.android.systemui.tests.R; 51 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.mockito.ArgumentMatcher; 56 import org.mockito.MockitoAnnotations; 57 58 @CarSystemUiTest 59 @RunWith(AndroidTestingRunner.class) 60 @SmallTest 61 public class CarSystemBarButtonTest extends SysuiTestCase { 62 63 private static final String DIALER_BUTTON_ACTIVITY_NAME = 64 "com.android.car.dialer/.ui.TelecomActivity"; 65 private static final String BROADCAST_ACTION_NAME = 66 "android.car.intent.action.TOGGLE_HVAC_CONTROLS"; 67 68 private ActivityManager mActivityManager; 69 // LinearLayout with CarSystemBarButtons with different configurations. 70 private LinearLayout mTestView; 71 // Does not have any selection state which is the default configuration. 72 private CarSystemBarButton mDefaultButton; 73 74 @Before setUp()75 public void setUp() { 76 MockitoAnnotations.initMocks(this); 77 mContext = spy(mContext); 78 ActivityManager am = mContext.getSystemService(ActivityManager.class); 79 mActivityManager = spy(am); 80 when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager); 81 mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate( 82 R.layout.car_system_bar_button_test, /* root= */ null); 83 mDefaultButton = mTestView.findViewById(R.id.default_no_selection_state); 84 } 85 86 @Test onCreate_iconIsVisible()87 public void onCreate_iconIsVisible() { 88 AlphaOptimizedImageView icon = mDefaultButton.findViewById( 89 R.id.car_nav_button_icon_image); 90 91 assertThat(icon.getDrawable()).isNotNull(); 92 } 93 94 @Test onSelected_selectedIconDefined_togglesIcon()95 public void onSelected_selectedIconDefined_togglesIcon() { 96 mDefaultButton.setSelected(true); 97 waitForIdleSync(); 98 Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById( 99 R.id.car_nav_button_icon_image)).getDrawable(); 100 101 mDefaultButton.setSelected(false); 102 waitForIdleSync(); 103 Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById( 104 R.id.car_nav_button_icon_image)).getDrawable(); 105 106 assertThat(selectedIconDrawable).isNotEqualTo(unselectedIconDrawable); 107 } 108 109 @Test onSelected_selectedIconUndefined_displaysSameIcon()110 public void onSelected_selectedIconUndefined_displaysSameIcon() { 111 CarSystemBarButton selectedIconUndefinedButton = mTestView.findViewById( 112 R.id.selected_icon_undefined); 113 114 selectedIconUndefinedButton.setSelected(true); 115 waitForIdleSync(); 116 Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById( 117 R.id.car_nav_button_icon_image)).getDrawable(); 118 119 120 selectedIconUndefinedButton.setSelected(false); 121 waitForIdleSync(); 122 Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById( 123 R.id.car_nav_button_icon_image)).getDrawable(); 124 125 assertThat(selectedIconDrawable).isEqualTo(unselectedIconDrawable); 126 } 127 128 @Test onUnselected_doesNotHighlightWhenSelected_applySelectedAlpha()129 public void onUnselected_doesNotHighlightWhenSelected_applySelectedAlpha() { 130 mDefaultButton.setSelected(false); 131 waitForIdleSync(); 132 133 assertThat(mDefaultButton.getAlpha()).isEqualTo(mDefaultButton.getSelectedAlpha()); 134 } 135 136 @Test onSelected_doesNotHighlightWhenSelected_applyDefaultUnselectedAlpha()137 public void onSelected_doesNotHighlightWhenSelected_applyDefaultUnselectedAlpha() { 138 mDefaultButton.setSelected(true); 139 waitForIdleSync(); 140 141 assertThat(mDefaultButton.getIconAlpha()).isEqualTo(mDefaultButton.getUnselectedAlpha()); 142 } 143 144 @Test onUnselected_highlightWhenSelected_applyDefaultUnselectedAlpha()145 public void onUnselected_highlightWhenSelected_applyDefaultUnselectedAlpha() { 146 CarSystemBarButton highlightWhenSelectedButton = mTestView.findViewById( 147 R.id.highlightable_no_more_button); 148 highlightWhenSelectedButton.setSelected(false); 149 waitForIdleSync(); 150 151 assertThat(highlightWhenSelectedButton.getIconAlpha()).isEqualTo( 152 highlightWhenSelectedButton.getUnselectedAlpha()); 153 } 154 155 @Test onSelected_highlightWhenSelected_applyDefaultSelectedAlpha()156 public void onSelected_highlightWhenSelected_applyDefaultSelectedAlpha() { 157 CarSystemBarButton highlightWhenSelectedButton = mTestView.findViewById( 158 R.id.highlightable_no_more_button); 159 highlightWhenSelectedButton.setSelected(true); 160 waitForIdleSync(); 161 162 assertThat(highlightWhenSelectedButton.getIconAlpha()).isEqualTo( 163 highlightWhenSelectedButton.getSelectedAlpha()); 164 } 165 166 @Test onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon()167 public void onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon() { 168 mDefaultButton.setSelected(true); 169 AlphaOptimizedImageView moreIcon = mDefaultButton.findViewById( 170 R.id.car_nav_button_more_icon); 171 waitForIdleSync(); 172 173 assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE); 174 } 175 176 @Test onSelected_showMoreWhenSelected_showsMoreIcon()177 public void onSelected_showMoreWhenSelected_showsMoreIcon() { 178 CarSystemBarButton showMoreWhenSelected = mTestView.findViewById( 179 R.id.not_highlightable_more_button); 180 showMoreWhenSelected.setSelected(true); 181 AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById( 182 R.id.car_nav_button_more_icon); 183 waitForIdleSync(); 184 185 assertThat(moreIcon.getVisibility()).isEqualTo(View.VISIBLE); 186 } 187 188 @Test onUnselected_showMoreWhenSelected_doesNotShowMoreIcon()189 public void onUnselected_showMoreWhenSelected_doesNotShowMoreIcon() { 190 CarSystemBarButton showMoreWhenSelected = mTestView.findViewById( 191 R.id.highlightable_no_more_button); 192 showMoreWhenSelected.setSelected(true); 193 showMoreWhenSelected.setSelected(false); 194 AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById( 195 R.id.car_nav_button_more_icon); 196 waitForIdleSync(); 197 198 assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE); 199 } 200 201 @Test onUnselected_withAppIcon_showsAppIcon()202 public void onUnselected_withAppIcon_showsAppIcon() { 203 CarSystemBarButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); 204 Drawable appIcon = getContext().getDrawable(R.drawable.ic_android); 205 206 roleBasedButton.setAppIcon(appIcon); 207 roleBasedButton.setSelected(false); 208 waitForIdleSync(); 209 210 Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById( 211 R.id.car_nav_button_icon_image)).getDrawable(); 212 213 assertThat(currentDrawable).isEqualTo(appIcon); 214 } 215 216 @Test onUnselected_withAppIcon_applyUnselectedAlpha()217 public void onUnselected_withAppIcon_applyUnselectedAlpha() { 218 CarSystemBarButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); 219 220 roleBasedButton.setAppIcon(getContext().getDrawable(R.drawable.ic_android)); 221 roleBasedButton.setSelected(false); 222 waitForIdleSync(); 223 224 assertThat(roleBasedButton.getIconAlpha()).isEqualTo(roleBasedButton.getUnselectedAlpha()); 225 } 226 227 @Test onSelected_withAppIcon_showsAppIcon()228 public void onSelected_withAppIcon_showsAppIcon() { 229 CarSystemBarButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); 230 Drawable appIcon = getContext().getDrawable(R.drawable.ic_android); 231 232 roleBasedButton.setSelected(true); 233 roleBasedButton.setAppIcon(appIcon); 234 waitForIdleSync(); 235 236 Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById( 237 R.id.car_nav_button_icon_image)).getDrawable(); 238 239 assertThat(currentDrawable).isEqualTo(appIcon); 240 } 241 242 @Test onSelected_withAppIcon_applySelectedAlpha()243 public void onSelected_withAppIcon_applySelectedAlpha() { 244 CarSystemBarButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); 245 246 roleBasedButton.setSelected(true); 247 roleBasedButton.setAppIcon(getContext().getDrawable(R.drawable.ic_android)); 248 waitForIdleSync(); 249 250 assertThat(roleBasedButton.getIconAlpha()).isEqualTo(roleBasedButton.getSelectedAlpha()); 251 } 252 253 @Test onClick_launchesIntentActivity()254 public void onClick_launchesIntentActivity() { 255 mDefaultButton.performClick(); 256 257 CarSystemBarButton dialerButton = mTestView.findViewById(R.id.dialer_activity); 258 dialerButton.performClick(); 259 waitForIdleSync(); 260 261 assertThat(getCurrentActivityName()).isEqualTo(DIALER_BUTTON_ACTIVITY_NAME); 262 } 263 264 @Test onLongClick_longIntentDefined_launchesLongIntentActivity()265 public void onLongClick_longIntentDefined_launchesLongIntentActivity() { 266 mDefaultButton.performClick(); 267 waitForIdleSync(); 268 269 CarSystemBarButton dialerButton = mTestView.findViewById( 270 R.id.long_click_dialer_activity); 271 dialerButton.performLongClick(); 272 273 assertThat(getCurrentActivityName()).isEqualTo(DIALER_BUTTON_ACTIVITY_NAME); 274 } 275 276 @Test onClick_useBroadcast_broadcastsIntent()277 public void onClick_useBroadcast_broadcastsIntent() { 278 CarSystemBarButton button = mTestView.findViewById(R.id.broadcast); 279 reset(mContext); 280 281 button.performClick(); 282 waitForIdleSync(); 283 284 verify(mContext).sendBroadcastAsUser(argThat(new ArgumentMatcher<Intent>() { 285 @Override 286 public boolean matches(Intent argument) { 287 return argument.getAction().equals(BROADCAST_ACTION_NAME); 288 } 289 }), any()); 290 } 291 292 @Test onClick_requestBackstackClear_clearBackStack()293 public void onClick_requestBackstackClear_clearBackStack() { 294 CarSystemBarButton dialerButton = 295 mTestView.findViewById(R.id.dialer_activity_clear_backstack); 296 297 dialerButton.performClick(); 298 299 verify(mActivityManager).moveTaskToFront(anyInt(), anyInt()); 300 } 301 302 @Test onClick_useBroadcast_requestBackstackClear_doesNotClearingBackstack()303 public void onClick_useBroadcast_requestBackstackClear_doesNotClearingBackstack() { 304 CarSystemBarButton button = 305 mTestView.findViewById(R.id.broadcast_try_clear_backstack); 306 307 button.performClick(); 308 309 verify(mActivityManager, never()).moveTaskToFront(anyInt(), anyInt()); 310 } 311 312 @Test onSetUnseen_hasUnseen_showsUnseenIndicator()313 public void onSetUnseen_hasUnseen_showsUnseenIndicator() { 314 mDefaultButton.setUnseen(true); 315 ImageView hasUnseenIndicator = mDefaultButton.findViewById(R.id.car_nav_button_unseen_icon); 316 waitForIdleSync(); 317 318 assertThat(hasUnseenIndicator.getVisibility()).isEqualTo(View.VISIBLE); 319 } 320 321 @Test onSetUnseen_doesNotHaveUnseen_hidesUnseenIndicator()322 public void onSetUnseen_doesNotHaveUnseen_hidesUnseenIndicator() { 323 mDefaultButton.setUnseen(false); 324 ImageView hasUnseenIndicator = mDefaultButton.findViewById(R.id.car_nav_button_unseen_icon); 325 waitForIdleSync(); 326 327 assertThat(hasUnseenIndicator.getVisibility()).isEqualTo(View.GONE); 328 } 329 330 @Test onSetDisabled_enabled_refreshIconAlpha()331 public void onSetDisabled_enabled_refreshIconAlpha() { 332 mDefaultButton.setDisabled(false, /* runnable= */ null); 333 334 assertThat(mDefaultButton.getAlpha()).isEqualTo(mDefaultButton.getSelectedAlpha()); 335 } 336 337 @Test onSetDisabled_disdabledAlpha()338 public void onSetDisabled_disdabledAlpha() { 339 mDefaultButton.setDisabled(true, /* runnable= */ null); 340 341 assertThat(mDefaultButton.getIconAlpha()).isEqualTo(mDefaultButton.getDisabledAlpha()); 342 } 343 344 @Test onSetDisabled_nullRunnable_doesNotSendBroadcast()345 public void onSetDisabled_nullRunnable_doesNotSendBroadcast() { 346 mDefaultButton.setDisabled(true, /* runnable= */ null); 347 348 mDefaultButton.performClick(); 349 350 verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), any()); 351 } 352 353 @Test onSetDisabled_runnable()354 public void onSetDisabled_runnable() { 355 Runnable mockRunnable = mock(Runnable.class); 356 mDefaultButton.setDisabled(true, /* runnable= */ mockRunnable); 357 358 mDefaultButton.performClick(); 359 360 verify(mockRunnable).run(); 361 } 362 363 /** 364 * Returns the name of the first activity running in fullscreen mode (i.e. excludes things 365 * like TaskViews). 366 */ getCurrentActivityName()367 private String getCurrentActivityName() { 368 try { 369 ActivityTaskManager.RootTaskInfo rootTaskInfo = 370 ActivityTaskManager.getService().getRootTaskInfoOnDisplay( 371 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_UNDEFINED, 372 mContext.getDisplayId()); 373 if (rootTaskInfo == null || rootTaskInfo.topActivity == null) { 374 return null; 375 } 376 return rootTaskInfo.topActivity.flattenToShortString(); 377 } catch (RemoteException e) { 378 return null; 379 } 380 } 381 } 382