summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java11
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivityUtils.java5
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values/attrs_manifest.xml7
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java312
9 files changed, 440 insertions, 35 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 55dd8b2d81b4..6ba9478ffc62 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -92,6 +92,7 @@ package android {
field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
+ field public static final String DISABLE_SYSTEM_SOUND_EFFECTS = "android.permission.DISABLE_SYSTEM_SOUND_EFFECTS";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
field public static final String DOMAIN_VERIFICATION_AGENT = "android.permission.DOMAIN_VERIFICATION_AGENT";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
@@ -311,6 +312,7 @@ package android {
field public static final int hotwordDetectionService = 16844326; // 0x1010626
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int minExtensionVersion = 16844305; // 0x1010611
+ field public static final int playHomeTransitionSound = 16844358; // 0x1010646
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int sdkVersion = 16844304; // 0x1010610
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index feb58a30e519..0952b3e1233c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -550,9 +550,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public static final int FLAG_INHERIT_SHOW_WHEN_LOCKED = 0x1;
/**
+ * Bit in {@link #privateFlags} indicating whether a home sound effect should be played if the
+ * home app moves to front after the activity with this flag set.
+ * Set from the {@link android.R.attr#playHomeTransitionSound} attribute.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_HOME_TRANSITION_SOUND = 0x2;
+
+ /**
* Options that have been set in the activity declaration in the manifest.
* These include:
- * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED}.
+ * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED},
+ * {@link #PRIVATE_FLAG_HOME_TRANSITION_SOUND}.
* @hide
*/
public int privateFlags;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index d99c4109e5ad..ff6aaad09d09 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -149,7 +149,10 @@ public class ParsedActivityUtils {
| flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
| flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa);
- activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa);
+ activity.privateFlags |= flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED,
+ R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa)
+ | flag(ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND,
+ R.styleable.AndroidManifestActivity_playHomeTransitionSound, true, sa);
activity.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT);
activity.documentLaunchMode = sa.getInt(R.styleable.AndroidManifestActivity_documentLaunchMode, ActivityInfo.DOCUMENT_LAUNCH_NONE);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 38ef9d2ea525..1d462bc5dd48 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4440,6 +4440,13 @@
<permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to disable system sound effects when the user exits one of
+ the application's activities.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.DISABLE_SYSTEM_SOUND_EFFECTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to provide remote displays.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 38e8f83ff767..dc4f52e980ce 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2862,6 +2862,13 @@
{@link android.content.Context#sendBroadcast(Intent, String)} being used.
Multiple tags can be specified separated by '|'. -->
<attr name="attributionTags"/>
+ <!-- Specifies whether a home sound effect should be played if the home app moves to
+ front after an activity with this flag set to <code>true</code>.
+ <p>The default value of this attribute is <code>true</code>.
+ <p>Also note that home sounds are only played if the device supports home sounds,
+ usually TVs.
+ <p>Requires permission {@code android.permission.DISABLE_SYSTEM_SOUND_EFFECTS}. -->
+ <attr name="playHomeTransitionSound" format="boolean"/>
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3259cafb4f7e..16feb4fc7dac 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3093,6 +3093,8 @@
<public name="suppressesSpellChecker" />
<public name="usesPermissionFlags" />
<public name="requestOptimizedExternalStorageAccess" />
+ <!-- @hide @SystemApi -->
+ <public name="playHomeTransitionSound" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index af6df32a02b0..fbe7175b757f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -591,4 +591,12 @@
<!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
<bool name="allow_force_nav_bar_handle_opaque">true</bool>
+
+ <!-- Whether a transition of ACTIVITY_TYPE_DREAM to the home app should play a home sound
+ effect -->
+ <bool name="config_playHomeSoundAfterDream">false</bool>
+
+ <!-- Whether a transition of ACTIVITY_TYPE_ASSISTANT to the home app should play a home sound
+ effect -->
+ <bool name="config_playHomeSoundAfterAssistant">false</bool>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
index dd3d02a86672..31e49390b9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java
@@ -16,38 +16,64 @@
package com.android.systemui.media.systemsounds;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
+import android.util.Slog;
+import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import javax.inject.Inject;
/**
- * If a sound effect is defined for {@link android.media.AudioManager#FX_HOME}, a sound is played
- * when the home task moves to front and the last task that moved to front was not the home task.
+ * If a sound effect is defined for {@link android.media.AudioManager#FX_HOME}, a
+ * {@link TaskStackChangeListener} is registered to play a home sound effect when conditions
+ * documented at {@link #handleTaskStackChanged} apply.
*/
@SysUISingleton
public class HomeSoundEffectController extends SystemUI {
+ private static final String TAG = "HomeSoundEffectController";
private final AudioManager mAudioManager;
private final TaskStackChangeListeners mTaskStackChangeListeners;
+ private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final PackageManager mPm;
+ private final boolean mPlayHomeSoundAfterAssistant;
+ private final boolean mPlayHomeSoundAfterDream;
// Initialize true because home sound should not be played when the system boots.
private boolean mIsLastTaskHome = true;
+ // mLastHomePackageName could go out of sync in rare circumstances if launcher changes,
+ // but it's cheaper than the alternative and potential impact is low
+ private String mLastHomePackageName;
+ private @WindowConfiguration.ActivityType int mLastActivityType;
+ private boolean mLastActivityHasNoHomeSound = false;
+ private int mLastTaskId;
@Inject
public HomeSoundEffectController(
Context context,
AudioManager audioManager,
- TaskStackChangeListeners taskStackChangeListeners) {
+ TaskStackChangeListeners taskStackChangeListeners,
+ ActivityManagerWrapper activityManagerWrapper,
+ PackageManager packageManager) {
super(context);
mAudioManager = audioManager;
mTaskStackChangeListeners = taskStackChangeListeners;
+ mActivityManagerWrapper = activityManagerWrapper;
+ mPm = packageManager;
+ mPlayHomeSoundAfterAssistant = context.getResources().getBoolean(
+ R.bool.config_playHomeSoundAfterAssistant);
+ mPlayHomeSoundAfterDream = context.getResources().getBoolean(
+ R.bool.config_playHomeSoundAfterDream);
}
@Override
@@ -56,27 +82,94 @@ public class HomeSoundEffectController extends SystemUI {
mTaskStackChangeListeners.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
- handleHomeTaskMovedToFront(taskInfo);
+ public void onTaskStackChanged() {
+ ActivityManager.RunningTaskInfo currentTask =
+ mActivityManagerWrapper.getRunningTask();
+ if (currentTask == null || currentTask.topActivityInfo == null) {
+ return;
+ }
+ handleTaskStackChanged(currentTask);
}
});
}
}
- private boolean isHomeTask(ActivityManager.RunningTaskInfo taskInfo) {
- return taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_HOME;
+ private boolean hasFlagNoSound(ActivityInfo activityInfo) {
+ if ((activityInfo.privateFlags & ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND) == 0) {
+ // Only allow flag if app has permission
+ if (mPm.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS,
+ activityInfo.packageName) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ } else {
+ Slog.w(TAG,
+ "Activity has flag playHomeTransition set to false but doesn't hold "
+ + "required permission "
+ + Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS);
+ return false;
+ }
+ }
+ return false;
}
/**
- * To enable a home sound, check if the home app moves to front.
+ * The home sound is played if all of the following conditions are met:
+ * <ul>
+ * <li>The last task which moved to front was not home. This avoids playing the sound
+ * e.g. after FallbackHome transitions to home, another activity of the home app like a
+ * notification panel moved to front, or in case the home app crashed.</li>
+ * <li>The current activity which moved to front is home</li>
+ * <li>The topActivity of the last task has {@link android.R.attr#playHomeTransitionSound} set
+ * to <code>true</code>.</li>
+ * <li>The topActivity of the last task is not of type
+ * {@link WindowConfiguration#ACTIVITY_TYPE_ASSISTANT} if config_playHomeSoundAfterAssistant is
+ * set to <code>false</code> (default).</li>
+ * <li>The topActivity of the last task is not of type
+ * {@link WindowConfiguration#ACTIVITY_TYPE_DREAM} if config_playHomeSoundAfterDream is
+ * set to <code>false</code> (default).</li>
+ * </ul>
*/
- private void handleHomeTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
- boolean isCurrentTaskHome = isHomeTask(taskInfo);
- // If the last task is home we don't want to play the home sound. This avoids playing
- // the home sound after FallbackHome transitions to Home
- if (!mIsLastTaskHome && isCurrentTaskHome) {
+ private boolean shouldPlayHomeSoundForCurrentTransition(
+ ActivityManager.RunningTaskInfo currentTask) {
+ boolean isHomeActivity =
+ currentTask.topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME;
+ if (currentTask.taskId == mLastTaskId) {
+ return false;
+ }
+ if (mIsLastTaskHome || !isHomeActivity) {
+ return false;
+ }
+ if (mLastActivityHasNoHomeSound) {
+ return false;
+ }
+ if (mLastActivityType == WindowConfiguration.ACTIVITY_TYPE_ASSISTANT
+ && !mPlayHomeSoundAfterAssistant) {
+ return false;
+ }
+ if (mLastActivityType == WindowConfiguration.ACTIVITY_TYPE_DREAM
+ && !mPlayHomeSoundAfterDream) {
+ return false;
+ }
+ return true;
+ }
+
+ private void updateLastTaskInfo(ActivityManager.RunningTaskInfo currentTask) {
+ mLastTaskId = currentTask.taskId;
+ mLastActivityType = currentTask.topActivityType;
+ mLastActivityHasNoHomeSound = hasFlagNoSound(currentTask.topActivityInfo);
+ boolean isHomeActivity =
+ currentTask.topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME;
+ boolean isHomePackage = currentTask.topActivityInfo.packageName.equals(
+ mLastHomePackageName);
+ mIsLastTaskHome = isHomeActivity || isHomePackage;
+ if (isHomeActivity && !isHomePackage) {
+ mLastHomePackageName = currentTask.topActivityInfo.packageName;
+ }
+ }
+
+ private void handleTaskStackChanged(ActivityManager.RunningTaskInfo frontTask) {
+ if (shouldPlayHomeSoundForCurrentTransition(frontTask)) {
mAudioManager.playSoundEffect(AudioManager.FX_HOME);
}
- mIsLastTaskHome = isCurrentTaskHome;
+ updateLastTaskInfo(frontTask);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
index 3a77f7eec7f9..33a30e0bcc27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java
@@ -21,16 +21,20 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
-import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -41,30 +45,50 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class HomeSoundEffectControllerTest extends SysuiTestCase {
- private @Mock Context mContext;
+ private static final String HOME_PACKAGE_NAME = "com.android.apps.home";
+ private static final String NON_HOME_PACKAGE_NAME = "com.android.apps.not.home";
+ private static final int HOME_TASK_ID = 0;
+ private static final int NON_HOME_TASK_ID = 1;
+
private @Mock AudioManager mAudioManager;
private @Mock TaskStackChangeListeners mTaskStackChangeListeners;
- private @Mock ActivityManager.RunningTaskInfo mStandardActivityTaskInfo;
- private @Mock ActivityManager.RunningTaskInfo mHomeActivityTaskInfo;
-
+ private @Mock ActivityManagerWrapper mActivityManagerWrapper;
+ private @Mock PackageManager mPackageManager;
+
+ private ActivityManager.RunningTaskInfo mTaskAStandardActivity;
+ private ActivityManager.RunningTaskInfo mTaskAExceptionActivity;
+ private ActivityManager.RunningTaskInfo mHomeTaskHomeActivity;
+ private ActivityManager.RunningTaskInfo mHomeTaskStandardActivity;
+ private ActivityManager.RunningTaskInfo mEmptyTask;
private HomeSoundEffectController mController;
private TaskStackChangeListener mTaskStackChangeListener;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
-
- doReturn(WindowConfiguration.ACTIVITY_TYPE_STANDARD).when(
- mStandardActivityTaskInfo).getActivityType();
- doReturn(WindowConfiguration.ACTIVITY_TYPE_HOME).when(
- mHomeActivityTaskInfo).getActivityType();
-
+ mTaskAStandardActivity = createRunningTaskInfo(NON_HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD, NON_HOME_TASK_ID,
+ true /* playHomeTransitionSound */);
+ mTaskAExceptionActivity = createRunningTaskInfo(NON_HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD, NON_HOME_TASK_ID,
+ false /* playHomeTransitionSound */);
+ mHomeTaskHomeActivity = createRunningTaskInfo(HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_HOME, HOME_TASK_ID,
+ true /* playHomeTransitionSound */);
+ mHomeTaskStandardActivity = createRunningTaskInfo(HOME_PACKAGE_NAME,
+ WindowConfiguration.ACTIVITY_TYPE_STANDARD, HOME_TASK_ID,
+ true /* playHomeTransitionSound */);
+ mEmptyTask = new ActivityManager.RunningTaskInfo();
+ mContext.setMockPackageManager(mPackageManager);
+ when(mPackageManager.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS,
+ NON_HOME_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_GRANTED);
mController = new HomeSoundEffectController(mContext, mAudioManager,
- mTaskStackChangeListeners);
+ mTaskStackChangeListeners, mActivityManagerWrapper, mPackageManager);
}
@Test
@@ -73,43 +97,60 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
startController(true /* isHomeSoundEffectEnabled */);
// And the home task moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(mHomeTaskHomeActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then no home sound effect should be played.
verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
}
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME
+ * Expectation: Home sound is played
+ */
@Test
public void testHomeSoundEffectPlayedWhenEnabled() {
// When HomeSoundEffectController is started and the home sound effect is enabled,
startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity);
// And first a task different from the home task moves to front,
- mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// And the home task moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then the home sound effect should be played.
verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
}
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME -> HOME
+ * Expectation: Home sound is played once after HOME moves to front the first time
+ */
@Test
public void testHomeSoundEffectNotPlayedTwiceInRow() {
// When HomeSoundEffectController is started and the home sound effect is enabled,
startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity,
+ mHomeTaskHomeActivity);
+
// And first a task different from the home task moves to front,
- mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// And the home task moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then the home sound effect should be played.
verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
// If the home task moves to front a second time in a row,
- mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo);
+ mTaskStackChangeListener.onTaskStackChanged();
// Then no home sound effect should be played.
verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME);
@@ -121,7 +162,59 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
startController(true /* isHomeSoundEffectEnabled */);
// And a standard, non-home task, moves to the front,
- mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(mTaskAStandardActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME -> HOME (activity type standard)
+ * Expectation: Home sound is played once after HOME moves to front
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFront() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity,
+ mHomeTaskStandardActivity);
+
+ // And first a task different from the home task moves to front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+
+ // If the home task moves to front a second time in a row,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * Task A (playHomeTransitionSound = true) -> HOME (activity type standard)
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenOtherHomeActivityMovesToFrontOfOtherApp() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+
+ // And first a task different from the home task moves to front,
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskStandardActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And an activity from the home package but not the home root activity moves to front
+ mTaskStackChangeListener.onTaskStackChanged();
// Then no home sound effect should be played.
verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
@@ -138,6 +231,171 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
}
/**
+ * Task A (playHomeTransitionSound = false) -> HOME
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+
+ // And first a task different from the home task moves to front, which has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAExceptionActivity,
+ mHomeTaskHomeActivity);
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played because the last package is an exception.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = true) -> Task A (playHomeTransitionSound = false)
+ * -> HOME
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenHomeActivityMovesToFrontAfterException2() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mTaskAExceptionActivity,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a different activity from the same task moves to front, which has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = false) -> Task A (playHomeTransitionSound = true)
+ * -> HOME
+ * Expectation: Home sound is played
+ */
+ @Test
+ public void testHomeSoundEffectPlayedWhenHomeActivityMovesToFrontAfterException() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAExceptionActivity,
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front,
+ // the topActivity of this task has {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND}
+ // set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a different activity from the same task moves to front, which has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>true</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = false) -> Task A (empty task, no top activity)
+ * -> HOME
+ * Expectation: Home sound is not played
+ */
+ @Test
+ public void testHomeSoundEffectNotPlayedWhenEmptyTaskMovesToFrontAfterException() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAExceptionActivity,
+ mEmptyTask,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front, whose topActivity has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a task with no topActivity moves to front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then no home sound effect should be played.
+ verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = true) -> Task A (empty task, no top activity)
+ * -> HOME
+ * Expectation: Home sound is played
+ */
+ @Test
+ public void testHomeSoundEffectPlayedWhenEmptyTaskMovesToFrontAfterStandardActivity() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mEmptyTask,
+ mHomeTaskHomeActivity);
+
+ // And first a task different from the home task moves to front, whose topActivity has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>false</code>
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then a task with no topActivity moves to front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
+ * HOME -> Task A (playHomeTransitionSound = false, no permission) -> HOME
+ * Expectation: Home sound is played
+ */
+ @Test
+ public void testHomeSoundEffectPlayedWhenFlagSetButPermissionNotGranted() {
+ // When HomeSoundEffectController is started and the home sound effect is enabled,
+ startController(true /* isHomeSoundEffectEnabled */);
+ when(mActivityManagerWrapper.getRunningTask()).thenReturn(
+ mTaskAStandardActivity,
+ mHomeTaskHomeActivity);
+ when(mPackageManager.checkPermission(Manifest.permission.DISABLE_SYSTEM_SOUND_EFFECTS,
+ NON_HOME_PACKAGE_NAME)).thenReturn(PackageManager.PERMISSION_DENIED);
+
+ // And first a task different from the home task moves to front, whose topActivity has
+ // {@link ActivityInfo#PRIVATE_FLAG_HOME_TRANSITION_SOUND} set to <code>true</code>,
+ // but the app doesn't have the right permission granted
+ mTaskStackChangeListener.onTaskStackChanged();
+
+
+ // And the home task moves to the front,
+ mTaskStackChangeListener.onTaskStackChanged();
+
+ // Then the home sound effect should be played.
+ verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME);
+ }
+
+ /**
* Sets {@link AudioManager#isHomeSoundEffectEnabled()} and starts HomeSoundEffectController.
* If the home sound effect is enabled, the registered TaskStackChangeListener is extracted.
*/
@@ -155,4 +413,20 @@ public class HomeSoundEffectControllerTest extends SysuiTestCase {
mTaskStackChangeListener = listenerCaptor.getValue();
}
}
+
+ private ActivityManager.RunningTaskInfo createRunningTaskInfo(String packageName,
+ int activityType, int taskId, boolean playHomeTransitionSound) {
+ ActivityManager.RunningTaskInfo res = new ActivityManager.RunningTaskInfo();
+ res.topActivityInfo = new ActivityInfo();
+ res.topActivityInfo.packageName = packageName;
+ res.topActivityType = activityType;
+ res.taskId = taskId;
+ if (!playHomeTransitionSound) {
+ // set the flag to 0
+ res.topActivityInfo.privateFlags &= ~ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND;
+ } else {
+ res.topActivityInfo.privateFlags |= ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND;
+ }
+ return res;
+ }
}