Merge "Delegate playSoundEffect calls to VDM for virtual context"
This commit is contained in:
committed by
Android (Google) Code Review
commit
3690ef8849
@@ -57,6 +57,7 @@ import android.hardware.input.VirtualNavigationTouchpad;
|
||||
import android.hardware.input.VirtualNavigationTouchpadConfig;
|
||||
import android.hardware.input.VirtualTouchscreen;
|
||||
import android.hardware.input.VirtualTouchscreenConfig;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@@ -302,6 +303,22 @@ public final class VirtualDeviceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests sound effect to be played on virtual device.
|
||||
*
|
||||
* @see android.media.AudioManager#playSoundEffect(int)
|
||||
*
|
||||
* @param deviceId - id of the virtual audio device
|
||||
* @param effectType the type of sound effect
|
||||
* @hide
|
||||
*/
|
||||
public void playSoundEffect(int deviceId, @AudioManager.SystemSoundEffect int effectType) {
|
||||
//TODO - handle requests to play sound effects by custom callbacks or SoundPool asociated
|
||||
// with device session id.
|
||||
// For now, this is intentionally left empty and effectively disables sound effects for
|
||||
// virtual devices with custom device audio policy.
|
||||
}
|
||||
|
||||
/**
|
||||
* A virtual device has its own virtual display, audio output, microphone, and camera etc. The
|
||||
* creator of a virtual device can take the output from the virtual display and stream it over
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package android.media;
|
||||
|
||||
import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
|
||||
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
|
||||
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
@@ -34,6 +38,7 @@ import android.app.compat.CompatChanges;
|
||||
import android.bluetooth.BluetoothCodecConfig;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothLeAudioCodecConfig;
|
||||
import android.companion.virtual.VirtualDeviceManager;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
@@ -100,6 +105,7 @@ public class AudioManager {
|
||||
|
||||
private Context mOriginalContext;
|
||||
private Context mApplicationContext;
|
||||
private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized.
|
||||
private long mVolumeKeyUpTime;
|
||||
private static final String TAG = "AudioManager";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -858,6 +864,14 @@ public class AudioManager {
|
||||
return sService;
|
||||
}
|
||||
|
||||
private VirtualDeviceManager getVirtualDeviceManager() {
|
||||
if (mVirtualDeviceManager != null) {
|
||||
return mVirtualDeviceManager;
|
||||
}
|
||||
mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class);
|
||||
return mVirtualDeviceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a simulated key event for a media button.
|
||||
* To simulate a key press, you must first send a KeyEvent built with a
|
||||
@@ -3635,11 +3649,15 @@ public class AudioManager {
|
||||
* whether sounds are heard or not.
|
||||
* @hide
|
||||
*/
|
||||
public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
|
||||
public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
|
||||
if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (delegateSoundEffectToVdm(effectType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final IAudioService service = getService();
|
||||
try {
|
||||
service.playSoundEffect(effectType, userId);
|
||||
@@ -3657,11 +3675,15 @@ public class AudioManager {
|
||||
* NOTE: This version is for applications that have their own
|
||||
* settings panel for enabling and controlling volume.
|
||||
*/
|
||||
public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
|
||||
public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
|
||||
if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (delegateSoundEffectToVdm(effectType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final IAudioService service = getService();
|
||||
try {
|
||||
service.playSoundEffectVolume(effectType, volume);
|
||||
@@ -3670,6 +3692,28 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this {@link AudioManager} instance is asociated with {@link VirtualDevice}
|
||||
* configured with custom device policy for audio. If there is such device, request to play
|
||||
* sound effect is forwarded to {@link VirtualDeviceManager}.
|
||||
*
|
||||
* @param effectType - The type of sound effect.
|
||||
* @return true if the request was forwarded to {@link VirtualDeviceManager} instance,
|
||||
* false otherwise.
|
||||
*/
|
||||
private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
|
||||
int deviceId = getContext().getDeviceId();
|
||||
if (deviceId != DEVICE_ID_DEFAULT) {
|
||||
VirtualDeviceManager vdm = getVirtualDeviceManager();
|
||||
if (vdm != null && vdm.getDevicePolicy(deviceId, POLICY_TYPE_AUDIO)
|
||||
!= DEVICE_POLICY_DEFAULT) {
|
||||
vdm.playSoundEffect(deviceId, effectType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Sound effects.
|
||||
* This method must be called when sound effects are enabled.
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.mediaframeworktest.unit;
|
||||
|
||||
|
||||
import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
|
||||
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
|
||||
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
|
||||
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
|
||||
import static android.media.AudioManager.FX_KEY_CLICK;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.companion.virtual.VirtualDeviceManager;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.test.mock.MockContext;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AudioManagerUnitTest {
|
||||
private static final int TEST_VIRTUAL_DEVICE_ID = 42;
|
||||
|
||||
@Test
|
||||
public void testAudioManager_playSoundWithDefaultDeviceContext() {
|
||||
VirtualDeviceManager mockVdm = getMockVirtualDeviceManager(TEST_VIRTUAL_DEVICE_ID,
|
||||
DEVICE_POLICY_CUSTOM);
|
||||
Context defaultDeviceContext = getVirtualDeviceMockContext(DEVICE_ID_DEFAULT, /*vdm=*/
|
||||
mockVdm);
|
||||
AudioManager audioManager = new AudioManager(defaultDeviceContext);
|
||||
|
||||
audioManager.playSoundEffect(FX_KEY_CLICK);
|
||||
|
||||
// We expect no interactions with VDM when running on default device.
|
||||
verifyZeroInteractions(mockVdm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAudioManager_playSoundWithVirtualDeviceContextDefaultPolicy() {
|
||||
VirtualDeviceManager mockVdm = getMockVirtualDeviceManager(TEST_VIRTUAL_DEVICE_ID,
|
||||
DEVICE_POLICY_DEFAULT);
|
||||
Context defaultDeviceContext = getVirtualDeviceMockContext(TEST_VIRTUAL_DEVICE_ID, /*vdm=*/
|
||||
mockVdm);
|
||||
AudioManager audioManager = new AudioManager(defaultDeviceContext);
|
||||
|
||||
audioManager.playSoundEffect(FX_KEY_CLICK);
|
||||
|
||||
// We expect playback not to be delegated to VDM because of default device policy for audio.
|
||||
verify(mockVdm, never()).playSoundEffect(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAudioManager_playSoundWithVirtualDeviceContextCustomPolicy() {
|
||||
VirtualDeviceManager mockVdm = getMockVirtualDeviceManager(TEST_VIRTUAL_DEVICE_ID,
|
||||
DEVICE_POLICY_CUSTOM);
|
||||
Context defaultDeviceContext = getVirtualDeviceMockContext(TEST_VIRTUAL_DEVICE_ID, /*vdm=*/
|
||||
mockVdm);
|
||||
AudioManager audioManager = new AudioManager(defaultDeviceContext);
|
||||
|
||||
audioManager.playSoundEffect(FX_KEY_CLICK);
|
||||
|
||||
// We expect playback to be delegated to VDM because of custom device policy for audio.
|
||||
verify(mockVdm, times(1)).playSoundEffect(TEST_VIRTUAL_DEVICE_ID, FX_KEY_CLICK);
|
||||
}
|
||||
|
||||
private static Context getVirtualDeviceMockContext(int deviceId, VirtualDeviceManager vdm) {
|
||||
MockContext mockContext = mock(MockContext.class);
|
||||
when(mockContext.getDeviceId()).thenReturn(deviceId);
|
||||
when(mockContext.getSystemService(VirtualDeviceManager.class)).thenReturn(vdm);
|
||||
return mockContext;
|
||||
}
|
||||
|
||||
private static VirtualDeviceManager getMockVirtualDeviceManager(
|
||||
int deviceId, int audioDevicePolicy) {
|
||||
VirtualDeviceManager vdmMock = mock(VirtualDeviceManager.class);
|
||||
when(vdmMock.getDevicePolicy(anyInt(), anyInt())).thenReturn(DEVICE_POLICY_DEFAULT);
|
||||
when(vdmMock.getDevicePolicy(deviceId, POLICY_TYPE_AUDIO)).thenReturn(audioDevicePolicy);
|
||||
return vdmMock;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user