Merge "AudioService AudioDeviceBroker: fix speakerphone control" into rvc-dev am: bf01a79a83

Change-Id: I922d2be182c9937e82790e8b4ab9b49213d1e2c4
This commit is contained in:
Eric Laurent
2020-05-16 04:07:05 +00:00
committed by Automerger Merge Worker
5 changed files with 232 additions and 57 deletions

View File

@@ -1505,7 +1505,7 @@ public class AudioManager {
public void setSpeakerphoneOn(boolean on){ public void setSpeakerphoneOn(boolean on){
final IAudioService service = getService(); final IAudioService service = getService();
try { try {
service.setSpeakerphoneOn(on); service.setSpeakerphoneOn(mICallBack, on);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -150,7 +150,7 @@ interface IAudioService {
oneway void avrcpSupportsAbsoluteVolume(String address, boolean support); oneway void avrcpSupportsAbsoluteVolume(String address, boolean support);
void setSpeakerphoneOn(boolean on); void setSpeakerphoneOn(IBinder cb, boolean on);
boolean isSpeakerphoneOn(); boolean isSpeakerphoneOn();

View File

@@ -36,6 +36,7 @@ import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter;
@@ -43,6 +44,9 @@ import android.util.PrintWriterPrinter;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.NoSuchElementException;
/** @hide */ /** @hide */
/*package*/ final class AudioDeviceBroker { /*package*/ final class AudioDeviceBroker {
@@ -91,6 +95,9 @@ import java.io.PrintWriter;
// TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055
/*package*/ final Object mSetModeLock = new Object(); /*package*/ final Object mSetModeLock = new Object();
/** PID of current audio mode owner communicated by AudioService */
private int mModeOwnerPid = 0;
//------------------------------------------------------------------- //-------------------------------------------------------------------
/*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) { /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) {
mContext = context; mContext = context;
@@ -136,6 +143,7 @@ import java.io.PrintWriter;
/*package*/ void onSystemReady() { /*package*/ void onSystemReady() {
synchronized (mSetModeLock) { synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
mModeOwnerPid = mAudioService.getModeOwnerPid();
mBtHelper.onSystemReady(); mBtHelper.onSystemReady();
} }
} }
@@ -202,30 +210,57 @@ import java.io.PrintWriter;
* @param eventSource for logging purposes * @param eventSource for logging purposes
* @return true if speakerphone state changed * @return true if speakerphone state changed
*/ */
/*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) { /*package*/ boolean setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
final boolean wasOn = isSpeakerphoneOn(); if (!addSpeakerphoneClient(cb, pid, on)) {
if (on) { return false;
if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
}
mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
} else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
if (mBtHelper.isBluetoothScoOn()) {
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
setForceUse_Async(
AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
} else {
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
} }
final boolean wasOn = isSpeakerphoneOn();
mForcedUseForCommExt = mForcedUseForComm; updateSpeakerphoneOn(eventSource);
setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
return (wasOn != isSpeakerphoneOn()); return (wasOn != isSpeakerphoneOn());
} }
} }
@GuardedBy("mDeviceStateLock")
private void updateSpeakerphoneOn(String eventSource) {
if (isSpeakerphoneOnRequested()) {
if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
}
mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
} else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
if (mBtHelper.isBluetoothScoOn()) {
mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
setForceUse_Async(
AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
} else {
mForcedUseForComm = AudioSystem.FORCE_NONE;
}
}
mForcedUseForCommExt = mForcedUseForComm;
setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
}
/**
* Returns if speakerphone is requested ON or OFF.
* If the current audio mode owner is in the speakerphone client list, use this preference.
* Otherwise use first client's preference (first client corresponds to latest request).
* Speakerphone is requested OFF if no client is in the list.
* @return true if speakerphone is requested ON, false otherwise
*/
@GuardedBy("mDeviceStateLock")
private boolean isSpeakerphoneOnRequested() {
if (mSpeakerphoneClients.isEmpty()) {
return false;
}
for (SpeakerphoneClient cl : mSpeakerphoneClients) {
if (cl.getPid() == mModeOwnerPid) {
return cl.isOn();
}
}
return mSpeakerphoneClients.get(0).isOn();
}
/*package*/ boolean isSpeakerphoneOn() { /*package*/ boolean isSpeakerphoneOn() {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER); return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
@@ -384,7 +419,8 @@ import java.io.PrintWriter;
} }
mForcedUseForComm = AudioSystem.FORCE_BT_SCO; mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
} else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
mForcedUseForComm = AudioSystem.FORCE_NONE; mForcedUseForComm = isSpeakerphoneOnRequested()
? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
} }
mForcedUseForCommExt = mForcedUseForComm; mForcedUseForCommExt = mForcedUseForComm;
AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off")); AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off"));
@@ -429,8 +465,8 @@ import java.io.PrintWriter;
sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType);
} }
/*package*/ void postDisconnectBluetoothSco(int exceptPid) { /*package*/ void postSetModeOwnerPid(int pid) {
sendIMsgNoDelay(MSG_I_DISCONNECT_BT_SCO, SENDMSG_REPLACE, exceptPid); sendIMsgNoDelay(MSG_I_SET_MODE_OWNER_PID, SENDMSG_REPLACE, pid);
} }
/*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) {
@@ -483,7 +519,7 @@ import java.io.PrintWriter;
} }
/*package*/ int getModeOwnerPid() { /*package*/ int getModeOwnerPid() {
return mAudioService.getModeOwnerPid(); return mModeOwnerPid;
} }
/*package*/ int getDeviceForStream(int streamType) { /*package*/ int getDeviceForStream(int streamType) {
@@ -605,6 +641,10 @@ import java.io.PrintWriter;
sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
} }
/*package*/ void postSpeakerphoneClientDied(Object obj) {
sendLMsgNoDelay(MSG_L_SPEAKERPHONE_CLIENT_DIED, SENDMSG_QUEUE, obj);
}
/*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy,
AudioDeviceAttributes device) AudioDeviceAttributes device)
{ {
@@ -674,7 +714,7 @@ import java.io.PrintWriter;
new BtHelper.BluetoothA2dpDeviceInfo(btDevice); new BtHelper.BluetoothA2dpDeviceInfo(btDevice);
return (mBrokerHandler.hasEqualMessages( return (mBrokerHandler.hasEqualMessages(
MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck) MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, devInfoToCheck)
|| mBrokerHandler.hasEqualMessages( || mBrokerHandler.hasEqualMessages(
MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck)); MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, devInfoToCheck));
} }
@@ -707,7 +747,20 @@ import java.io.PrintWriter;
} else { } else {
pw.println("Message handler is null"); pw.println("Message handler is null");
} }
mDeviceInventory.dump(pw, prefix); mDeviceInventory.dump(pw, prefix);
pw.println("\n" + prefix + "mForcedUseForComm: "
+ AudioSystem.forceUseConfigToString(mForcedUseForComm));
pw.println(prefix + "mForcedUseForCommExt: "
+ AudioSystem.forceUseConfigToString(mForcedUseForCommExt));
pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid);
pw.println(prefix + "Speakerphone clients:");
mSpeakerphoneClients.forEach((cl) -> {
pw.println(" " + prefix + "pid: " + cl.getPid() + " on: "
+ cl.isOn() + " cb: " + cl.getBinder()); });
mBtHelper.dump(pw, prefix);
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@@ -877,10 +930,16 @@ import java.io.PrintWriter;
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
} }
break; break;
case MSG_I_DISCONNECT_BT_SCO: case MSG_I_SET_MODE_OWNER_PID:
synchronized (mSetModeLock) { synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
mBtHelper.disconnectBluetoothSco(msg.arg1); if (mModeOwnerPid != msg.arg1) {
mModeOwnerPid = msg.arg1;
updateSpeakerphoneOn("setNewModeOwner");
if (mModeOwnerPid != 0) {
mBtHelper.disconnectBluetoothSco(mModeOwnerPid);
}
}
} }
} }
break; break;
@@ -891,6 +950,11 @@ import java.io.PrintWriter;
} }
} }
break; break;
case MSG_L_SPEAKERPHONE_CLIENT_DIED:
synchronized (mDeviceStateLock) {
speakerphoneClientDied(msg.obj);
}
break;
case MSG_TOGGLE_HDMI: case MSG_TOGGLE_HDMI:
synchronized (mDeviceStateLock) { synchronized (mDeviceStateLock) {
mDeviceInventory.onToggleHdmi(); mDeviceInventory.onToggleHdmi();
@@ -1021,7 +1085,7 @@ import java.io.PrintWriter;
private static final int MSG_REPORT_NEW_ROUTES = 13; private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14; private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
private static final int MSG_I_DISCONNECT_BT_SCO = 16; private static final int MSG_I_SET_MODE_OWNER_PID = 16;
// process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo // process active A2DP device change, obj is BtHelper.BluetoothA2dpDeviceInfo
private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
@@ -1051,6 +1115,8 @@ import java.io.PrintWriter;
private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33; private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33;
private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34;
private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35;
private static boolean isMessageHandledUnderWakelock(int msgId) { private static boolean isMessageHandledUnderWakelock(int msgId) {
switch(msgId) { switch(msgId) {
@@ -1166,4 +1232,93 @@ import java.io.PrintWriter;
time); time);
} }
} }
private class SpeakerphoneClient implements IBinder.DeathRecipient {
private final IBinder mCb;
private final int mPid;
private final boolean mOn;
SpeakerphoneClient(IBinder cb, int pid, boolean on) {
mCb = cb;
mPid = pid;
mOn = on;
}
public boolean registerDeathRecipient() {
boolean status = false;
try {
mCb.linkToDeath(this, 0);
status = true;
} catch (RemoteException e) {
Log.w(TAG, "SpeakerphoneClient could not link to " + mCb + " binder death");
}
return status;
}
public void unregisterDeathRecipient() {
try {
mCb.unlinkToDeath(this, 0);
} catch (NoSuchElementException e) {
Log.w(TAG, "SpeakerphoneClient could not not unregistered to binder");
}
}
@Override
public void binderDied() {
postSpeakerphoneClientDied(this);
}
IBinder getBinder() {
return mCb;
}
int getPid() {
return mPid;
}
boolean isOn() {
return mOn;
}
}
@GuardedBy("mDeviceStateLock")
private void speakerphoneClientDied(Object obj) {
if (obj == null) {
return;
}
Log.w(TAG, "Speaker client died");
if (removeSpeakerphoneClient(((SpeakerphoneClient) obj).getBinder(), false) != null) {
updateSpeakerphoneOn("speakerphoneClientDied");
}
}
private SpeakerphoneClient removeSpeakerphoneClient(IBinder cb, boolean unregister) {
for (SpeakerphoneClient cl : mSpeakerphoneClients) {
if (cl.getBinder() == cb) {
if (unregister) {
cl.unregisterDeathRecipient();
}
mSpeakerphoneClients.remove(cl);
return cl;
}
}
return null;
}
@GuardedBy("mDeviceStateLock")
private boolean addSpeakerphoneClient(IBinder cb, int pid, boolean on) {
// always insert new request at first position
removeSpeakerphoneClient(cb, true);
SpeakerphoneClient client = new SpeakerphoneClient(cb, pid, on);
if (client.registerDeathRecipient()) {
mSpeakerphoneClients.add(0, client);
return true;
}
return false;
}
// List of clients requesting speakerPhone ON
@GuardedBy("mDeviceStateLock")
private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
new ArrayList<SpeakerphoneClient>();
} }

View File

@@ -3567,11 +3567,9 @@ public class AudioService extends IAudioService.Stub
} }
public void binderDied() { public void binderDied() {
int oldModeOwnerPid;
int newModeOwnerPid = 0; int newModeOwnerPid = 0;
synchronized (mDeviceBroker.mSetModeLock) { synchronized (mDeviceBroker.mSetModeLock) {
Log.w(TAG, "setMode() client died"); Log.w(TAG, "setMode() client died");
oldModeOwnerPid = getModeOwnerPid();
int index = mSetModeDeathHandlers.indexOf(this); int index = mSetModeDeathHandlers.indexOf(this);
if (index < 0) { if (index < 0) {
Log.w(TAG, "unregistered setMode() client died"); Log.w(TAG, "unregistered setMode() client died");
@@ -3581,9 +3579,7 @@ public class AudioService extends IAudioService.Stub
} }
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes // SCO connections not started by the application changing the mode when pid changes
if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) { mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid);
}
} }
public int getPid() { public int getPid() {
@@ -3635,17 +3631,20 @@ public class AudioService extends IAudioService.Stub
return; return;
} }
int oldModeOwnerPid;
int newModeOwnerPid; int newModeOwnerPid;
synchronized (mDeviceBroker.mSetModeLock) { synchronized (mDeviceBroker.mSetModeLock) {
if (mode == AudioSystem.MODE_CURRENT) { if (mode == AudioSystem.MODE_CURRENT) {
mode = mMode; mode = mMode;
} }
oldModeOwnerPid = getModeOwnerPid(); int oldModeOwnerPid = getModeOwnerPid();
// Do not allow changing mode if a call is active and the requester // Do not allow changing mode if a call is active and the requester
// does not have permission to modify phone state or is not the mode owner. // does not have permission to modify phone state or is not the mode owner,
if (((mMode == AudioSystem.MODE_IN_CALL) // unless returning to NORMAL mode (will not change current mode owner) or
|| (mMode == AudioSystem.MODE_IN_COMMUNICATION)) // not changing mode in which case the mode owner will reflect the last
// requester of current mode
if (!((mode == mMode) || (mode == AudioSystem.MODE_NORMAL))
&& ((mMode == AudioSystem.MODE_IN_CALL)
|| (mMode == AudioSystem.MODE_IN_COMMUNICATION))
&& !(hasModifyPhoneStatePermission || (oldModeOwnerPid == callingPid))) { && !(hasModifyPhoneStatePermission || (oldModeOwnerPid == callingPid))) {
Log.w(TAG, "setMode(" + mode + ") from pid=" + callingPid Log.w(TAG, "setMode(" + mode + ") from pid=" + callingPid
+ ", uid=" + Binder.getCallingUid() + ", uid=" + Binder.getCallingUid()
@@ -3658,9 +3657,7 @@ public class AudioService extends IAudioService.Stub
} }
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes // SCO connections not started by the application changing the mode when pid changes
if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) { mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid);
mDeviceBroker.postDisconnectBluetoothSco(newModeOwnerPid);
}
} }
// setModeInt() returns a valid PID if the audio mode was successfully set to // setModeInt() returns a valid PID if the audio mode was successfully set to
@@ -3937,32 +3934,18 @@ public class AudioService extends IAudioService.Stub
} }
/** @see AudioManager#setSpeakerphoneOn(boolean) */ /** @see AudioManager#setSpeakerphoneOn(boolean) */
public void setSpeakerphoneOn(boolean on){ public void setSpeakerphoneOn(IBinder cb, boolean on) {
if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
return; return;
} }
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
synchronized (mSetModeDeathHandlers) {
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
if (h.getMode() == AudioSystem.MODE_IN_CALL) {
Log.w(TAG, "getMode is call, Permission Denial: setSpeakerphoneOn from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
return;
}
}
}
}
// for logging only // for logging only
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid(); final int pid = Binder.getCallingPid();
final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on) final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
.append(") from u/pid:").append(uid).append("/") .append(") from u/pid:").append(uid).append("/")
.append(pid).toString(); .append(pid).toString();
final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource); final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(cb, pid, on, eventSource);
new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE
+ MediaMetrics.SEPARATOR + "setSpeakerphoneOn") + MediaMetrics.SEPARATOR + "setSpeakerphoneOn")
.setUid(uid) .setUid(uid)

View File

@@ -38,6 +38,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -131,6 +132,26 @@ public class BtHelper {
} }
} }
/**
* Returns a string representation of the scoAudioState.
*/
public static String scoAudioStateToString(int scoAudioState) {
switch (scoAudioState) {
case SCO_STATE_INACTIVE:
return "SCO_STATE_INACTIVE";
case SCO_STATE_ACTIVATE_REQ:
return "SCO_STATE_ACTIVATE_REQ";
case SCO_STATE_ACTIVE_EXTERNAL:
return "SCO_STATE_ACTIVE_EXTERNAL";
case SCO_STATE_ACTIVE_INTERNAL:
return "SCO_STATE_ACTIVE_INTERNAL";
case SCO_STATE_DEACTIVATING:
return "SCO_STATE_DEACTIVATING";
default:
return "SCO_STATE_(" + scoAudioState + ")";
}
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
/*package*/ static class BluetoothA2dpDeviceInfo { /*package*/ static class BluetoothA2dpDeviceInfo {
private final @NonNull BluetoothDevice mBtDevice; private final @NonNull BluetoothDevice mBtDevice;
@@ -1007,4 +1028,20 @@ public class BtHelper {
return "ENCODING_BT_CODEC_TYPE(" + btCodecType + ")"; return "ENCODING_BT_CODEC_TYPE(" + btCodecType + ")";
} }
} }
//------------------------------------------------------------
/*package*/ void dump(PrintWriter pw, String prefix) {
pw.println("\n" + prefix + "mBluetoothHeadset: " + mBluetoothHeadset);
pw.println(prefix + "mBluetoothHeadsetDevice: " + mBluetoothHeadsetDevice);
pw.println(prefix + "mScoAudioState: " + scoAudioStateToString(mScoAudioState));
pw.println(prefix + "mScoAudioMode: " + scoAudioModeToString(mScoAudioMode));
pw.println(prefix + "Sco clients:");
mScoClients.forEach((cl) -> {
pw.println(" " + prefix + "pid: " + cl.getPid() + " cb: " + cl.getBinder()); });
pw.println("\n" + prefix + "mHearingAid: " + mHearingAid);
pw.println(prefix + "mA2dp: " + mA2dp);
pw.println(prefix + "mAvrcpAbsVolSupported: " + mAvrcpAbsVolSupported);
}
} }