diff options
6 files changed, 66 insertions, 7 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 10146731491c..fee4ed85cf4d 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1458,6 +1458,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable(); method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int requestAudioFocusForTest(@NonNull android.media.AudioFocusRequest, @NonNull String, int, int); method public void setRampingRingerEnabled(boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setTestDeviceConnectionState(@NonNull android.media.AudioDeviceAttributes, boolean); } public static final class AudioRecord.MetricsConstants { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 9bde8c3e59cc..d721291ad78f 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -5776,6 +5776,23 @@ public class AudioManager { } /** + * Indicate wired accessory connection state change. + * @param device {@link AudioDeviceAttributes} of the device to "fake-connect" + * @param connected true for connected, false for disconnected + * {@hide} + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, + boolean connected) { + try { + getService().setTestDeviceConnectionState(device, connected); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Indicate Bluetooth profile connection state change. * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and * <code>previousDevice</code> diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 67f366473134..afcbc5769cf0 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -458,4 +458,6 @@ interface IAudioService { void registerMuteAwaitConnectionDispatcher(in IMuteAwaitConnectionCallback cb, boolean register); + + void setTestDeviceConnectionState(in AudioDeviceAttributes device, boolean connected); } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 3bd723e1187c..e4ac7be6be59 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -508,6 +508,13 @@ import java.util.concurrent.atomic.AtomicBoolean; } } + /*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, + @AudioService.ConnectionState int state) { + synchronized (mDeviceStateLock) { + mDeviceInventory.setTestDeviceConnectionState(device, state); + } + } + /*package*/ static final class BleVolumeInfo { final int mIndex; final int mMaxIndex; @@ -1008,7 +1015,8 @@ import java.util.concurrent.atomic.AtomicBoolean; /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) { synchronized (mDeviceStateLock) { - return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName); + return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName, + false /*for test*/); } } diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index fdb2970f6339..a27e4b77959c 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -224,6 +224,7 @@ public class AudioDeviceInventory { public final String mAddress; public final String mName; public final String mCaller; + public boolean mForTest = false; /*package*/ WiredDeviceConnectionState(int type, @AudioService.ConnectionState int state, String address, String name, String caller) { @@ -521,7 +522,7 @@ public class AudioDeviceInventory { } if (!handleDeviceConnection(wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, - wdcs.mType, wdcs.mAddress, wdcs.mName)) { + wdcs.mType, wdcs.mAddress, wdcs.mName, wdcs.mForTest)) { // change of connection state failed, bailout mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed") .record(); @@ -681,7 +682,7 @@ public class AudioDeviceInventory { * @param device the device whose connection state is queried * @return true if connected */ - @GuardedBy("AudioDeviceBroker.mDeviceStateLock") + // called with AudioDeviceBroker.mDeviceStateLock lock held public boolean isDeviceConnected(@NonNull AudioDeviceAttributes device) { final String key = DeviceInfo.makeDeviceListKey(device.getInternalType(), device.getAddress()); @@ -696,10 +697,12 @@ public class AudioDeviceInventory { * @param device the device type * @param address the address of the device * @param deviceName human-readable name of device + * @param isForTesting if true, not calling AudioSystem for the connection as this is + * just for testing * @return false if an error was reported by AudioSystem */ /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address, - String deviceName) { + String deviceName, boolean isForTesting) { if (AudioService.DEBUG_DEVICES) { Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device) + " address:" + address @@ -722,9 +725,14 @@ public class AudioDeviceInventory { Slog.i(TAG, "deviceInfo:" + di + " is(already)Connected:" + isConnected); } if (connect && !isConnected) { - final int res = mAudioSystem.setDeviceConnectionState(device, - AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName, - AudioSystem.AUDIO_FORMAT_DEFAULT); + final int res; + if (isForTesting) { + res = AudioSystem.AUDIO_STATUS_OK; + } else { + res = mAudioSystem.setDeviceConnectionState(device, + AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName, + AudioSystem.AUDIO_FORMAT_DEFAULT); + } if (res != AudioSystem.AUDIO_STATUS_OK) { final String reason = "not connecting device 0x" + Integer.toHexString(device) + " due to command error " + res; @@ -930,6 +938,15 @@ public class AudioDeviceInventory { } } + /*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, + @AudioService.ConnectionState int state) { + final WiredDeviceConnectionState connection = new WiredDeviceConnectionState( + device.getInternalType(), state, device.getAddress(), + "test device", "com.android.server.audio"); + connection.mForTest = true; + onSetWiredDeviceConnectionState(connection); + } + //------------------------------------------------------------------- // Internal utilities diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 3eeffcb82e27..aa33644357be 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6364,6 +6364,20 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.setWiredDeviceConnectionState(type, state, address, name, caller); } + /** @see AudioManager#setTestDeviceConnectionState(AudioDeviceAttributes, boolean) */ + public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, + boolean connected) { + Objects.requireNonNull(device); + enforceModifyAudioRoutingPermission(); + mDeviceBroker.setTestDeviceConnectionState(device, + connected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED); + // simulate a routing update from native + sendMsg(mAudioHandler, + MSG_ROUTING_UPDATED, + SENDMSG_REPLACE, 0, 0, null, + /*delay*/ 0); + } + /** * @hide * The states that can be used with AudioService.setBluetoothHearingAidDeviceConnectionState() |