diff options
34 files changed, 809 insertions, 210 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 27660ec88f44..5e5d7c629a38 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -21520,6 +21520,8 @@ package android.media { method public void removeKeys(@NonNull byte[]); method public void removeOfflineLicense(@NonNull byte[]); method public void removeSecureStop(@NonNull byte[]); + method public boolean requiresSecureDecoder(@NonNull String); + method public boolean requiresSecureDecoder(@NonNull String, @android.media.MediaDrm.SecurityLevel int); method public void restoreKeys(@NonNull byte[], @NonNull byte[]); method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener); method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener, @Nullable android.os.Handler); diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index b09eda4ad2b6..dddf7352424b 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -454,6 +454,33 @@ public final class HdmiControlManager { @Retention(RetentionPolicy.SOURCE) public @interface SystemAudioModeMuting {} + // -- Whether the HDMI CEC volume control is enabled or disabled. + /** + * HDMI CEC enabled. + * + * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE + * @hide + */ + public static final int VOLUME_CONTROL_ENABLED = 1; + /** + * HDMI CEC disabled. + * + * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE + * @hide + */ + public static final int VOLUME_CONTROL_DISABLED = 0; + /** + * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE + * @hide + */ + @IntDef({ + VOLUME_CONTROL_ENABLED, + VOLUME_CONTROL_DISABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface VolumeControl {} + + // -- Settings available in the CEC Configuration. /** * Name of a setting deciding whether the CEC is enabled. @@ -492,6 +519,43 @@ public final class HdmiControlManager { @SystemApi public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING = "system_audio_mode_muting"; + + /** + * Controls whether volume control commands via HDMI CEC are enabled. + * + * <p>Effects on different device types: + * <table> + * <tr><th>HDMI CEC device type</th><th>0: disabled</th><th>1: enabled</th></tr> + * <tr> + * <td>TV (type: 0)</td> + * <td>Per CEC specification.</td> + * <td>TV changes system volume. TV no longer reacts to incoming volume changes + * via {@code <User Control Pressed>}. TV no longer handles {@code <Report Audio + * Status>}.</td> + * </tr> + * <tr> + * <td>Playback device (type: 4)</td> + * <td>Device sends volume commands to TV/Audio system via {@code <User Control + * Pressed>}</td> + * <td>Device does not send volume commands via {@code <User Control Pressed>}.</td> + * </tr> + * <tr> + * <td>Audio device (type: 5)</td> + * <td>Full "System Audio Control" capabilities.</td> + * <td>Audio device no longer reacts to incoming {@code <User Control Pressed>} + * volume commands. Audio device no longer reports volume changes via {@code + * <Report Audio Status>}.</td> + * </tr> + * </table> + * + * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged. + * + * @hide + * @see android.hardware.hdmi.HdmiControlManager#setHdmiCecVolumeControlEnabled(int) + */ + public static final String CEC_SETTING_NAME_VOLUME_CONTROL_MODE = + "volume_control_enabled"; + /** * @hide */ @@ -501,6 +565,7 @@ public final class HdmiControlManager { CEC_SETTING_NAME_POWER_CONTROL_MODE, CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, + CEC_SETTING_NAME_VOLUME_CONTROL_MODE, }) public @interface CecSettingName {} @@ -913,14 +978,16 @@ public final class HdmiControlManager { * * <p> Due to the resulting behavior, usage on TV and Audio devices is discouraged. * - * @param isHdmiCecVolumeControlEnabled target state of HDMI CEC volume control. - * @see Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED + * @param hdmiCecVolumeControlEnabled target state of HDMI CEC volume control. + * @see HdmiControlManager#CEC_SETTING_NAME_VOLUME_CONTROL_MODE * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) - public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { + public void setHdmiCecVolumeControlEnabled( + @VolumeControl int hdmiCecVolumeControlEnabled) { try { - mService.setHdmiCecVolumeControlEnabled(isHdmiCecVolumeControlEnabled); + mService.setCecSettingIntValue(CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + hdmiCecVolumeControlEnabled); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -931,9 +998,10 @@ public final class HdmiControlManager { * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) - public boolean isHdmiCecVolumeControlEnabled() { + @VolumeControl + public int getHdmiCecVolumeControlEnabled() { try { - return mService.isHdmiCecVolumeControlEnabled(); + return mService.getCecSettingIntValue(CEC_SETTING_NAME_VOLUME_CONTROL_MODE); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1056,10 +1124,10 @@ public final class HdmiControlManager { /** * Called when the HDMI Control (CEC) volume control feature is enabled/disabled. * - * @param enabled status of HDMI CEC volume control feature - * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()} + * @param hdmiCecVolumeControl status of HDMI CEC volume control feature + * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(int)} ()} **/ - void onHdmiCecVolumeControlFeature(boolean enabled); + void onHdmiCecVolumeControlFeature(@VolumeControl int hdmiCecVolumeControl); } private final ArrayMap<HdmiCecVolumeControlFeatureListener, @@ -1360,7 +1428,7 @@ public final class HdmiControlManager { Executor executor, final HdmiCecVolumeControlFeatureListener listener) { return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() { @Override - public void onHdmiCecVolumeControlFeature(boolean enabled) { + public void onHdmiCecVolumeControlFeature(int enabled) { final long token = Binder.clearCallingIdentity(); try { executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled)); diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java index 89a7afa894eb..9a9e945a91cf 100644 --- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java +++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java @@ -273,17 +273,6 @@ public final class HdmiControlServiceWrapper { } @Override - public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { - HdmiControlServiceWrapper.this.setHdmiCecVolumeControlEnabled( - isHdmiCecVolumeControlEnabled); - } - - @Override - public boolean isHdmiCecVolumeControlEnabled() { - return HdmiControlServiceWrapper.this.isHdmiCecVolumeControlEnabled(); - } - - @Override public void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute) { HdmiControlServiceWrapper.this.reportAudioStatus(deviceType, volume, maxVolume, isMute); } diff --git a/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl index 873438bb1d20..f7c5887864c9 100644 --- a/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl +++ b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl @@ -26,7 +26,7 @@ oneway interface IHdmiCecVolumeControlFeatureListener { * Called when the HDMI Control (CEC) volume control feature is enabled/disabled. * * @param enabled status of HDMI CEC volume control feature - * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()} + * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(int)} ()} **/ - void onHdmiCecVolumeControlFeature(boolean enabled); + void onHdmiCecVolumeControlFeature(int hdmiCecVolumeControl); } diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index d7329e0ba3b5..7f0e53ea2e68 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -86,8 +86,6 @@ interface IHdmiControlService { void sendMhlVendorCommand(int portId, int offset, int length, in byte[] data); void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener); void setStandbyMode(boolean isStandbyModeOn); - void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled); - boolean isHdmiCecVolumeControlEnabled(); void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute); void setSystemAudioModeOnForAudioOnlySource(); void addCecSettingChangeListener(String name, IHdmiCecSettingChangeListener listener); diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java index 0330500f0997..30afe38be397 100644 --- a/core/java/android/os/SystemVibrator.java +++ b/core/java/android/os/SystemVibrator.java @@ -17,6 +17,7 @@ package android.os; import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -27,6 +28,8 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; import java.util.concurrent.Executor; @@ -38,6 +41,14 @@ import java.util.concurrent.Executor; public class SystemVibrator extends Vibrator { private static final String TAG = "Vibrator"; + private static final int VIBRATOR_PRESENT_UNKNOWN = 0; + private static final int VIBRATOR_PRESENT_YES = 1; + private static final int VIBRATOR_PRESENT_NO = 2; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({VIBRATOR_PRESENT_UNKNOWN, VIBRATOR_PRESENT_YES, VIBRATOR_PRESENT_NO}) + private @interface VibratorPresent {} + private final IVibratorService mService; private final IVibratorManagerService mManagerService; private final Object mLock = new Object(); @@ -45,6 +56,9 @@ public class SystemVibrator extends Vibrator { private final Context mContext; @GuardedBy("mLock") private VibratorInfo mVibratorInfo; + @GuardedBy("mLock") + @VibratorPresent + private int mVibratorPresent; @GuardedBy("mDelegates") private final ArrayMap<OnVibratorStateChangedListener, @@ -69,15 +83,18 @@ public class SystemVibrator extends Vibrator { @Override public boolean hasVibrator() { - if (mService == null) { - Log.w(TAG, "Failed to vibrate; no vibrator service."); - return false; - } try { - return mService.hasVibrator(); + synchronized (mLock) { + if (mVibratorPresent == VIBRATOR_PRESENT_UNKNOWN && mService != null) { + mVibratorPresent = + mService.hasVibrator() ? VIBRATOR_PRESENT_YES : VIBRATOR_PRESENT_NO; + } + return mVibratorPresent == VIBRATOR_PRESENT_YES; + } } catch (RemoteException e) { + Log.w(TAG, "Failed to query vibrator presence", e); + return false; } - return false; } /** diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java index 6019b90ca13b..597ea14df56d 100644 --- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java @@ -366,15 +366,6 @@ public class HdmiAudioSystemClientTest { } @Override - public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { - } - - @Override - public boolean isHdmiCecVolumeControlEnabled() { - return true; - } - - @Override public void addHdmiCecVolumeControlFeatureListener( IHdmiCecVolumeControlFeatureListener listener) { } diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 13bd85634fda..2703ee35b099 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -1993,6 +1993,33 @@ public final class MediaDrm implements AutoCloseable { return signRSANative(this, sessionId, algorithm, wrappedKey, message); } + /** + * Query if the crypto scheme requires the use of a secure decoder + * to decode data of the given mime type at the default security level. + * The default security level is defined as the highest security level + * supported on the device. + * + * @param mime The mime type of the media data + */ + public boolean requiresSecureDecoder(@NonNull String mime) { + return requiresSecureDecoder(mime, getMaxSecurityLevel()); + } + + /** + * Query if the crypto scheme requires the use of a secure decoder + * to decode data of the given mime type at the given security level. + * + * @param mime The mime type of the media data + * @param level a security level between {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO} + * and {@link #SECURITY_LEVEL_HW_SECURE_ALL}. Otherwise the special value + * {@link #getMaxSecurityLevel()} is also permitted; + * use {@link #getMaxSecurityLevel()} to indicate the maximum security level + * supported by the device. + * @throws IllegalArgumentException if the requested security level is none of the documented + * values for the parameter {@code level}. + */ + public native boolean requiresSecureDecoder(@NonNull String mime, @SecurityLevel int level); + @Override protected void finalize() throws Throwable { try { diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index f38a29c69a3e..babb16b1c880 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -1953,6 +1953,30 @@ static jbyteArray android_media_MediaDrm_signRSANative( return VectorToJByteArray(env, signature); } +static jboolean android_media_MediaDrm_requiresSecureDecoder( + JNIEnv *env, jobject thiz, jstring jmimeType, + jint jSecurityLevel) { + sp<IDrm> drm = GetDrm(env, thiz); + if (!CheckDrm(env, drm)) { + return JNI_FALSE; + } + + String8 mimeType; + if (jmimeType != NULL) { + mimeType = JStringToString8(env, jmimeType); + } + + DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel); + if (securityLevel == DrmPlugin::kSecurityLevelUnknown) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level"); + return JNI_FALSE; + } + + if (securityLevel == DrmPlugin::kSecurityLevelMax) { + return drm->requiresSecureDecoder(mimeType.c_str()); + } + return drm->requiresSecureDecoder(mimeType.c_str(), securityLevel); +} static const JNINativeMethod gMethods[] = { { "native_release", "()V", (void *)android_media_MediaDrm_native_release }, @@ -2075,6 +2099,9 @@ static const JNINativeMethod gMethods[] = { { "getMetricsNative", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaDrm_native_getMetrics }, + + { "requiresSecureDecoder", "(Ljava/lang/String;I)Z", + (void *)android_media_MediaDrm_requiresSecureDecoder }, }; int register_android_media_Drm(JNIEnv *env) { diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 0c8c5c443c4a..dec83d95f0be 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -43,6 +43,7 @@ <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> <item>com.android.systemui.toast.ToastUI</item> <item>com.android.systemui.wmshell.WMShell</item> + <item>com.android.systemui.media.systemsounds.HomeSoundEffectController</item> </string-array> <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. --> diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index 9f6c19bdf06f..55359ea70873 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -27,6 +27,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.globalactions.GlobalActionsComponent; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.dagger.KeyguardModule; +import com.android.systemui.media.systemsounds.HomeSoundEffectController; import com.android.systemui.power.PowerUI; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsModule; @@ -178,4 +179,10 @@ public abstract class SystemUIBinder { @IntoMap @ClassKey(WMShell.class) public abstract SystemUI bindWMShell(WMShell sysui); + + /** Inject into HomeSoundEffectController. */ + @Binds + @IntoMap + @ClassKey(HomeSoundEffectController.class) + public abstract SystemUI bindHomeSoundEffectController(HomeSoundEffectController sysui); } diff --git a/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java new file mode 100644 index 000000000000..dd3d02a86672 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/systemsounds/HomeSoundEffectController.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.systemsounds; + +import android.app.ActivityManager; +import android.app.WindowConfiguration; +import android.content.Context; +import android.media.AudioManager; + +import com.android.systemui.SystemUI; +import com.android.systemui.dagger.SysUISingleton; +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. + */ +@SysUISingleton +public class HomeSoundEffectController extends SystemUI { + + private final AudioManager mAudioManager; + private final TaskStackChangeListeners mTaskStackChangeListeners; + // Initialize true because home sound should not be played when the system boots. + private boolean mIsLastTaskHome = true; + + @Inject + public HomeSoundEffectController( + Context context, + AudioManager audioManager, + TaskStackChangeListeners taskStackChangeListeners) { + super(context); + mAudioManager = audioManager; + mTaskStackChangeListeners = taskStackChangeListeners; + } + + @Override + public void start() { + if (mAudioManager.isHomeSoundEffectEnabled()) { + mTaskStackChangeListeners.registerTaskStackListener( + new TaskStackChangeListener() { + @Override + public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { + handleHomeTaskMovedToFront(taskInfo); + } + }); + } + } + + private boolean isHomeTask(ActivityManager.RunningTaskInfo taskInfo) { + return taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_HOME; + } + + /** + * To enable a home sound, check if the home app moves to front. + */ + 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) { + mAudioManager.playSoundEffect(AudioManager.FX_HOME); + } + mIsLastTaskHome = isCurrentTaskHome; + } +} 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 new file mode 100644 index 000000000000..3a77f7eec7f9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/systemsounds/HomeSoundEffectControllerTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.systemsounds; + +import static org.mockito.ArgumentMatchers.any; +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 android.app.ActivityManager; +import android.app.WindowConfiguration; +import android.content.Context; +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.TaskStackChangeListener; +import com.android.systemui.shared.system.TaskStackChangeListeners; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +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 @Mock AudioManager mAudioManager; + private @Mock TaskStackChangeListeners mTaskStackChangeListeners; + private @Mock ActivityManager.RunningTaskInfo mStandardActivityTaskInfo; + private @Mock ActivityManager.RunningTaskInfo mHomeActivityTaskInfo; + + 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(); + + mController = new HomeSoundEffectController(mContext, mAudioManager, + mTaskStackChangeListeners); + } + + @Test + public void testHomeSoundEffectNotPlayedWhenHomeFirstMovesToFront() { + // When HomeSoundEffectController is started and the home sound effect is enabled, + startController(true /* isHomeSoundEffectEnabled */); + + // And the home task moves to the front, + mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo); + + // Then no home sound effect should be played. + verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); + } + + @Test + public void testHomeSoundEffectPlayedWhenEnabled() { + // 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, + mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo); + + // And the home task moves to the front, + mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo); + + // Then the home sound effect should be played. + verify(mAudioManager).playSoundEffect(AudioManager.FX_HOME); + } + + @Test + public void testHomeSoundEffectNotPlayedTwiceInRow() { + // 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, + mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo); + + // And the home task moves to the front, + mTaskStackChangeListener.onTaskMovedToFront(mHomeActivityTaskInfo); + + // 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); + + // Then no home sound effect should be played. + verify(mAudioManager, times(1)).playSoundEffect(AudioManager.FX_HOME); + } + + @Test + public void testHomeSoundEffectNotPlayedWhenNonHomeTaskMovesToFront() { + // When HomeSoundEffectController is started and the home sound effect is enabled, + startController(true /* isHomeSoundEffectEnabled */); + + // And a standard, non-home task, moves to the front, + mTaskStackChangeListener.onTaskMovedToFront(mStandardActivityTaskInfo); + + // Then no home sound effect should be played. + verify(mAudioManager, never()).playSoundEffect(AudioManager.FX_HOME); + } + + @Test + public void testHomeSoundEffectDisabled() { + // When HomeSoundEffectController is started and the home sound effect is disabled, + startController(false /* isHomeSoundEffectEnabled */); + + // Then no TaskStackListener should be registered + verify(mTaskStackChangeListeners, never()).registerTaskStackListener( + any(TaskStackChangeListener.class)); + } + + /** + * Sets {@link AudioManager#isHomeSoundEffectEnabled()} and starts HomeSoundEffectController. + * If the home sound effect is enabled, the registered TaskStackChangeListener is extracted. + */ + private void startController(boolean isHomeSoundEffectEnabled) { + // Configure home sound effect to be enabled + doReturn(isHomeSoundEffectEnabled).when(mAudioManager).isHomeSoundEffectEnabled(); + + mController.start(); + + if (isHomeSoundEffectEnabled) { + // Construct controller. Save the TaskStackListener for injecting events. + final ArgumentCaptor<TaskStackChangeListener> listenerCaptor = + ArgumentCaptor.forClass(TaskStackChangeListener.class); + verify(mTaskStackChangeListeners).registerTaskStackListener(listenerCaptor.capture()); + mTaskStackChangeListener = listenerCaptor.getValue(); + } + } +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1f48aeb91de8..b07c892ff226 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6003,23 +6003,21 @@ public class ActivityManagerService extends IActivityManager.Stub final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, String abiOverride, int zygotePolicyFlags) { return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */, - false /* mountExtStorageFull */, abiOverride, zygotePolicyFlags); + abiOverride, zygotePolicyFlags); } @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, - boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride, - int zygotePolicyFlags) { + boolean disableHiddenApiChecks, String abiOverride, int zygotePolicyFlags) { return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks, - false /* disableTestApiChecks */, mountExtStorageFull, abiOverride, - zygotePolicyFlags); + false /* disableTestApiChecks */, abiOverride, zygotePolicyFlags); } // TODO: Move to ProcessList? @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, boolean disableHiddenApiChecks, boolean disableTestApiChecks, - boolean mountExtStorageFull, String abiOverride, int zygotePolicyFlags) { + String abiOverride, int zygotePolicyFlags) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, @@ -6054,8 +6052,7 @@ public class ActivityManagerService extends IActivityManager.Stub mPersistentStartingProcesses.add(app); mProcessList.startProcessLocked(app, new HostingRecord("added application", customProcess != null ? customProcess : app.processName), - zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks, - mountExtStorageFull, abiOverride); + zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks, abiOverride); } return app; @@ -7612,10 +7609,10 @@ public class ActivityManagerService extends IActivityManager.Stub crashInfo.throwLineNumber); FrameworkStatsLog.write(FrameworkStatsLog.APP_CRASH_OCCURRED, - Binder.getCallingUid(), + (r != null) ? r.uid : -1, eventType, processName, - Binder.getCallingPid(), + (r != null) ? r.pid : -1, (r != null && r.info != null) ? r.info.packageName : "", (r != null && r.info != null) ? (r.info.isInstantApp() ? FrameworkStatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE @@ -14356,10 +14353,6 @@ public class ActivityManagerService extends IActivityManager.Stub "disable hidden API checks"); } - // TODO(b/158750470): remove - final boolean mountExtStorageFull = isCallerShell() - && (flags & INSTR_FLAG_DISABLE_ISOLATED_STORAGE) != 0; - final long origId = Binder.clearCallingIdentity(); ProcessRecord app; @@ -14375,8 +14368,7 @@ public class ActivityManagerService extends IActivityManager.Stub UsageEvents.Event.SYSTEM_INTERACTION); } app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, - disableTestApiChecks, mountExtStorageFull, abiOverride, - ZYGOTE_POLICY_FLAG_EMPTY); + disableTestApiChecks, abiOverride, ZYGOTE_POLICY_FLAG_EMPTY); } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 6f6cad043a42..47b7e1b5fa41 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -1737,7 +1737,7 @@ public final class ProcessList { @GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, - boolean mountExtStorageFull, String abiOverride) { + String abiOverride) { if (app.pendingStart) { return true; } @@ -2331,7 +2331,7 @@ public final class ProcessList { int zygotePolicyFlags, String abiOverride) { return startProcessLocked(app, hostingRecord, zygotePolicyFlags, false /* disableHiddenApiChecks */, false /* disableTestApiChecks */, - false /* mountExtStorageFull */, abiOverride); + abiOverride); } @GuardedBy("mService") diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 17627fa23a96..e13d6af99231 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -7734,10 +7734,12 @@ public class AudioService extends IAudioService.Stub private class MyHdmiCecVolumeControlFeatureListener implements HdmiControlManager.HdmiCecVolumeControlFeatureListener { - public void onHdmiCecVolumeControlFeature(boolean enabled) { + public void onHdmiCecVolumeControlFeature( + @HdmiControlManager.VolumeControl int hdmiCecVolumeControl) { synchronized (mHdmiClientLock) { if (mHdmiManager == null) return; - mHdmiCecVolumeControlEnabled = enabled; + mHdmiCecVolumeControlEnabled = + hdmiCecVolumeControl == HdmiControlManager.VOLUME_CONTROL_ENABLED; } } }; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java index 16695d1237b6..e854481985ce 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java @@ -291,6 +291,8 @@ public class HdmiCecConfig { return STORAGE_GLOBAL_SETTINGS; case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE: return STORAGE_GLOBAL_SETTINGS; + case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE: + return STORAGE_GLOBAL_SETTINGS; case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST: return STORAGE_SHARED_PREFS; case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING: @@ -309,6 +311,8 @@ public class HdmiCecConfig { return Global.HDMI_CEC_VERSION; case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE: return Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP; + case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE: + return Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED; case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST: return setting.getName(); case HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING: @@ -323,13 +327,13 @@ public class HdmiCecConfig { @Storage int storage = getStorage(setting); String storageKey = getStorageKey(setting); if (storage == STORAGE_SYSPROPS) { - Slog.d(TAG, "Reading '" + storageKey + "' sysprop."); + HdmiLogger.debug("Reading '" + storageKey + "' sysprop."); return mStorageAdapter.retrieveSystemProperty(storageKey, defaultValue); } else if (storage == STORAGE_GLOBAL_SETTINGS) { - Slog.d(TAG, "Reading '" + storageKey + "' global setting."); + HdmiLogger.debug("Reading '" + storageKey + "' global setting."); return mStorageAdapter.retrieveGlobalSetting(storageKey, defaultValue); } else if (storage == STORAGE_SHARED_PREFS) { - Slog.d(TAG, "Reading '" + storageKey + "' shared preference."); + HdmiLogger.debug("Reading '" + storageKey + "' shared preference."); return mStorageAdapter.retrieveSharedPref(storageKey, defaultValue); } return null; @@ -339,13 +343,13 @@ public class HdmiCecConfig { @Storage int storage = getStorage(setting); String storageKey = getStorageKey(setting); if (storage == STORAGE_SYSPROPS) { - Slog.d(TAG, "Setting '" + storageKey + "' sysprop."); + HdmiLogger.debug("Setting '" + storageKey + "' sysprop."); mStorageAdapter.storeSystemProperty(storageKey, value); } else if (storage == STORAGE_GLOBAL_SETTINGS) { - Slog.d(TAG, "Setting '" + storageKey + "' global setting."); + HdmiLogger.debug("Setting '" + storageKey + "' global setting."); mStorageAdapter.storeGlobalSetting(storageKey, value); } else if (storage == STORAGE_SHARED_PREFS) { - Slog.d(TAG, "Setting '" + storageKey + "' shared pref."); + HdmiLogger.debug("Setting '" + storageKey + "' shared pref."); mStorageAdapter.storeSharedPref(storageKey, value); notifySettingChanged(setting); } @@ -366,6 +370,9 @@ public class HdmiCecConfig { case Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP: notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE); break; + case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED: + notifySettingChanged(HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE); + break; } } @@ -399,6 +406,7 @@ public class HdmiCecConfig { Global.HDMI_CONTROL_ENABLED, Global.HDMI_CEC_VERSION, Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP, + Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, }; for (String setting: settings) { resolver.registerContentObserver(Global.getUriFor(setting), false, @@ -597,7 +605,7 @@ public class HdmiCecConfig { throw new IllegalArgumentException("Setting '" + name + "' is not a string-type setting."); } - Slog.d(TAG, "Getting CEC setting value '" + name + "'."); + HdmiLogger.debug("Getting CEC setting value '" + name + "'."); return retrieveValue(setting, setting.getDefaultValue().getStringValue()); } @@ -613,7 +621,7 @@ public class HdmiCecConfig { throw new IllegalArgumentException("Setting '" + name + "' is not a int-type setting."); } - Slog.d(TAG, "Getting CEC setting value '" + name + "'."); + HdmiLogger.debug("Getting CEC setting value '" + name + "'."); String defaultValue = Integer.toString(getIntValue(setting.getDefaultValue())); String value = retrieveValue(setting, defaultValue); return Integer.parseInt(value); @@ -638,7 +646,7 @@ public class HdmiCecConfig { throw new IllegalArgumentException("Invalid CEC setting '" + name + "' value: '" + value + "'."); } - Slog.d(TAG, "Updating CEC setting '" + name + "' to '" + value + "'."); + HdmiLogger.debug("Updating CEC setting '" + name + "' to '" + value + "'."); storeValue(setting, value); } @@ -661,7 +669,7 @@ public class HdmiCecConfig { throw new IllegalArgumentException("Invalid CEC setting '" + name + "' value: '" + value + "'."); } - Slog.d(TAG, "Updating CEC setting '" + name + "' to '" + value + "'."); + HdmiLogger.debug("Updating CEC setting '" + name + "' to '" + value + "'."); storeValue(setting, Integer.toString(value)); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 0b10cc36ded9..ccce9dc43e6d 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -619,7 +619,9 @@ abstract class HdmiCecLocalDevice { } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) { mService.wakeUp(); return true; - } else if (!mService.isHdmiCecVolumeControlEnabled() && isVolumeOrMuteCommand(message)) { + } else if (mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED && isVolumeOrMuteCommand( + message)) { return false; } @@ -1142,7 +1144,8 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly protected void sendVolumeKeyEvent(int keyCode, boolean isPressed) { assertRunOnServiceThread(); - if (!mService.isHdmiCecVolumeControlEnabled()) { + if (mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; } if (!HdmiCecKeycode.isVolumeKeycode(keyCode)) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index a945c90d30ef..b909b1639e1a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -373,7 +373,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @ServiceThreadOnly protected boolean handleGiveAudioStatus(HdmiCecMessage message) { assertRunOnServiceThread(); - if (isSystemAudioControlFeatureEnabled() && mService.isHdmiCecVolumeControlEnabled()) { + if (isSystemAudioControlFeatureEnabled() && mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_ENABLED) { reportAudioStatus(message.getSource()); } else { mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); @@ -723,7 +724,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { void reportAudioStatus(int source) { assertRunOnServiceThread(); - if (!mService.isHdmiCecVolumeControlEnabled()) { + if (mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index ad3773e78b6a..e568aa228b40 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -618,7 +618,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleReportAudioStatus(HdmiCecMessage message) { assertRunOnServiceThread(); - if (!mService.isHdmiCecVolumeControlEnabled()) { + if (mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return false; } @@ -897,7 +898,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } void setAudioStatus(boolean mute, int volume) { - if (!isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) { + if (!isSystemAudioActivated() || mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; } synchronized (mLock) { @@ -919,7 +921,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // On initialization process, getAvrDeviceInfo() may return null and cause exception return; } - if (delta == 0 || !isSystemAudioActivated() || !mService.isHdmiCecVolumeControlEnabled()) { + if (delta == 0 || !isSystemAudioActivated() || mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; } @@ -948,7 +951,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly void changeMute(boolean mute) { assertRunOnServiceThread(); - if (getAvrDeviceInfo() == null || !mService.isHdmiCecVolumeControlEnabled()) { + if (getAvrDeviceInfo() == null || mService.getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { // On initialization process, getAvrDeviceInfo() may return null and cause exception return; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index b427bd0a0b06..beaf6d53370d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -206,7 +206,8 @@ public class HdmiControlService extends SystemService { // Whether HDMI CEC volume control is enabled or not. @GuardedBy("mLock") - private boolean mHdmiCecVolumeControlEnabled; + @HdmiControlManager.VolumeControl + private int mHdmiCecVolumeControl; // Make sure HdmiCecConfig is instantiated and the XMLs are read. private final HdmiCecConfig mHdmiCecConfig; @@ -478,8 +479,8 @@ public class HdmiControlService extends SystemService { mHdmiControlEnabled = mHdmiCecConfig.getIntValue( HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED) == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED; - mHdmiCecVolumeControlEnabled = readBooleanSetting( - Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true); + setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)); mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); if (mCecController == null) { @@ -676,7 +677,8 @@ public class HdmiControlService extends SystemService { boolean enabled = readBooleanSetting(option, true); switch (option) { case Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED: - setHdmiCecVolumeControlEnabledInternal(enabled); + setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)); break; case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: if (isTvDeviceEnabled()) { @@ -1212,7 +1214,8 @@ public class HdmiControlService extends SystemService { void setAudioStatus(boolean mute, int volume) { if (!isTvDeviceEnabled() || !tv().isSystemAudioActivated() - || !isHdmiCecVolumeControlEnabled()) { + || getHdmiCecVolumeControl() + == HdmiControlManager.VOLUME_CONTROL_DISABLED) { return; } AudioManager audioManager = getAudioManager(); @@ -2120,24 +2123,6 @@ public class HdmiControlService extends SystemService { } @Override - public boolean isHdmiCecVolumeControlEnabled() { - initBinderCall(); - return HdmiControlService.this.isHdmiCecVolumeControlEnabled(); - } - - @Override - public void setHdmiCecVolumeControlEnabled(final boolean isHdmiCecVolumeControlEnabled) { - initBinderCall(); - final long token = Binder.clearCallingIdentity(); - try { - HdmiControlService.this.setHdmiCecVolumeControlEnabled( - isHdmiCecVolumeControlEnabled); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override public void reportAudioStatus(final int deviceType, final int volume, final int maxVolume, final boolean isMute) { initBinderCall(); @@ -2211,7 +2196,7 @@ public class HdmiControlService extends SystemService { pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled); pw.println("mSystemAudioActivated: " + isSystemAudioActivated()); - pw.println("mHdmiCecVolumeControlEnabled: " + mHdmiCecVolumeControlEnabled); + pw.println("mHdmiCecVolumeControlEnabled: " + mHdmiCecVolumeControl); pw.decreaseIndent(); // CEC settings @@ -2340,6 +2325,13 @@ public class HdmiControlService extends SystemService { } } + @VisibleForTesting + void setHdmiCecVolumeControlEnabledInternal( + @HdmiControlManager.VolumeControl int hdmiCecVolumeControl) { + mHdmiCecVolumeControl = hdmiCecVolumeControl; + announceHdmiCecVolumeControlFeatureChange(hdmiCecVolumeControl); + } + // Get the source address to send out commands to devices connected to the current device // when other services interact with HdmiControlService. private int getRemoteControlSourceAddress() { @@ -2533,10 +2525,10 @@ public class HdmiControlService extends SystemService { // Return the current status of mHdmiCecVolumeControlEnabled; synchronized (mLock) { try { - listener.onHdmiCecVolumeControlFeature(mHdmiCecVolumeControlEnabled); + listener.onHdmiCecVolumeControlFeature(mHdmiCecVolumeControl); } catch (RemoteException e) { Slog.e(TAG, "Failed to report HdmiControlVolumeControlStatusChange: " - + mHdmiCecVolumeControlEnabled, e); + + mHdmiCecVolumeControl, e); } } } @@ -2835,15 +2827,16 @@ public class HdmiControlService extends SystemService { } } - private void announceHdmiCecVolumeControlFeatureChange(boolean isEnabled) { + private void announceHdmiCecVolumeControlFeatureChange( + @HdmiControlManager.VolumeControl int hdmiCecVolumeControl) { assertRunOnServiceThread(); mHdmiCecVolumeControlFeatureListenerRecords.broadcast(listener -> { try { - listener.onHdmiCecVolumeControlFeature(isEnabled); + listener.onHdmiCecVolumeControlFeature(hdmiCecVolumeControl); } catch (RemoteException e) { Slog.e(TAG, "Failed to report HdmiControlVolumeControlStatusChange: " - + isEnabled); + + hdmiCecVolumeControl); } }); } @@ -3193,31 +3186,10 @@ public class HdmiControlService extends SystemService { } } - void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) { - setHdmiCecVolumeControlEnabledInternal(isHdmiCecVolumeControlEnabled); - - writeBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, - isHdmiCecVolumeControlEnabled); - } - - @VisibleForTesting - void setHdmiCecVolumeControlEnabledInternal(boolean isHdmiCecVolumeControlEnabled) { - synchronized (mLock) { - mHdmiCecVolumeControlEnabled = isHdmiCecVolumeControlEnabled; - - boolean storedValue = readBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, - true); - if (storedValue != isHdmiCecVolumeControlEnabled) { - HdmiLogger.debug("Changing HDMI CEC volume control feature state: %s", - isHdmiCecVolumeControlEnabled); - } - } - announceHdmiCecVolumeControlFeatureChange(isHdmiCecVolumeControlEnabled); - } - - boolean isHdmiCecVolumeControlEnabled() { + @HdmiControlManager.VolumeControl + int getHdmiCecVolumeControl() { synchronized (mLock) { - return mHdmiCecVolumeControlEnabled; + return mHdmiCecVolumeControl; } } @@ -3261,12 +3233,12 @@ public class HdmiControlService extends SystemService { if (enabled) { enableHdmiControlService(); - setHdmiCecVolumeControlEnabledInternal( - readBooleanSetting(Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true)); + setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)); return; } - setHdmiCecVolumeControlEnabledInternal(false); + setHdmiCecVolumeControlEnabledInternal(HdmiControlManager.VOLUME_CONTROL_DISABLED); // Call the vendor handler before the service is disabled. invokeVendorCommandListenersOnControlStateChanged(false, HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); diff --git a/services/core/java/com/android/server/hdmi/cec_config.xml b/services/core/java/com/android/server/hdmi/cec_config.xml index 480e0ec040a8..e6e3c2f5eda1 100644 --- a/services/core/java/com/android/server/hdmi/cec_config.xml +++ b/services/core/java/com/android/server/hdmi/cec_config.xml @@ -46,4 +46,13 @@ </allowed-values> <default-value int-value="1" /> </setting> + <setting name="volume_control_enabled" + value-type="int" + user-configurable="true"> + <allowed-values> + <value int-value="0" /> + <value int-value="1" /> + </allowed-values> + <default-value int-value="1" /> + </setting> </cec-settings> diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 61b218ce7196..60d83f1fd4e8 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3085,8 +3085,23 @@ public class NotificationManagerService extends SystemService { synchronized (mToastQueue) { int uid = Binder.getCallingUid(); + int userId = UserHandle.getUserId(uid); if (enable) { mToastRateLimitingDisabledUids.remove(uid); + try { + String[] packages = mPackageManager.getPackagesForUid(uid); + if (packages == null) { + Slog.e(TAG, "setToastRateLimitingEnabled method haven't found any " + + "packages for the given uid: " + uid + ", toast rate " + + "limiter not reset for that uid."); + return; + } + for (String pkg : packages) { + mToastRateLimiter.clear(userId, pkg); + } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to reset toast rate limiter for given uid", e); + } } else { mToastRateLimitingDisabledUids.add(uid); } diff --git a/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java b/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java index fdbe4b425d39..82c6d01056fd 100644 --- a/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java +++ b/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java @@ -19,6 +19,8 @@ package com.android.server.utils.quota; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageManager; +import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -48,15 +50,18 @@ import java.util.List; * @hide */ public class MultiRateLimiter { + private static final String TAG = "MultiRateLimiter"; private static final CountQuotaTracker[] EMPTY_TRACKER_ARRAY = {}; private final Object mLock = new Object(); @GuardedBy("mLock") private final CountQuotaTracker[] mQuotaTrackers; + private final PackageManager mPackageManager; - private MultiRateLimiter(List<CountQuotaTracker> quotaTrackers) { + private MultiRateLimiter(List<CountQuotaTracker> quotaTrackers, PackageManager packageManager) { mQuotaTrackers = quotaTrackers.toArray(EMPTY_TRACKER_ARRAY); + mPackageManager = packageManager; } /** Record that an event happened and count it towards the given quota. */ @@ -73,6 +78,13 @@ public class MultiRateLimiter { } } + /** Remove all saved events from the rate limiter for the given app (reset it). */ + public void clear(int userId, @NonNull String packageName) { + synchronized (mLock) { + clearLocked(userId, packageName); + } + } + @GuardedBy("mLock") private void noteEventLocked(int userId, @NonNull String packageName, @Nullable String tag) { for (CountQuotaTracker quotaTracker : mQuotaTrackers) { @@ -91,6 +103,22 @@ public class MultiRateLimiter { return true; } + @GuardedBy("mLock") + private void clearLocked(int userId, @NonNull String packageName) { + try { + int uid = mPackageManager.getApplicationInfoAsUser(packageName, 0, userId).uid; + for (CountQuotaTracker quotaTracker : mQuotaTrackers) { + // This method behaves as if the package has been removed from the device, which + // isn't the case here, but it does similar clean-up to what we are aiming for here, + // so it works for this use case. + quotaTracker.onAppRemovedLocked(packageName, uid); + } + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "clear(userId, packageName) called with unrecognized arguments, no " + + "action taken"); + } + } + /** Can create a new {@link MultiRateLimiter}. */ public static class Builder { @@ -154,7 +182,7 @@ public class MultiRateLimiter { * limit. */ public MultiRateLimiter build() { - return new MultiRateLimiter(mQuotaTrackers); + return new MultiRateLimiter(mQuotaTrackers, mContext.getPackageManager()); } } diff --git a/services/core/java/com/android/server/utils/quota/QuotaTracker.java b/services/core/java/com/android/server/utils/quota/QuotaTracker.java index 7f446185f63f..673862cc18e5 100644 --- a/services/core/java/com/android/server/utils/quota/QuotaTracker.java +++ b/services/core/java/com/android/server/utils/quota/QuotaTracker.java @@ -58,7 +58,7 @@ import java.util.PriorityQueue; * of quota until it is below that limit again. Limits are applied according to the category * the UPTC is placed in. Categories are basic constructs to apply different limits to * different groups of UPTCs. For example, standby buckets can be a set of categories, or - * foreground & background could be two categories. If every UPTC should have the limits + * foreground & background could be two categories. If every UPTC should have the same limits * applied, then only one category is needed. * * Note: all limits are enforced per category unless explicitly stated otherwise. @@ -361,7 +361,7 @@ abstract class QuotaTracker { abstract void handleRemovedAppLocked(String packageName, int uid); @GuardedBy("mLock") - private void onAppRemovedLocked(String packageName, int uid) { + void onAppRemovedLocked(String packageName, int uid) { if (packageName == null) { Slog.wtf(TAG, "Told app removed but given null package name."); return; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f9cc33453e15..0f4bb4c5b081 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2606,7 +2606,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A finishActivityResults(resultCode, resultData, resultGrants); - final boolean endTask = task.getActivityBelow(this) == null + final boolean endTask = task.getTopNonFinishingActivity() == null && !task.isClearingToReuseTask(); final int transit = endTask ? TRANSIT_OLD_TASK_CLOSE : TRANSIT_OLD_ACTIVITY_CLOSE; if (isState(RESUMED)) { diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java index df533f3c122a..ab86e19c4a56 100644 --- a/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java @@ -16,15 +16,29 @@ package com.android.server.utils.quota; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import android.content.ContextWrapper; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.UserHandle; import android.testing.TestableContext; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; +import org.junit.After; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoSession; +import org.mockito.quality.Strictness; import java.time.Duration; @@ -32,15 +46,20 @@ import java.time.Duration; public class MultiRateLimiterTest { private static final int USER_ID = 1; + private static final int UID_1 = 10_001; private static final String PACKAGE_NAME_1 = "com.android.package.one"; private static final String PACKAGE_NAME_2 = "com.android.package.two"; private static final String TAG = "tag"; @Rule - public final TestableContext mContext = + public final TestableContext mTestableContext = new TestableContext(InstrumentationRegistry.getContext(), null); private final InjectorForTest mInjector = new InjectorForTest(); + private MockitoSession mMockingSession; + private ContextWrapper mContext; + + @Mock private PackageManager mPackageManager; private static class InjectorForTest extends QuotaTracker.Injector { Duration mElapsedTime = Duration.ZERO; @@ -56,6 +75,35 @@ public class MultiRateLimiterTest { } } + @Before + public void setup() throws Exception { + mMockingSession = mockitoSession() + .initMocks(this) + .strictness(Strictness.LENIENT) + .mockStatic(UserHandle.class) + .startMocking(); + doReturn(USER_ID).when(() -> UserHandle.getUserId(UID_1)); + + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.uid = UID_1; + when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0, USER_ID)) + .thenReturn(applicationInfo); + + mContext = new ContextWrapper(mTestableContext) { + @Override + public PackageManager getPackageManager() { + return mPackageManager; + } + }; + } + + @After + public void tearDown() { + if (mMockingSession != null) { + mMockingSession.finishMocking(); + } + } + @Test public void testSingleRateLimit_belowLimit_isWithinQuota() { MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector) @@ -194,4 +242,48 @@ public class MultiRateLimiterTest { assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue(); assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue(); } + + @Test + public void clearRateLimiterForPackage_afterReachingQuota_quotaIsReset() { + MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector) + .addRateLimit(1, Duration.ofSeconds(100)) + .build(); + + mInjector.mElapsedTime = Duration.ZERO; + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue(); + multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG); + + mInjector.mElapsedTime = Duration.ofSeconds(1); + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse(); + + multiRateLimiter.clear(USER_ID, PACKAGE_NAME_1); + + // Quota for that package is reset. + mInjector.mElapsedTime = Duration.ofSeconds(1); + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue(); + + // Quota is enforced again. + mInjector.mElapsedTime = Duration.ofSeconds(1); + multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG); + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse(); + } + + @Test + public void clearRateLimiterForPackage_doesntAffectOtherPackages() { + MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector) + .addRateLimit(1, Duration.ofSeconds(100)) + .build(); + + mInjector.mElapsedTime = Duration.ZERO; + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue(); + multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_2, TAG); + + mInjector.mElapsedTime = Duration.ofSeconds(1); + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isFalse(); + + multiRateLimiter.clear(USER_ID, PACKAGE_NAME_1); + + // Doesn't affect the other package. + assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isFalse(); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java index aeeca1a39cc0..8e37f94828fb 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java @@ -95,6 +95,15 @@ final class FakeHdmiCecConfig extends HdmiCecConfig { + " </allowed-values>" + " <default-value int-value=\"1\" />" + " </setting>" + + " <setting name=\"volume_control_enabled\"" + + " value-type=\"int\"" + + " user-configurable=\"true\">" + + " <allowed-values>" + + " <value int-value=\"0\" />" + + " <value int-value=\"1\" />" + + " </allowed-values>" + + " <default-value int-value=\"1\" />" + + " </setting>" + "</cec-settings>"; FakeHdmiCecConfig(@NonNull Context context) { diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index 6bb68da2a894..95a0a7439904 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -195,8 +195,9 @@ public class HdmiCecLocalDeviceAudioSystemTest { } }; - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); - + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_ENABLED); mMyLooper = mTestLooper.getLooper(); mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService); mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) { @@ -710,7 +711,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { public void giveAudioStatus_volumeEnabled() { mMusicVolume = 50; mMusicMaxVolume = 100; - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); int volume = mHdmiControlService.getAudioManager() @@ -740,7 +742,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { public void giveAudioStatus_volumeDisabled() { mMusicVolume = 50; mMusicMaxVolume = 100; - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); int volume = mHdmiControlService.getAudioManager() @@ -770,7 +773,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { public void reportAudioStatus_volumeEnabled() { mMusicVolume = 50; mMusicMaxVolume = 100; - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); int volume = mHdmiControlService.getAudioManager() @@ -794,7 +798,8 @@ public class HdmiCecLocalDeviceAudioSystemTest { public void reportAudioStatus_volumeDisabled() { mMusicVolume = 50; mMusicMaxVolume = 100; - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDeviceAudioSystem.setSystemAudioControlFeatureEnabled(true); int volume = mHdmiControlService.getAudioManager() diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index 7aea4ffe1b03..bc808762b855 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -862,7 +862,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_up_volumeEnabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false); mTestLooper.dispatchAll(); @@ -879,7 +880,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_down_volumeEnabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false); mTestLooper.dispatchAll(); @@ -896,7 +898,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_mute_volumeEnabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false); mTestLooper.dispatchAll(); @@ -913,7 +916,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_up_volumeDisabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false); mTestLooper.dispatchAll(); @@ -930,7 +934,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_down_volumeDisabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, true); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN, false); mTestLooper.dispatchAll(); @@ -947,7 +952,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_mute_volumeDisabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, true); mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_MUTE, false); mTestLooper.dispatchAll(); @@ -964,7 +970,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_toTv_activeSource() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiControlService.setSystemAudioActivated(false); mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest"); @@ -984,7 +991,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_toAudio_activeSource() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiControlService.setSystemAudioActivated(true); mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest"); @@ -1004,7 +1012,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_toTv_inactiveSource() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiControlService.setSystemAudioActivated(false); mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest"); @@ -1023,7 +1032,8 @@ public class HdmiCecLocalDevicePlaybackTest { @Test public void sendVolumeKeyEvent_toAudio_inactiveSource() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mHdmiControlService.setSystemAudioActivated(true); mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest"); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java index eb2f9608f6f3..0717112da12c 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java @@ -32,6 +32,7 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import android.content.Context; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPortInfo; import android.os.test.TestLooper; @@ -124,8 +125,13 @@ public class HdmiCecLocalDeviceTest { @Before public void SetUp() { + + Context context = InstrumentationRegistry.getTargetContext(); + + HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context); + mHdmiControlService = - new HdmiControlService(InstrumentationRegistry.getTargetContext()) { + new HdmiControlService(context) { @Override boolean isControlEnabled() { return isControlEnabled; @@ -157,6 +163,11 @@ public class HdmiCecLocalDeviceTest { void wakeUp() { mWakeupMessageReceived = true; } + + @Override + protected HdmiCecConfig getHdmiCecConfig() { + return hdmiCecConfig; + } }; mHdmiControlService.setIoLooper(mTestLooper.getLooper()); mNativeWrapper = new FakeNativeWrapper(); @@ -244,7 +255,8 @@ public class HdmiCecLocalDeviceTest { @Test public void handleUserControlPressed_volumeUp() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); boolean result = mHdmiLocalDevice.handleUserControlPressed( HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP)); @@ -254,7 +266,8 @@ public class HdmiCecLocalDeviceTest { @Test public void handleUserControlPressed_volumeDown() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); boolean result = mHdmiLocalDevice.handleUserControlPressed( HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN)); @@ -264,7 +277,8 @@ public class HdmiCecLocalDeviceTest { @Test public void handleUserControlPressed_volumeMute() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); boolean result = mHdmiLocalDevice.handleUserControlPressed( HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_MUTE)); @@ -274,7 +288,8 @@ public class HdmiCecLocalDeviceTest { @Test public void handleUserControlPressed_volumeUp_disabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); boolean result = mHdmiLocalDevice.handleUserControlPressed( HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP)); @@ -284,7 +299,8 @@ public class HdmiCecLocalDeviceTest { @Test public void handleUserControlPressed_volumeDown_disabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); boolean result = mHdmiLocalDevice.handleUserControlPressed( HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN)); @@ -294,7 +310,8 @@ public class HdmiCecLocalDeviceTest { @Test public void handleUserControlPressed_volumeMute_disabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); boolean result = mHdmiLocalDevice.handleUserControlPressed( HdmiCecMessageBuilder.buildUserControlPressed(ADDR_PLAYBACK_1, ADDR_TV, HdmiCecKeycode.CEC_KEYCODE_MUTE)); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java index c212bf868c76..70718f765412 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java @@ -136,6 +136,8 @@ public class HdmiControlServiceBinderAPITest { // Some tests expect no logical addresses being allocated at the beginning of the test. setHdmiControlEnabled(false); + HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContext); + mHdmiControlService = new HdmiControlService(mContext) { @Override @@ -158,6 +160,11 @@ public class HdmiControlServiceBinderAPITest { boolean isPowerStandby() { return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; } + + @Override + protected HdmiCecConfig getHdmiCecConfig() { + return hdmiCecConfig; + } }; mMyLooper = mTestLooper.getLooper(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java index 9152e1e84b71..dbb03cb6dbdc 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java @@ -291,136 +291,175 @@ public class HdmiControlServiceTest { @Test public void setAndGetCecVolumeControlEnabled_isApi() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); - assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isFalse(); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_DISABLED); + assertThat(mHdmiControlService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_DISABLED); - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); - assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isTrue(); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_ENABLED); + assertThat(mHdmiControlService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test public void setAndGetCecVolumeControlEnabled_changesSetting() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); - assertThat(mHdmiControlService.readBooleanSetting( - Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true)).isFalse(); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_DISABLED); + assertThat(mHdmiControlService.readIntSetting( + Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, -1)).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_DISABLED); - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); - assertThat(mHdmiControlService.readBooleanSetting( - Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true)).isTrue(); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_ENABLED); + assertThat(mHdmiControlService.readIntSetting( + Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, -1)).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test public void setAndGetCecVolumeControlEnabledInternal_doesNotChangeSetting() { - mHdmiControlService.setHdmiCecVolumeControlEnabledInternal(true); - - mHdmiControlService.setHdmiCecVolumeControlEnabledInternal(false); - assertThat(mHdmiControlService.readBooleanSetting( - Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true)).isTrue(); - - mHdmiControlService.setHdmiCecVolumeControlEnabledInternal(true); - assertThat(mHdmiControlService.readBooleanSetting( - Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, true)).isTrue(); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_ENABLED); + + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); + assertThat(mHdmiControlService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); + + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); + assertThat(mHdmiControlService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test public void disableAndReenableCec_volumeControlReturnsToOriginalValue_enabled() { - boolean volumeControlEnabled = true; - mHdmiControlService.setHdmiCecVolumeControlEnabled(volumeControlEnabled); + int volumeControlEnabled = HdmiControlManager.VOLUME_CONTROL_ENABLED; + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal(volumeControlEnabled); mHdmiControlService.setControlEnabled(false); - assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isFalse(); + assertThat(mHdmiControlService.getHdmiCecVolumeControl()).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiControlService.setControlEnabled(true); - assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isEqualTo( - volumeControlEnabled); + assertThat(mHdmiControlService.getHdmiCecVolumeControl()).isEqualTo(volumeControlEnabled); } @Test public void disableAndReenableCec_volumeControlReturnsToOriginalValue_disabled() { - boolean volumeControlEnabled = false; - mHdmiControlService.setHdmiCecVolumeControlEnabled(volumeControlEnabled); + int volumeControlEnabled = HdmiControlManager.VOLUME_CONTROL_DISABLED; + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, volumeControlEnabled); mHdmiControlService.setControlEnabled(false); - assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isFalse(); + assertThat(mHdmiControlService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo( + volumeControlEnabled); mHdmiControlService.setControlEnabled(true); - assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isEqualTo( + assertThat(mHdmiControlService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo( volumeControlEnabled); } @Test public void disableAndReenableCec_volumeControlFeatureListenersNotified() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, + HdmiControlManager.VOLUME_CONTROL_ENABLED); VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback(); mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback); mHdmiControlService.setControlEnabled(false); assertThat(callback.mCallbackReceived).isTrue(); - assertThat(callback.mVolumeControlEnabled).isFalse(); + assertThat(callback.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_DISABLED); mHdmiControlService.setControlEnabled(true); - assertThat(callback.mVolumeControlEnabled).isTrue(); + assertThat(callback.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback(); mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback); mTestLooper.dispatchAll(); assertThat(callback.mCallbackReceived).isTrue(); - assertThat(callback.mVolumeControlEnabled).isTrue(); + assertThat(callback.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_disabled() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback(); mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback); mTestLooper.dispatchAll(); assertThat(callback.mCallbackReceived).isTrue(); - assertThat(callback.mVolumeControlEnabled).isFalse(); + assertThat(callback.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_DISABLED); } @Test public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback(); mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback); - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mTestLooper.dispatchAll(); assertThat(callback.mCallbackReceived).isTrue(); - assertThat(callback.mVolumeControlEnabled).isTrue(); + assertThat(callback.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test public void addHdmiCecVolumeControlFeatureListener_honorsUnregistration() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback(); mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback); mTestLooper.dispatchAll(); mHdmiControlService.removeHdmiControlVolumeControlStatusChangeListener(callback); - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mTestLooper.dispatchAll(); assertThat(callback.mCallbackReceived).isTrue(); - assertThat(callback.mVolumeControlEnabled).isFalse(); + assertThat(callback.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_DISABLED); } @Test public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate_multiple() { - mHdmiControlService.setHdmiCecVolumeControlEnabled(false); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_DISABLED); VolumeControlFeatureCallback callback1 = new VolumeControlFeatureCallback(); VolumeControlFeatureCallback callback2 = new VolumeControlFeatureCallback(); @@ -428,13 +467,16 @@ public class HdmiControlServiceTest { mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback2); - mHdmiControlService.setHdmiCecVolumeControlEnabled(true); + mHdmiControlService.setHdmiCecVolumeControlEnabledInternal( + HdmiControlManager.VOLUME_CONTROL_ENABLED); mTestLooper.dispatchAll(); assertThat(callback1.mCallbackReceived).isTrue(); assertThat(callback2.mCallbackReceived).isTrue(); - assertThat(callback1.mVolumeControlEnabled).isTrue(); - assertThat(callback2.mVolumeControlEnabled).isTrue(); + assertThat(callback1.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); + assertThat(callback2.mVolumeControlEnabled).isEqualTo( + HdmiControlManager.VOLUME_CONTROL_ENABLED); } @Test @@ -579,10 +621,10 @@ public class HdmiControlServiceTest { private static class VolumeControlFeatureCallback extends IHdmiCecVolumeControlFeatureListener.Stub { boolean mCallbackReceived = false; - boolean mVolumeControlEnabled = false; + int mVolumeControlEnabled = -1; @Override - public void onHdmiCecVolumeControlFeature(boolean enabled) throws RemoteException { + public void onHdmiCecVolumeControlFeature(int enabled) throws RemoteException { this.mCallbackReceived = true; this.mVolumeControlEnabled = enabled; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 6f584ee9a18c..ef96a2d5960a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1064,6 +1064,21 @@ public class ActivityRecordTests extends WindowTestsBase { } /** + * Verify that finish bottom activity from a task won't boost it to top. + */ + @Test + public void testFinishBottomActivityIfPossible_noZBoost() { + final ActivityRecord bottomActivity = createActivityWithTask(); + final ActivityRecord topActivity = new ActivityBuilder(mAtm) + .setTask(bottomActivity.getTask()).build(); + topActivity.mVisibleRequested = true; + // simulating bottomActivity as a trampoline activity. + bottomActivity.setState(RESUMED, "test"); + bottomActivity.finishIfPossible("test", false); + assertFalse(bottomActivity.mNeedsZBoost); + } + + /** * Verify that complete finish request for visible activity must be delayed before the next one * becomes visible. */ |