Merge "AudioDeviceVolumeManager: Add APIs for listeners for device volume behavior changes" into tm-dev

This commit is contained in:
Yan Han 2022-03-23 14:44:24 +00:00 committed by Android (Google) Code Review
commit f928348826
7 changed files with 385 additions and 30 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}
//====================

View File

@ -62,7 +62,7 @@ public class AudioServiceTest {
mSpySystemServer = spy(new NoOpSystemServerAdapter());
mSettingsAdapter = new NoOpSettingsAdapter();
mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer,
mSettingsAdapter);
mSettingsAdapter, null);
}
/**

View File

@ -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;
}
}
}

View File

@ -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<>();
}
}