Merge "AudioDeviceVolumeManager: Add APIs for listeners for device volume behavior changes" into tm-dev
This commit is contained in:
commit
f928348826
@ -181,6 +181,80 @@ public class AudioDeviceVolumeManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the OnDeviceVolumeBehaviorChangedListener listeners and
|
||||
* DeviceVolumeBehaviorDispatcherStub
|
||||
*/
|
||||
private final CallbackUtil.LazyListenerManager<OnDeviceVolumeBehaviorChangedListener>
|
||||
mDeviceVolumeBehaviorChangedListenerMgr = new CallbackUtil.LazyListenerManager();
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Interface definition of a callback to be invoked when the volume behavior of an audio device
|
||||
* is updated.
|
||||
*/
|
||||
public interface OnDeviceVolumeBehaviorChangedListener {
|
||||
/**
|
||||
* Called on the listener to indicate that the volume behavior of a device has changed.
|
||||
* @param device the audio device whose volume behavior changed
|
||||
* @param volumeBehavior the new volume behavior of the audio device
|
||||
*/
|
||||
void onDeviceVolumeBehaviorChanged(
|
||||
@NonNull AudioDeviceAttributes device,
|
||||
@AudioManager.DeviceVolumeBehavior int volumeBehavior);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Adds a listener for being notified of changes to any device's volume behavior.
|
||||
* @throws SecurityException if the caller doesn't hold the required permission
|
||||
*/
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.MODIFY_AUDIO_ROUTING,
|
||||
android.Manifest.permission.QUERY_AUDIO_STATE
|
||||
})
|
||||
public void addOnDeviceVolumeBehaviorChangedListener(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull OnDeviceVolumeBehaviorChangedListener listener)
|
||||
throws SecurityException {
|
||||
mDeviceVolumeBehaviorChangedListenerMgr.addListener(executor, listener,
|
||||
"addOnDeviceVolumeBehaviorChangedListener",
|
||||
() -> new DeviceVolumeBehaviorDispatcherStub());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Removes a previously added listener of changes to device volume behavior.
|
||||
*/
|
||||
|
||||
@RequiresPermission(anyOf = {
|
||||
android.Manifest.permission.MODIFY_AUDIO_ROUTING,
|
||||
android.Manifest.permission.QUERY_AUDIO_STATE
|
||||
})
|
||||
public void removeOnDeviceVolumeBehaviorChangedListener(
|
||||
@NonNull OnDeviceVolumeBehaviorChangedListener listener) {
|
||||
mDeviceVolumeBehaviorChangedListenerMgr.removeListener(listener,
|
||||
"removeOnDeviceVolumeBehaviorChangedListener");
|
||||
}
|
||||
|
||||
private final class DeviceVolumeBehaviorDispatcherStub
|
||||
extends IDeviceVolumeBehaviorDispatcher.Stub implements CallbackUtil.DispatcherStub {
|
||||
public void register(boolean register) {
|
||||
try {
|
||||
getService().registerDeviceVolumeBehaviorDispatcher(register, this);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
|
||||
@AudioManager.DeviceVolumeBehavior int volumeBehavior) {
|
||||
mDeviceVolumeBehaviorChangedListenerMgr.callListeners((listener) ->
|
||||
listener.onDeviceVolumeBehaviorChanged(device, volumeBehavior));
|
||||
}
|
||||
}
|
||||
|
||||
private static IAudioService getService() {
|
||||
if (sService != null) {
|
||||
return sService;
|
||||
|
@ -33,6 +33,7 @@ import android.media.IAudioRoutesObserver;
|
||||
import android.media.IAudioServerStateDispatcher;
|
||||
import android.media.ICapturePresetDevicesRoleDispatcher;
|
||||
import android.media.ICommunicationDeviceDispatcher;
|
||||
import android.media.IDeviceVolumeBehaviorDispatcher;
|
||||
import android.media.IMuteAwaitConnectionCallback;
|
||||
import android.media.IPlaybackConfigDispatcher;
|
||||
import android.media.IRecordingConfigDispatcher;
|
||||
@ -44,7 +45,6 @@ import android.media.ISpatializerHeadTrackingModeCallback;
|
||||
import android.media.ISpatializerHeadToSoundStagePoseCallback;
|
||||
import android.media.ISpatializerOutputCallback;
|
||||
import android.media.IVolumeController;
|
||||
import android.media.IVolumeController;
|
||||
import android.media.PlayerBase;
|
||||
import android.media.VolumeInfo;
|
||||
import android.media.VolumePolicy;
|
||||
@ -482,6 +482,10 @@ interface IAudioService {
|
||||
|
||||
void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected);
|
||||
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING,android.Manifest.permission.QUERY_AUDIO_STATE})")
|
||||
void registerDeviceVolumeBehaviorDispatcher(boolean register,
|
||||
in IDeviceVolumeBehaviorDispatcher dispatcher);
|
||||
|
||||
List<AudioFocusInfo> getFocusStack();
|
||||
|
||||
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 android.media;
|
||||
|
||||
import android.media.AudioDeviceAttributes;
|
||||
|
||||
/**
|
||||
* AIDL for AudioService to signal changes to an audio device's volume behavior
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IDeviceVolumeBehaviorDispatcher {
|
||||
|
||||
void dispatchDeviceVolumeBehaviorChanged(in AudioDeviceAttributes device,
|
||||
int deviceVolumeBehavior);
|
||||
|
||||
}
|
@ -96,6 +96,7 @@ import android.media.IAudioServerStateDispatcher;
|
||||
import android.media.IAudioService;
|
||||
import android.media.ICapturePresetDevicesRoleDispatcher;
|
||||
import android.media.ICommunicationDeviceDispatcher;
|
||||
import android.media.IDeviceVolumeBehaviorDispatcher;
|
||||
import android.media.IMuteAwaitConnectionCallback;
|
||||
import android.media.IPlaybackConfigDispatcher;
|
||||
import android.media.IRecordingConfigDispatcher;
|
||||
@ -341,6 +342,7 @@ public class AudioService extends IAudioService.Stub
|
||||
private static final int MSG_ADD_ASSISTANT_SERVICE_UID = 44;
|
||||
private static final int MSG_REMOVE_ASSISTANT_SERVICE_UID = 45;
|
||||
private static final int MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID = 46;
|
||||
private static final int MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR = 47;
|
||||
|
||||
// start of messages handled under wakelock
|
||||
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
|
||||
@ -876,13 +878,23 @@ public class AudioService extends IAudioService.Stub
|
||||
|
||||
/** @hide */
|
||||
public AudioService(Context context) {
|
||||
this(context, AudioSystemAdapter.getDefaultAdapter(),
|
||||
this(context,
|
||||
AudioSystemAdapter.getDefaultAdapter(),
|
||||
SystemServerAdapter.getDefaultAdapter(context),
|
||||
SettingsAdapter.getDefaultAdapter());
|
||||
SettingsAdapter.getDefaultAdapter(),
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param audioSystem Adapter for {@link AudioSystem}
|
||||
* @param systemServer Adapter for privilieged functionality for system server components
|
||||
* @param settings Adapter for {@link Settings}
|
||||
* @param looper Looper to use for the service's message handler. If this is null, an
|
||||
* {@link AudioSystemThread} is created as the messaging thread instead.
|
||||
*/
|
||||
public AudioService(Context context, AudioSystemAdapter audioSystem,
|
||||
SystemServerAdapter systemServer, SettingsAdapter settings) {
|
||||
SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper) {
|
||||
sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()"));
|
||||
mContext = context;
|
||||
mContentResolver = context.getContentResolver();
|
||||
@ -1010,7 +1022,11 @@ public class AudioService extends IAudioService.Stub
|
||||
MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
|
||||
}
|
||||
|
||||
createAudioSystemThread();
|
||||
if (looper == null) {
|
||||
createAudioSystemThread();
|
||||
} else {
|
||||
mAudioHandler = new AudioHandler(looper);
|
||||
}
|
||||
|
||||
AudioSystem.setErrorCallback(mAudioSystemCallback);
|
||||
|
||||
@ -6457,34 +6473,41 @@ public class AudioService extends IAudioService.Stub
|
||||
return;
|
||||
}
|
||||
|
||||
int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
|
||||
device.getType());
|
||||
setDeviceVolumeBehaviorInternal(audioSystemDeviceOut, deviceVolumeBehavior, pkgName);
|
||||
|
||||
persistDeviceVolumeBehavior(audioSystemDeviceOut, deviceVolumeBehavior);
|
||||
setDeviceVolumeBehaviorInternal(device, deviceVolumeBehavior, pkgName);
|
||||
persistDeviceVolumeBehavior(device.getInternalType(), deviceVolumeBehavior);
|
||||
}
|
||||
|
||||
private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
|
||||
private void setDeviceVolumeBehaviorInternal(@NonNull AudioDeviceAttributes device,
|
||||
@AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
|
||||
int audioSystemDeviceOut = device.getInternalType();
|
||||
boolean volumeBehaviorChanged = false;
|
||||
// update device masks based on volume behavior
|
||||
switch (deviceVolumeBehavior) {
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
|
||||
removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
|
||||
removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
|
||||
volumeBehaviorChanged |=
|
||||
removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut)
|
||||
| removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
|
||||
break;
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED:
|
||||
removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut);
|
||||
addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut);
|
||||
volumeBehaviorChanged |=
|
||||
removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut)
|
||||
| addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut);
|
||||
break;
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL:
|
||||
addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut);
|
||||
removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
|
||||
volumeBehaviorChanged |=
|
||||
addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut)
|
||||
| removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut);
|
||||
break;
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
|
||||
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
|
||||
throw new IllegalArgumentException("Absolute volume unsupported for now");
|
||||
}
|
||||
|
||||
if (volumeBehaviorChanged) {
|
||||
sendMsg(mAudioHandler, MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR, SENDMSG_QUEUE,
|
||||
deviceVolumeBehavior, 0, device, /*delay*/ 0);
|
||||
}
|
||||
|
||||
// log event and caller
|
||||
sDeviceLogger.log(new AudioEventLogger.StringEvent(
|
||||
"Volume behavior " + deviceVolumeBehavior + " for dev=0x"
|
||||
@ -7761,6 +7784,14 @@ public class AudioService extends IAudioService.Stub
|
||||
/** Handles internal volume messages in separate volume thread. */
|
||||
private class AudioHandler extends Handler {
|
||||
|
||||
AudioHandler() {
|
||||
super();
|
||||
}
|
||||
|
||||
AudioHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
private void setAllVolumes(VolumeStreamState streamState) {
|
||||
|
||||
// Apply volume
|
||||
@ -8063,6 +8094,10 @@ public class AudioService extends IAudioService.Stub
|
||||
case MSG_UPDATE_ACTIVE_ASSISTANT_SERVICE_UID:
|
||||
updateActiveAssistantServiceUids();
|
||||
break;
|
||||
|
||||
case MSG_DISPATCH_DEVICE_VOLUME_BEHAVIOR:
|
||||
dispatchDeviceVolumeBehavior((AudioDeviceAttributes) msg.obj, msg.arg1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9080,6 +9115,35 @@ public class AudioService extends IAudioService.Stub
|
||||
mMuteAwaitConnectionDispatchers.finishBroadcast();
|
||||
}
|
||||
|
||||
final RemoteCallbackList<IDeviceVolumeBehaviorDispatcher> mDeviceVolumeBehaviorDispatchers =
|
||||
new RemoteCallbackList<IDeviceVolumeBehaviorDispatcher>();
|
||||
|
||||
/**
|
||||
* @see AudioDeviceVolumeManager#addOnDeviceVolumeBehaviorChangedListener and
|
||||
* AudioDeviceVolumeManager#removeOnDeviceVolumeBehaviorChangedListener
|
||||
*/
|
||||
public void registerDeviceVolumeBehaviorDispatcher(boolean register,
|
||||
@NonNull IDeviceVolumeBehaviorDispatcher dispatcher) {
|
||||
enforceQueryStateOrModifyRoutingPermission();
|
||||
Objects.requireNonNull(dispatcher);
|
||||
if (register) {
|
||||
mDeviceVolumeBehaviorDispatchers.register(dispatcher);
|
||||
} else {
|
||||
mDeviceVolumeBehaviorDispatchers.unregister(dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchDeviceVolumeBehavior(AudioDeviceAttributes device, int volumeBehavior) {
|
||||
final int dispatchers = mDeviceVolumeBehaviorDispatchers.beginBroadcast();
|
||||
for (int i = 0; i < dispatchers; i++) {
|
||||
try {
|
||||
mDeviceVolumeBehaviorDispatchers.getBroadcastItem(i)
|
||||
.dispatchDeviceVolumeBehaviorChanged(device, volumeBehavior);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
mDeviceVolumeBehaviorDispatchers.finishBroadcast();
|
||||
}
|
||||
|
||||
//==========================================================================================
|
||||
// Device orientation
|
||||
@ -9310,14 +9374,20 @@ public class AudioService extends IAudioService.Stub
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "CEC sink: setting HDMI as full vol device");
|
||||
}
|
||||
addAudioSystemDeviceOutToFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
|
||||
setDeviceVolumeBehaviorInternal(
|
||||
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
|
||||
"AudioService.updateHdmiCecSinkLocked()");
|
||||
} else {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
|
||||
}
|
||||
// Android TV devices without CEC service apply software volume on
|
||||
// HDMI output
|
||||
removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI);
|
||||
setDeviceVolumeBehaviorInternal(
|
||||
new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
|
||||
"AudioService.updateHdmiCecSinkLocked()");
|
||||
}
|
||||
postUpdateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI,
|
||||
"HdmiPlaybackClient.DisplayStatusCallback");
|
||||
@ -11463,8 +11533,8 @@ public class AudioService extends IAudioService.Stub
|
||||
continue;
|
||||
}
|
||||
|
||||
setDeviceVolumeBehaviorInternal(deviceType, deviceVolumeBehavior,
|
||||
"AudioService.restoreDeviceVolumeBehavior()");
|
||||
setDeviceVolumeBehaviorInternal(new AudioDeviceAttributes(deviceType, ""),
|
||||
deviceVolumeBehavior, "AudioService.restoreDeviceVolumeBehavior()");
|
||||
}
|
||||
}
|
||||
|
||||
@ -11479,36 +11549,36 @@ public class AudioService extends IAudioService.Stub
|
||||
!= AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET;
|
||||
}
|
||||
|
||||
private void addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) {
|
||||
private boolean addAudioSystemDeviceOutToFixedVolumeDevices(int audioSystemDeviceOut) {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
|
||||
+ " to mFixedVolumeDevices");
|
||||
}
|
||||
mFixedVolumeDevices.add(audioSystemDeviceOut);
|
||||
return mFixedVolumeDevices.add(audioSystemDeviceOut);
|
||||
}
|
||||
|
||||
private void removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) {
|
||||
private boolean removeAudioSystemDeviceOutFromFixedVolumeDevices(int audioSystemDeviceOut) {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
|
||||
+ " from mFixedVolumeDevices");
|
||||
}
|
||||
mFixedVolumeDevices.remove(audioSystemDeviceOut);
|
||||
return mFixedVolumeDevices.remove(audioSystemDeviceOut);
|
||||
}
|
||||
|
||||
private void addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) {
|
||||
private boolean addAudioSystemDeviceOutToFullVolumeDevices(int audioSystemDeviceOut) {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
|
||||
+ " to mFullVolumeDevices");
|
||||
}
|
||||
mFullVolumeDevices.add(audioSystemDeviceOut);
|
||||
return mFullVolumeDevices.add(audioSystemDeviceOut);
|
||||
}
|
||||
|
||||
private void removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) {
|
||||
private boolean removeAudioSystemDeviceOutFromFullVolumeDevices(int audioSystemDeviceOut) {
|
||||
if (DEBUG_VOL) {
|
||||
Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
|
||||
+ " from mFullVolumeDevices");
|
||||
}
|
||||
mFullVolumeDevices.remove(audioSystemDeviceOut);
|
||||
return mFullVolumeDevices.remove(audioSystemDeviceOut);
|
||||
}
|
||||
|
||||
//====================
|
||||
|
@ -62,7 +62,7 @@ public class AudioServiceTest {
|
||||
mSpySystemServer = spy(new NoOpSystemServerAdapter());
|
||||
mSettingsAdapter = new NoOpSettingsAdapter();
|
||||
mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer,
|
||||
mSettingsAdapter);
|
||||
mSettingsAdapter, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.server.audio;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.media.AudioDeviceAttributes;
|
||||
import android.media.AudioDeviceInfo;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IDeviceVolumeBehaviorDispatcher;
|
||||
import android.os.test.TestLooper;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for AudioService's tracking and reporting of device volume behaviors.
|
||||
*/
|
||||
public class DeviceVolumeBehaviorTest {
|
||||
private static final String TAG = "DeviceVolumeBehaviorTest";
|
||||
|
||||
private static final String PACKAGE_NAME = "";
|
||||
private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
|
||||
AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
|
||||
|
||||
private Context mContext;
|
||||
private AudioSystemAdapter mAudioSystem;
|
||||
private SystemServerAdapter mSystemServer;
|
||||
private SettingsAdapter mSettingsAdapter;
|
||||
private TestLooper mTestLooper;
|
||||
|
||||
private AudioService mAudioService;
|
||||
|
||||
/**
|
||||
* Volume behaviors that can be set using AudioService#setDeviceVolumeBehavior
|
||||
*/
|
||||
public static final int[] BASIC_VOLUME_BEHAVIORS = {
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED
|
||||
};
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mTestLooper = new TestLooper();
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mAudioSystem = new NoOpAudioSystemAdapter();
|
||||
mSystemServer = new NoOpSystemServerAdapter();
|
||||
mSettingsAdapter = new NoOpSettingsAdapter();
|
||||
mAudioService = new AudioService(mContext, mAudioSystem, mSystemServer,
|
||||
mSettingsAdapter, mTestLooper.getLooper());
|
||||
mTestLooper.dispatchAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setDeviceVolumeBehavior_changesDeviceVolumeBehavior() {
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
for (int behavior : BASIC_VOLUME_BEHAVIORS) {
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, behavior, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
int actualBehavior = mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT);
|
||||
|
||||
assertWithMessage("Expected volume behavior to be " + behavior
|
||||
+ " but was instead " + actualBehavior)
|
||||
.that(actualBehavior).isEqualTo(behavior);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setToNewBehavior_triggersDeviceVolumeBehaviorDispatcher() {
|
||||
TestDeviceVolumeBehaviorDispatcherStub dispatcher =
|
||||
new TestDeviceVolumeBehaviorDispatcherStub();
|
||||
mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
|
||||
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
for (int behavior : BASIC_VOLUME_BEHAVIORS) {
|
||||
dispatcher.reset();
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT, behavior, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
assertThat(dispatcher.mTimesCalled).isEqualTo(1);
|
||||
assertThat(dispatcher.mDevice).isEqualTo(DEVICE_SPEAKER_OUT);
|
||||
assertWithMessage("Expected dispatched volume behavior to be " + behavior
|
||||
+ " but was instead " + dispatcher.mVolumeBehavior)
|
||||
.that(dispatcher.mVolumeBehavior).isEqualTo(behavior);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setToSameBehavior_doesNotTriggerDeviceVolumeBehaviorDispatcher() {
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
TestDeviceVolumeBehaviorDispatcherStub dispatcher =
|
||||
new TestDeviceVolumeBehaviorDispatcherStub();
|
||||
mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
|
||||
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
assertThat(dispatcher.mTimesCalled).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisterDeviceVolumeBehaviorDispatcher_noLongerTriggered() {
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
|
||||
TestDeviceVolumeBehaviorDispatcherStub dispatcher =
|
||||
new TestDeviceVolumeBehaviorDispatcherStub();
|
||||
mAudioService.registerDeviceVolumeBehaviorDispatcher(true, dispatcher);
|
||||
mAudioService.registerDeviceVolumeBehaviorDispatcher(false, dispatcher);
|
||||
|
||||
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
|
||||
AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL, PACKAGE_NAME);
|
||||
mTestLooper.dispatchAll();
|
||||
assertThat(dispatcher.mTimesCalled).isEqualTo(0);
|
||||
}
|
||||
|
||||
private static class TestDeviceVolumeBehaviorDispatcherStub
|
||||
extends IDeviceVolumeBehaviorDispatcher.Stub {
|
||||
|
||||
private AudioDeviceAttributes mDevice;
|
||||
private int mVolumeBehavior;
|
||||
private int mTimesCalled;
|
||||
|
||||
@Override
|
||||
public void dispatchDeviceVolumeBehaviorChanged(@NonNull AudioDeviceAttributes device,
|
||||
@AudioManager.DeviceVolumeBehavior int volumeBehavior) {
|
||||
mDevice = device;
|
||||
mVolumeBehavior = volumeBehavior;
|
||||
mTimesCalled++;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mTimesCalled = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,10 +17,12 @@
|
||||
package com.android.server.audio;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioDeviceAttributes;
|
||||
import android.media.AudioSystem;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -122,4 +124,11 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter {
|
||||
public boolean isStreamActive(int stream, int inPastMs) {
|
||||
return mIsStreamActive;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ArrayList<AudioDeviceAttributes> getDevicesForAttributes(
|
||||
@NonNull AudioAttributes attributes, boolean forVolume) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user