Merge "Add locking to AVRCP Target JNI"
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index cc33719..508eda6 100644
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -897,48 +897,27 @@
mProfilesConnected = 0;
mProfilesConnecting = 0;
mProfilesDisconnecting = 0;
- // When BT is being turned on, all adapter properties will be sent in 1
- // callback. At this stage, set the scan mode.
- if (getState() == BluetoothAdapter.STATE_TURNING_ON
- && mScanMode == BluetoothAdapter.SCAN_MODE_NONE) {
- /* mDiscoverableTimeout is part of the
- adapterPropertyChangedCallback received before
- onBluetoothReady */
- if (mDiscoverableTimeout != 0) {
- setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE);
- } else /* if timeout == never (0) at startup */ {
- setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
- }
- /* though not always required, this keeps NV up-to date on first-boot after
- flash */
- setDiscoverableTimeout(mDiscoverableTimeout);
- }
+ // adapterPropertyChangedCallback has already been received. Set the scan mode.
+ setScanMode(AbstractionLayer.BT_SCAN_MODE_CONNECTABLE);
+ // This keeps NV up-to date on first-boot after flash.
+ setDiscoverableTimeout(mDiscoverableTimeout);
}
}
void onBleDisable() {
// Sequence BLE_ON to STATE_OFF - that is _complete_ OFF state.
- // When BT disable is invoked, set the scan_mode to NONE
- // so no incoming connections are possible
debugLog("onBleDisable");
- if (getState() == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
- setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
- }
+ // Set the scan_mode to NONE (no incoming connections).
+ setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
}
void onBluetoothDisable() {
// From STATE_ON to BLE_ON
- // When BT disable is invoked, set the scan_mode to NONE
- // so no incoming connections are possible
-
- //Set flag to indicate we are disabling. When property change of scan mode done
- //continue with disable sequence
debugLog("onBluetoothDisable()");
- if (getState() == BluetoothAdapter.STATE_TURNING_OFF) {
- // Turn off any Device Search/Inquiry
- mService.cancelDiscovery();
- setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
- }
+ // Turn off any Device Search/Inquiry
+ mService.cancelDiscovery();
+ // Set the scan_mode to NONE (no incoming connections).
+ setScanMode(AbstractionLayer.BT_SCAN_MODE_NONE);
}
void discoveryStateChangeCallback(int state) {
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index 55bde40..4191174 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -84,6 +84,12 @@
mNativeInterface.initializeNative();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ if (mAudioManager == null) {
+ Log.e(TAG, "AudioManager service doesn't exist?");
+ } else {
+ // start AudioManager in a known state
+ mAudioManager.setParameters("hfp_enable=false");
+ }
mSmFactory = new HeadsetClientStateMachineFactory();
mStateMachineMap.clear();
@@ -924,4 +930,8 @@
protected void setSMFactory(HeadsetClientStateMachineFactory factory) {
mSmFactory = factory;
}
+
+ AudioManager getAudioManager() {
+ return mAudioManager;
+ }
}
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 5b65b6b..266358c 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -39,8 +39,9 @@
import android.bluetooth.BluetoothHeadsetClientCall;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
-import android.content.Context;
import android.content.Intent;
+import android.media.AudioAttributes;
+import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Looper;
@@ -156,7 +157,6 @@
// indicator
private Pair<Integer, Object> mPendingAction;
- private static AudioManager sAudioManager;
private int mAudioState;
private boolean mAudioWbs;
private int mVoiceRecognitionActive;
@@ -169,6 +169,11 @@
private int mPeerFeatures;
private int mChldFeatures;
+ // This is returned when requesting focus from AudioManager
+ private AudioFocusRequest mAudioFocusRequest;
+
+ private AudioManager mAudioManager;
+
// Accessor for the states, useful for reusing the state machines
public IState getDisconnectedState() {
return mDisconnected;
@@ -690,13 +695,9 @@
HeadsetClientStateMachine(HeadsetClientService context, Looper looper) {
super(TAG, looper);
mService = context;
+ mAudioManager = mService.getAudioManager();
mAdapter = BluetoothAdapter.getDefaultAdapter();
- if (sAudioManager == null) {
- sAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- // Initialize hfp_enable into a known state.
- routeHfpAudio(false);
- }
mAudioState = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
mAudioWbs = false;
mVoiceRecognitionActive = HeadsetClientHalConstants.VR_STATE_STOPPED;
@@ -706,8 +707,8 @@
mIndicatorNetworkSignal = 0;
mIndicatorBatteryLevel = 0;
- sMaxAmVcVol = sAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
- sMinAmVcVol = sAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);
+ sMaxAmVcVol = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);
+ sMinAmVcVol = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);
mOperatorName = null;
mSubscriberInfo = null;
@@ -740,26 +741,53 @@
return hfcsm;
}
- static synchronized void routeHfpAudio(boolean enable) {
+ synchronized void routeHfpAudio(boolean enable) {
+ if (mAudioManager == null) {
+ Log.e(TAG, "AudioManager is null!");
+ return;
+ }
if (DBG) {
Log.d(TAG, "hfp_enable=" + enable);
}
if (enable && !sAudioIsRouted) {
- sAudioManager.setParameters("hfp_enable=true");
+ mAudioManager.setParameters("hfp_enable=true");
} else if (!enable) {
- sAudioManager.setParameters("hfp_enable=false");
+ mAudioManager.setParameters("hfp_enable=false");
}
sAudioIsRouted = enable;
}
+ private AudioFocusRequest requestAudioFocus() {
+ AudioAttributes streamAttributes =
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ .build();
+ AudioFocusRequest focusRequest =
+ new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
+ .setAudioAttributes(streamAttributes)
+ .build();
+ int focusRequestStatus = mAudioManager.requestAudioFocus(focusRequest);
+ if (DBG) {
+ String s = (focusRequestStatus == AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
+ ? "AudioFocus granted" : "AudioFocus NOT granted";
+ Log.d(TAG, "AudioManager requestAudioFocus returned: " + s);
+ }
+ return focusRequest;
+ }
+
public void doQuit() {
Log.d(TAG, "doQuit");
- if (sAudioManager != null) {
- routeHfpAudio(false);
- }
+ routeHfpAudio(false);
+ returnAudioFocusIfNecessary();
quitNow();
}
+ private void returnAudioFocusIfNecessary() {
+ if (mAudioFocusRequest == null) return;
+ mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest);
+ mAudioFocusRequest = null;
+ }
+
static int hfToAmVol(int hfVol) {
int amRange = sMaxAmVcVol - sMinAmVcVol;
int hfRange = MAX_HFP_SCO_VOICE_CALL_VOLUME - MIN_HFP_SCO_VOICE_CALL_VOLUME;
@@ -1025,13 +1053,13 @@
}
}
- int amVol = sAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+ int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
deferMessage(
obtainMessage(HeadsetClientStateMachine.SET_SPEAKER_VOLUME, amVol, 0));
// Mic is either in ON state (full volume) or OFF state. There is no way in
// Android to change the MIC volume.
deferMessage(obtainMessage(HeadsetClientStateMachine.SET_MIC_VOLUME,
- sAudioManager.isMicrophoneMute() ? 0 : 15, 0));
+ mAudioManager.isMicrophoneMute() ? 0 : 15, 0));
// query subscriber info
deferMessage(obtainMessage(HeadsetClientStateMachine.SUBSCRIBER_INFO));
transitionTo(mConnected);
@@ -1361,11 +1389,11 @@
if (event.valueInt == HeadsetClientHalConstants.VOLUME_TYPE_SPK) {
mCommandedSpeakerVolume = hfToAmVol(event.valueInt2);
Log.d(TAG, "AM volume set to " + mCommandedSpeakerVolume);
- sAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
+ mAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
+mCommandedSpeakerVolume, AudioManager.FLAG_SHOW_UI);
} else if (event.valueInt
== HeadsetClientHalConstants.VOLUME_TYPE_MIC) {
- sAudioManager.setMicrophoneMute(event.valueInt2 == 0);
+ mAudioManager.setMicrophoneMute(event.valueInt2 == 0);
}
break;
case StackEvent.EVENT_TYPE_CMD_RESULT:
@@ -1495,7 +1523,7 @@
// We need to set the volume after switching into HFP mode as some Audio HALs
// reset the volume to a known-default on mode switch.
- final int amVol = sAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
+ final int amVol = mAudioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
final int hfVol = amToHfVol(amVol);
if (DBG) {
@@ -1505,18 +1533,19 @@
if (DBG) {
Log.d(TAG, "Setting sampling rate as 16000");
}
- sAudioManager.setParameters("hfp_set_sampling_rate=16000");
+ mAudioManager.setParameters("hfp_set_sampling_rate=16000");
} else {
if (DBG) {
Log.d(TAG, "Setting sampling rate as 8000");
}
- sAudioManager.setParameters("hfp_set_sampling_rate=8000");
+ mAudioManager.setParameters("hfp_set_sampling_rate=8000");
}
if (DBG) {
Log.d(TAG, "hf_volume " + hfVol);
}
routeHfpAudio(true);
- sAudioManager.setParameters("hfp_volume=" + hfVol);
+ mAudioFocusRequest = requestAudioFocus();
+ mAudioManager.setParameters("hfp_volume=" + hfVol);
transitionTo(mAudioOn);
break;
@@ -1590,6 +1619,7 @@
*/
if (NativeInterface.disconnectAudioNative(getByteAddress(mCurrentDevice))) {
routeHfpAudio(false);
+ returnAudioFocusIfNecessary();
}
break;
@@ -1661,6 +1691,7 @@
// is not much we can do here since dropping the call without user consent
// even if the audio connection snapped may not be a good idea.
routeHfpAudio(false);
+ returnAudioFocusIfNecessary();
transitionTo(mConnected);
break;