1 /* 2 * Copyright (C) 2021 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.media.systemsounds; 18 19 import static org.mockito.ArgumentMatchers.any; 20 import static org.mockito.Mockito.doReturn; 21 import static org.mockito.Mockito.never; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.when; 25 26 import android.Manifest; 27 import android.app.ActivityManager; 28 import android.app.WindowConfiguration; 29 import android.content.pm.ActivityInfo; 30 import android.content.pm.PackageManager; 31 import android.media.AudioManager; 32 33 import androidx.test.filters.SmallTest; 34 import androidx.test.runner.AndroidJUnit4; 35 36 import com.android.systemui.SysuiTestCase; 37 import com.android.systemui.shared.system.ActivityManagerWrapper; 38 import com.android.systemui.shared.system.TaskStackChangeListener; 39 import com.android.systemui.shared.system.TaskStackChangeListeners; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.mockito.ArgumentCaptor; 45 import org.mockito.Mock; 46 import org.mockito.MockitoAnnotations; 47 48 @SmallTest 49 @RunWith(AndroidJUnit4.class) 50 public class HomeSoundEffectControllerTest extends SysuiTestCase { 51 52 private static final String HOME_PACKAGE_NAME = "com.android.apps.home"; 53 private static final String NON_HOME_PACKAGE_NAME = "com.android.apps.not.home"; 54 private static final int HOME_TASK_ID = 0; 55 private static final int NON_HOME_TASK_ID = 1; 56 57 private @Mock AudioManager mAudioManager; 58 private @Mock TaskStackChangeListeners mTaskStackChangeListeners; 59 private @Mock ActivityManagerWrapper mActivityManagerWrapper; 60 private @Mock PackageManager mPackageManager; 61 62 private ActivityManager.RunningTaskInfo mTaskAStandardActivity; 63 private ActivityManager.RunningTaskInfo mTaskAExceptionActivity; 64 private ActivityManager.RunningTaskInfo mHomeTaskHomeActivity; 65 private ActivityManager.RunningTaskInfo mHomeTaskStandardActivity; 66 private ActivityManager.RunningTaskInfo mEmptyTask; 67 private HomeSoundEffectController mController; 68 private TaskStackChangeListener mTaskStackChangeListener; 69 70 @Before setUp()71 public void setUp() throws Exception { 72 MockitoAnnotations.initMocks(this); 73 mTaskAStandardActivity = createRunningTaskInfo(NON_HOME_PACKAGE_NAME, 74 WindowConfiguration.ACTIVITY_TYPE_STANDARD, NON_HOME_TASK_ID, 75 true /* playHomeTransitionSound */); 76 mTaskAExceptionActivity = createRunningTaskInfo(NON_HOME_PACKAGE_NAME, 77 WindowConfiguration.ACTIVITY_TYPE_STANDARD, NON_HOME_TASK_ID, 78 false /* playHomeTransitionSound */); 79 mHomeTaskHomeActivity = createRunningTaskInfo(HOME_PACKAGE_NAME, 80 WindowConfiguration.ACTIVITY_TYPE_HOME, HOME_TASK_ID, 81 true /* playHomeTransitionSound */); 82 mHomeTaskStandardActivity = createRunningTaskInfo(HOME_PACKAGE_NAME, 83 WindowConfiguration.ACTIVITY_TYPE_STANDARD, HOME_TASK_ID, 84 true /* playHomeTransitionSound */); 85 mEmptyTask = new ActivityManager.RunningTaskInfo(); 86 mContext.setMockPackageManager(mPackageManager); 87 when(mPackageManager.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS, 88 NON_HOME_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED); 89 mController = new HomeSoundEffectController(mContext, mAudioManager, 90 mTaskStackChangeListeners, mActivityManagerWrapper, mPackageManager); 91 } 92 93 @Test testHomeSoundEffectNotPlayedWhenHomeFirstMovesToFront()94 public void testHomeSoundEffectNotPlayedWhenHomeFirstMovesToFront() { 95 // When HomeSoundEffectController is started and the home sound effect is enabled, 96 startController(true /* isHomeSoundEffectEnabled */); 97 98 // And the home task moves to the front, 99 when(mActivityManagerWrapper.getRunningTask()).thenReturn(mHomeTaskHomeActivity); 100 mTaskStackChangeListener.onTaskStackChanged(); 101 102 // Then no home sound effect should be played. 103 verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); 104 } 105 106 /** 107 * Task A (playHomeTransitionSound = true) -> HOME 108 * Expectation: Home sound is played 109 */ 110 @Test testHomeSoundEffectPlayedWhenEnabled()111 public void testHomeSoundEffectPlayedWhenEnabled() { 112 // When HomeSoundEffectController is started and the home sound effect is enabled, 113 startController(true /* isHomeSoundEffectEnabled */); 114 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 115 mTaskAStandardActivity, 116 mHomeTaskHomeActivity); 117 118 // And first a task different from the home task moves to front, 119 mTaskStackChangeListener.onTaskStackChanged(); 120 121 // And the home task moves to the front, 122 mTaskStackChangeListener.onTaskStackChanged(); 123 124 // Then the home sound effect should be played. 125 verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); 126 } 127 128 /** 129 * Task A (playHomeTransitionSound = true) -> HOME -> HOME 130 * Expectation: Home sound is played once after HOME moves to front the first time 131 */ 132 @Test testHomeSoundEffectNotPlayedTwiceInRow()133 public void testHomeSoundEffectNotPlayedTwiceInRow() { 134 // When HomeSoundEffectController is started and the home sound effect is enabled, 135 startController(true /* isHomeSoundEffectEnabled */); 136 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 137 mTaskAStandardActivity, 138 mHomeTaskHomeActivity, 139 mHomeTaskHomeActivity); 140 141 142 // And first a task different from the home task moves to front, 143 mTaskStackChangeListener.onTaskStackChanged(); 144 145 // And the home task moves to the front, 146 mTaskStackChangeListener.onTaskStackChanged(); 147 148 // Then the home sound effect should be played. 149 verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); 150 151 // If the home task moves to front a second time in a row, 152 mTaskStackChangeListener.onTaskStackChanged(); 153 154 // Then no home sound effect should be played. 155 verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME); 156 } 157 158 @Test testHomeSoundEffectNotPlayedWhenNonHomeTaskMovesToFront()159 public void testHomeSoundEffectNotPlayedWhenNonHomeTaskMovesToFront() { 160 // When HomeSoundEffectController is started and the home sound effect is enabled, 161 startController(true /* isHomeSoundEffectEnabled */); 162 163 // And a standard, non-home task, moves to the front, 164 when(mActivityManagerWrapper.getRunningTask()).thenReturn(mTaskAStandardActivity); 165 mTaskStackChangeListener.onTaskStackChanged(); 166 167 // Then no home sound effect should be played. 168 verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); 169 } 170 171 /** 172 * Task A (playHomeTransitionSound = true) -> HOME -> HOME (activity type standard) 173 * Expectation: Home sound is played once after HOME moves to front 174 */ 175 @Test testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFront()176 public void testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFront() { 177 // When HomeSoundEffectController is started and the home sound effect is enabled, 178 startController(true /* isHomeSoundEffectEnabled */); 179 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 180 mTaskAStandardActivity, 181 mHomeTaskHomeActivity, 182 mHomeTaskStandardActivity); 183 184 // And first a task different from the home task moves to front, 185 mTaskStackChangeListener.onTaskStackChanged(); 186 187 // And the home task moves to the front, 188 mTaskStackChangeListener.onTaskStackChanged(); 189 190 // Then the home sound effect should be played. 191 verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); 192 193 // If the home task moves to front a second time in a row, 194 mTaskStackChangeListener.onTaskStackChanged(); 195 196 // Then no home sound effect should be played. 197 verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME); 198 } 199 200 /** 201 * Task A (playHomeTransitionSound = true) -> HOME (activity type standard) 202 * Expectation: Home sound is not played 203 */ 204 @Test testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFrontOfOtherApp()205 public void testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFrontOfOtherApp() { 206 // When HomeSoundEffectController is started and the home sound effect is enabled, 207 startController(true /* isHomeSoundEffectEnabled */); 208 209 // And first a task different from the home task moves to front, 210 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 211 mTaskAStandardActivity, 212 mHomeTaskStandardActivity); 213 mTaskStackChangeListener.onTaskStackChanged(); 214 215 // And an activity from the home package but not the home root activity moves to front 216 mTaskStackChangeListener.onTaskStackChanged(); 217 218 // Then no home sound effect should be played. 219 verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); 220 } 221 222 @Test testHomeSoundEffectDisabled()223 public void testHomeSoundEffectDisabled() { 224 // When HomeSoundEffectController is started and the home sound effect is disabled, 225 startController(false /* isHomeSoundEffectEnabled */); 226 227 // Then no TaskStackListener should be registered 228 verify(mTaskStackChangeListeners, never()).registerTaskStackListener( 229 any(TaskStackChangeListener.class)); 230 } 231 232 /** 233 * Task A (playHomeTransitionSound = false) -> HOME 234 * Expectation: Home sound is not played 235 */ 236 @Test testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException()237 public void testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException() { 238 // When HomeSoundEffectController is started and the home sound effect is enabled, 239 startController(true /* isHomeSoundEffectEnabled */); 240 241 // And first a task different from the home task moves to front, which has 242 // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code> 243 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 244 mTaskAExceptionActivity, 245 mHomeTaskHomeActivity); 246 mTaskStackChangeListener.onTaskStackChanged(); 247 248 // And the home task moves to the front, 249 mTaskStackChangeListener.onTaskStackChanged(); 250 251 // Then no home sound effect should be played because the last package is an exception. 252 verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); 253 } 254 255 /** 256 * HOME -> Task A (playHomeTransitionSound = true) -> Task A (playHomeTransitionSound = false) 257 * -> HOME 258 * Expectation: Home sound is not played 259 */ 260 @Test testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException2()261 public void testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException2() { 262 // When HomeSoundEffectController is started and the home sound effect is enabled, 263 startController(true /* isHomeSoundEffectEnabled */); 264 265 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 266 mTaskAStandardActivity, 267 mTaskAExceptionActivity, 268 mHomeTaskHomeActivity); 269 270 // And first a task different from the home task moves to front 271 mTaskStackChangeListener.onTaskStackChanged(); 272 273 // Then a different activity from the same task moves to front, which has 274 // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code> 275 mTaskStackChangeListener.onTaskStackChanged(); 276 277 // And the home task moves to the front, 278 mTaskStackChangeListener.onTaskStackChanged(); 279 280 // Then no home sound effect should be played. 281 verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); 282 } 283 284 /** 285 * HOME -> Task A (playHomeTransitionSound = false) -> Task A (playHomeTransitionSound = true) 286 * -> HOME 287 * Expectation: Home sound is played 288 */ 289 @Test testHomeSoundEffectPlayedWhenHomeActivityMovesToFrontAfterException()290 public void testHomeSoundEffectPlayedWhenHomeActivityMovesToFrontAfterException() { 291 // When HomeSoundEffectController is started and the home sound effect is enabled, 292 startController(true /* isHomeSoundEffectEnabled */); 293 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 294 mTaskAExceptionActivity, 295 mTaskAStandardActivity, 296 mHomeTaskHomeActivity); 297 298 // And first a task different from the home task moves to front, 299 // the topActivity of this task has {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} 300 // set to <code>false</code> 301 mTaskStackChangeListener.onTaskStackChanged(); 302 303 // Then a different activity from the same task moves to front, which has 304 // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>true</code> 305 mTaskStackChangeListener.onTaskStackChanged(); 306 307 // And the home task moves to the front, 308 mTaskStackChangeListener.onTaskStackChanged(); 309 310 // Then the home sound effect should be played. 311 verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); 312 } 313 314 /** 315 * HOME -> Task A (playHomeTransitionSound = false) -> Task A (empty task, no top activity) 316 * -> HOME 317 * Expectation: Home sound is not played 318 */ 319 @Test testHomeSoundEffectNotPlayedWhenEmptyTaskMovesToFrontAfterException()320 public void testHomeSoundEffectNotPlayedWhenEmptyTaskMovesToFrontAfterException() { 321 // When HomeSoundEffectController is started and the home sound effect is enabled, 322 startController(true /* isHomeSoundEffectEnabled */); 323 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 324 mTaskAExceptionActivity, 325 mEmptyTask, 326 mHomeTaskHomeActivity); 327 328 // And first a task different from the home task moves to front, whose topActivity has 329 // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code> 330 mTaskStackChangeListener.onTaskStackChanged(); 331 332 // Then a task with no topActivity moves to front, 333 mTaskStackChangeListener.onTaskStackChanged(); 334 335 // And the home task moves to the front, 336 mTaskStackChangeListener.onTaskStackChanged(); 337 338 // Then no home sound effect should be played. 339 verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); 340 } 341 342 /** 343 * HOME -> Task A (playHomeTransitionSound = true) -> Task A (empty task, no top activity) 344 * -> HOME 345 * Expectation: Home sound is played 346 */ 347 @Test testHomeSoundEffectPlayedWhenEmptyTaskMovesToFrontAfterStandardActivity()348 public void testHomeSoundEffectPlayedWhenEmptyTaskMovesToFrontAfterStandardActivity() { 349 // When HomeSoundEffectController is started and the home sound effect is enabled, 350 startController(true /* isHomeSoundEffectEnabled */); 351 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 352 mTaskAStandardActivity, 353 mEmptyTask, 354 mHomeTaskHomeActivity); 355 356 // And first a task different from the home task moves to front, whose topActivity has 357 // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code> 358 mTaskStackChangeListener.onTaskStackChanged(); 359 360 // Then a task with no topActivity moves to front, 361 mTaskStackChangeListener.onTaskStackChanged(); 362 363 // And the home task moves to the front, 364 mTaskStackChangeListener.onTaskStackChanged(); 365 366 // Then the home sound effect should be played. 367 verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); 368 } 369 370 /** 371 * HOME -> Task A (playHomeTransitionSound = false, no permission) -> HOME 372 * Expectation: Home sound is played 373 */ 374 @Test testHomeSoundEffectPlayedWhenFlagSetButPermissionNotGranted()375 public void testHomeSoundEffectPlayedWhenFlagSetButPermissionNotGranted() { 376 // When HomeSoundEffectController is started and the home sound effect is enabled, 377 startController(true /* isHomeSoundEffectEnabled */); 378 when(mActivityManagerWrapper.getRunningTask()).thenReturn( 379 mTaskAStandardActivity, 380 mHomeTaskHomeActivity); 381 when(mPackageManager.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS, 382 NON_HOME_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_DENIED); 383 384 // And first a task different from the home task moves to front, whose topActivity has 385 // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>true</code>, 386 // but the app doesn't have the right permission granted 387 mTaskStackChangeListener.onTaskStackChanged(); 388 389 390 // And the home task moves to the front, 391 mTaskStackChangeListener.onTaskStackChanged(); 392 393 // Then the home sound effect should be played. 394 verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); 395 } 396 397 /** 398 * Sets {@link AudioManager#isHomeSoundEffectEnabled()} and starts HomeSoundEffectController. 399 * If the home sound effect is enabled, the registered TaskStackChangeListener is extracted. 400 */ startController(boolean isHomeSoundEffectEnabled)401 private void startController(boolean isHomeSoundEffectEnabled) { 402 // Configure home sound effect to be enabled 403 doReturn(isHomeSoundEffectEnabled).when(mAudioManager).isHomeSoundEffectEnabled(); 404 405 mController.start(); 406 407 if (isHomeSoundEffectEnabled) { 408 // Construct controller. Save the TaskStackListener for injecting events. 409 final ArgumentCaptor<TaskStackChangeListener> listenerCaptor = 410 ArgumentCaptor.forClass(TaskStackChangeListener.class); 411 verify(mTaskStackChangeListeners).registerTaskStackListener(listenerCaptor.capture()); 412 mTaskStackChangeListener = listenerCaptor.getValue(); 413 } 414 } 415 createRunningTaskInfo(String packageName, int activityType, int taskId, boolean playHomeTransitionSound)416 private ActivityManager.RunningTaskInfo createRunningTaskInfo(String packageName, 417 int activityType, int taskId, boolean playHomeTransitionSound) { 418 ActivityManager.RunningTaskInfo res = new ActivityManager.RunningTaskInfo(); 419 res.topActivityInfo = new ActivityInfo(); 420 res.topActivityInfo.packageName = packageName; 421 res.topActivityType = activityType; 422 res.taskId = taskId; 423 if (!playHomeTransitionSound) { 424 // set the flag to 0 425 res.topActivityInfo.privateFlags &= ~ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND; 426 } else { 427 res.topActivityInfo.privateFlags |= ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND; 428 } 429 return res; 430 } 431 } 432