Loading android/app/jni/com_android_bluetooth_hfp.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -799,6 +799,26 @@ static jboolean sendBsirNative(JNIEnv* env, jobject object, jboolean value, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, jbyteArray address) { std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothHfpInterface) return JNI_FALSE; jbyte* addr = env->GetByteArrayElements(address, NULL); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } bt_status_t status = sBluetoothHfpInterface->SetActiveDevice((RawAddress*)addr); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed to set active device, status: %d", status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void*)classInitNative}, {"initializeNative", "(IZ)V", (void*)initializeNative}, Loading @@ -824,6 +844,7 @@ static JNINativeMethod sMethods[] = { (void*)phoneStateChangeNative}, {"setScoAllowedNative", "(Z)Z", (void*)setScoAllowedNative}, {"sendBsirNative", "(Z[B)Z", (void*)sendBsirNative}, {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, }; int register_com_android_bluetooth_hfp(JNIEnv* env) { Loading android/app/src/com/android/bluetooth/a2dp/A2dpService.java +60 −0 Original line number Diff line number Diff line Loading @@ -278,6 +278,48 @@ public class A2dpService extends ProfileService { return mStateMachine.getConnectionState(device); } /** * Set the active device. * * @param device the active device * @return true on success, otherwise false */ public boolean setActiveDevice(BluetoothDevice device) { if (DBG) { Log.d(TAG, "setActiveDevice(): " + device); } enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { return false; } ParcelUuid[] featureUuids = device.getUuids(); if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID)) && !(BluetoothUuid.containsAllUuids(featureUuids, A2DP_SOURCE_SINK_UUIDS))) { Log.e(TAG, "Remote does not have A2dp Sink UUID"); return false; } int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED) { return false; } mStateMachine.sendMessage(A2dpStateMachine.SET_ACTIVE_DEVICE, device); return true; } /** * Get the active device. * * @return the active device or null if no device is active */ public BluetoothDevice getActiveDevice() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mStateMachine.getActiveDevice(); } public boolean setPriority(BluetoothDevice device, int priority) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); Settings.Global.putInt(getContentResolver(), Loading Loading @@ -472,6 +514,24 @@ public class A2dpService extends ProfileService { return service.getConnectionState(device); } @Override public boolean setActiveDevice(BluetoothDevice device) { A2dpService service = getService(); if (service == null) { return false; } return service.setActiveDevice(device); } @Override public BluetoothDevice getActiveDevice() { A2dpService service = getService(); if (service == null) { return null; } return service.getActiveDevice(); } @Override public boolean setPriority(BluetoothDevice device, int priority) { A2dpService service = getService(); Loading android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +60 −2 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ final class A2dpStateMachine extends StateMachine { static final int CONNECT = 1; static final int DISCONNECT = 2; static final int SET_ACTIVE_DEVICE = 3; @VisibleForTesting static final int STACK_EVENT = 101; private static final int CONNECT_TIMEOUT = 201; Loading @@ -82,6 +83,8 @@ final class A2dpStateMachine extends StateMachine { private final AudioManager mAudioManager; private BluetoothCodecConfig[] mCodecConfigPriorities; // mActiveDevice is the connected device that is connected and selected // as active. // mCurrentDevice is the device connected before the state changes // mTargetDevice is the device to be connected // mIncomingDevice is the device connecting to us, valid only in Pending state Loading @@ -104,6 +107,7 @@ final class A2dpStateMachine extends StateMachine { // mCurrentDevice is not null, mTargetDevice is null // Incoming connections Pending // Both mCurrentDevice and mTargetDevice are null private BluetoothDevice mActiveDevice = null; private BluetoothDevice mCurrentDevice = null; private BluetoothDevice mTargetDevice = null; private BluetoothDevice mIncomingDevice = null; Loading Loading @@ -277,12 +281,15 @@ final class A2dpStateMachine extends StateMachine { if (DBG) { Log.d(TAG, "Disconnected process message: " + message.what); } if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null) { if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null || mActiveDevice != null) { Log.e(TAG, "ERROR: not null state in Disconnected: current = " + mCurrentDevice + " target = " + mTargetDevice + " incoming = " + mIncomingDevice); + " target = " + mTargetDevice + " incoming = " + mIncomingDevice + " active = " + mActiveDevice); mCurrentDevice = null; mTargetDevice = null; mIncomingDevice = null; mActiveDevice = null; } boolean retValue = HANDLED; Loading @@ -309,6 +316,13 @@ final class A2dpStateMachine extends StateMachine { case DISCONNECT: // ignore break; case SET_ACTIVE_DEVICE: BluetoothDevice activeDevice = (BluetoothDevice) message.obj; // Cannot set the active device: not connected Log.e(TAG, "Disconnected: Cannot set active device to " + activeDevice); broadcastActiveDevice(null); break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Loading Loading @@ -439,6 +453,13 @@ final class A2dpStateMachine extends StateMachine { deferMessage(message); } break; case SET_ACTIVE_DEVICE: BluetoothDevice activeDevice = (BluetoothDevice) message.obj; // Cannot set the active device: not connected Log.e(TAG, "Pending: Cannot set active device to " + activeDevice); broadcastActiveDevice(null); break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Loading Loading @@ -704,6 +725,21 @@ final class A2dpStateMachine extends StateMachine { } } break; case SET_ACTIVE_DEVICE: { BluetoothDevice device = (BluetoothDevice) message.obj; if (!mCurrentDevice.equals(device)) { Log.e(TAG, "Connected: Cannot set active device to " + device + " : current connected device is " + mCurrentDevice); mActiveDevice = null; } else { if (DBG) { Log.d(TAG, "Connected: Active device set to " + device); } mActiveDevice = device; } broadcastActiveDevice(mActiveDevice); } break; case CONNECT_TIMEOUT: if (mTargetDevice == null) { Log.e(TAG, "CONNECT_TIMEOUT received for unknown device"); Loading Loading @@ -844,6 +880,15 @@ final class A2dpStateMachine extends StateMachine { return devices; } BluetoothDevice getActiveDevice() { synchronized (this) { if (getCurrentState() == mConnected) { return mActiveDevice; } } return null; } boolean isPlaying(BluetoothDevice device) { synchronized (this) { if (device.equals(mPlayingA2dpDevice)) { Loading Loading @@ -997,6 +1042,18 @@ final class A2dpStateMachine extends StateMachine { mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); } private void broadcastActiveDevice(BluetoothDevice device) { if (DBG) { Log.d(TAG, "Active device: " + device); } Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); } private void broadcastAudioState(BluetoothDevice device, int newState, int prevState) { if (DBG) { Loading @@ -1013,6 +1070,7 @@ final class A2dpStateMachine extends StateMachine { } public void dump(StringBuilder sb) { ProfileService.println(sb, "mActiveDevice: " + mActiveDevice); ProfileService.println(sb, "mCurrentDevice: " + mCurrentDevice); ProfileService.println(sb, "mTargetDevice: " + mTargetDevice); ProfileService.println(sb, "mIncomingDevice: " + mIncomingDevice); Loading android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java +12 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,16 @@ public class HeadsetNativeInterface { return sendBsirNative(value, Utils.getByteAddress(device)); } /** * Set the current active headset device for SCO audio * @param device current active SCO device * @return true on success */ @VisibleForTesting public boolean setActiveDevice(BluetoothDevice device) { return setActiveDeviceNative(Utils.getByteAddress(device)); } /* Native methods */ private static native void classInitNative(); Loading Loading @@ -475,4 +485,6 @@ public class HeadsetNativeInterface { private native boolean setScoAllowedNative(boolean value); private native boolean sendBsirNative(boolean value, byte[] address); private native boolean setActiveDeviceNative(byte[] address); } android/app/src/com/android/bluetooth/hfp/HeadsetService.java +84 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.os.BatteryManager; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; Loading @@ -47,6 +48,7 @@ public class HeadsetService extends ProfileService { private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE; private static final int MAX_HEADSET_CONNECTIONS = 1; private BluetoothDevice mActiveDevice; private HandlerThread mStateMachinesThread; private HeadsetStateMachine mStateMachine; private HeadsetNativeInterface mNativeInterface; Loading Loading @@ -443,6 +445,24 @@ public class HeadsetService extends ProfileService { } return service.sendVendorSpecificResultCode(device, command, arg); } @Override public boolean setActiveDevice(BluetoothDevice device) { HeadsetService service = getService(); if (service == null) { return false; } return service.setActiveDevice(device); } @Override public BluetoothDevice getActiveDevice() { HeadsetService service = getService(); if (service == null) { return null; } return service.getActiveDevice(); } } // API methods Loading Loading @@ -586,6 +606,47 @@ public class HeadsetService extends ProfileService { mStateMachine.setForceScoAudio(forced); } /** * Set the active device. * * @param device the active device * @return true on success, otherwise false */ public synchronized boolean setActiveDevice(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (DBG) { Log.d(TAG, "setActiveDevice: " + device); } if (device == null) { // Clear the active device mActiveDevice = null; broadcastActiveDevice(null); return true; } if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { Log.e(TAG, "setActiveDevice: Cannot set " + device + " as active, device is not connected"); return false; } if (!mNativeInterface.setActiveDevice(device)) { Log.e(TAG, "setActiveDevice: Cannot set " + device + " as active in native layer"); return false; } mActiveDevice = device; broadcastActiveDevice(mActiveDevice); return true; } /** * Get the active device. * * @return the active device or null if no device is active */ public synchronized BluetoothDevice getActiveDevice() { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); return mActiveDevice; } boolean connectAudio() { // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); Loading Loading @@ -666,6 +727,29 @@ public class HeadsetService extends ProfileService { return true; } void connectionStateChanged(BluetoothDevice device, int fromState, int toState) { if (fromState != BluetoothProfile.STATE_CONNECTED && toState == BluetoothProfile.STATE_CONNECTED) { // Assume only one connected device setActiveDevice(device); } if (fromState == BluetoothProfile.STATE_CONNECTED && toState != BluetoothProfile.STATE_CONNECTED) { setActiveDevice(null); } } private void broadcastActiveDevice(BluetoothDevice device) { if (DBG) { Log.d(TAG, "broadcastActiveDevice: " + device); } Intent intent = new Intent(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); sendBroadcastAsUser(intent, UserHandle.ALL, HeadsetService.BLUETOOTH_PERM); } @Override public void dump(StringBuilder sb) { super.dump(sb); Loading Loading
android/app/jni/com_android_bluetooth_hfp.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -799,6 +799,26 @@ static jboolean sendBsirNative(JNIEnv* env, jobject object, jboolean value, return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean setActiveDeviceNative(JNIEnv* env, jobject object, jbyteArray address) { std::shared_lock<std::shared_timed_mutex> lock(interface_mutex); if (!sBluetoothHfpInterface) return JNI_FALSE; jbyte* addr = env->GetByteArrayElements(address, NULL); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } bt_status_t status = sBluetoothHfpInterface->SetActiveDevice((RawAddress*)addr); if (status != BT_STATUS_SUCCESS) { ALOGE("Failed to set active device, status: %d", status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void*)classInitNative}, {"initializeNative", "(IZ)V", (void*)initializeNative}, Loading @@ -824,6 +844,7 @@ static JNINativeMethod sMethods[] = { (void*)phoneStateChangeNative}, {"setScoAllowedNative", "(Z)Z", (void*)setScoAllowedNative}, {"sendBsirNative", "(Z[B)Z", (void*)sendBsirNative}, {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative}, }; int register_com_android_bluetooth_hfp(JNIEnv* env) { Loading
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +60 −0 Original line number Diff line number Diff line Loading @@ -278,6 +278,48 @@ public class A2dpService extends ProfileService { return mStateMachine.getConnectionState(device); } /** * Set the active device. * * @param device the active device * @return true on success, otherwise false */ public boolean setActiveDevice(BluetoothDevice device) { if (DBG) { Log.d(TAG, "setActiveDevice(): " + device); } enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { return false; } ParcelUuid[] featureUuids = device.getUuids(); if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID)) && !(BluetoothUuid.containsAllUuids(featureUuids, A2DP_SOURCE_SINK_UUIDS))) { Log.e(TAG, "Remote does not have A2dp Sink UUID"); return false; } int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED) { return false; } mStateMachine.sendMessage(A2dpStateMachine.SET_ACTIVE_DEVICE, device); return true; } /** * Get the active device. * * @return the active device or null if no device is active */ public BluetoothDevice getActiveDevice() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mStateMachine.getActiveDevice(); } public boolean setPriority(BluetoothDevice device, int priority) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); Settings.Global.putInt(getContentResolver(), Loading Loading @@ -472,6 +514,24 @@ public class A2dpService extends ProfileService { return service.getConnectionState(device); } @Override public boolean setActiveDevice(BluetoothDevice device) { A2dpService service = getService(); if (service == null) { return false; } return service.setActiveDevice(device); } @Override public BluetoothDevice getActiveDevice() { A2dpService service = getService(); if (service == null) { return null; } return service.getActiveDevice(); } @Override public boolean setPriority(BluetoothDevice device, int priority) { A2dpService service = getService(); Loading
android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +60 −2 Original line number Diff line number Diff line Loading @@ -63,6 +63,7 @@ final class A2dpStateMachine extends StateMachine { static final int CONNECT = 1; static final int DISCONNECT = 2; static final int SET_ACTIVE_DEVICE = 3; @VisibleForTesting static final int STACK_EVENT = 101; private static final int CONNECT_TIMEOUT = 201; Loading @@ -82,6 +83,8 @@ final class A2dpStateMachine extends StateMachine { private final AudioManager mAudioManager; private BluetoothCodecConfig[] mCodecConfigPriorities; // mActiveDevice is the connected device that is connected and selected // as active. // mCurrentDevice is the device connected before the state changes // mTargetDevice is the device to be connected // mIncomingDevice is the device connecting to us, valid only in Pending state Loading @@ -104,6 +107,7 @@ final class A2dpStateMachine extends StateMachine { // mCurrentDevice is not null, mTargetDevice is null // Incoming connections Pending // Both mCurrentDevice and mTargetDevice are null private BluetoothDevice mActiveDevice = null; private BluetoothDevice mCurrentDevice = null; private BluetoothDevice mTargetDevice = null; private BluetoothDevice mIncomingDevice = null; Loading Loading @@ -277,12 +281,15 @@ final class A2dpStateMachine extends StateMachine { if (DBG) { Log.d(TAG, "Disconnected process message: " + message.what); } if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null) { if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null || mActiveDevice != null) { Log.e(TAG, "ERROR: not null state in Disconnected: current = " + mCurrentDevice + " target = " + mTargetDevice + " incoming = " + mIncomingDevice); + " target = " + mTargetDevice + " incoming = " + mIncomingDevice + " active = " + mActiveDevice); mCurrentDevice = null; mTargetDevice = null; mIncomingDevice = null; mActiveDevice = null; } boolean retValue = HANDLED; Loading @@ -309,6 +316,13 @@ final class A2dpStateMachine extends StateMachine { case DISCONNECT: // ignore break; case SET_ACTIVE_DEVICE: BluetoothDevice activeDevice = (BluetoothDevice) message.obj; // Cannot set the active device: not connected Log.e(TAG, "Disconnected: Cannot set active device to " + activeDevice); broadcastActiveDevice(null); break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Loading Loading @@ -439,6 +453,13 @@ final class A2dpStateMachine extends StateMachine { deferMessage(message); } break; case SET_ACTIVE_DEVICE: BluetoothDevice activeDevice = (BluetoothDevice) message.obj; // Cannot set the active device: not connected Log.e(TAG, "Pending: Cannot set active device to " + activeDevice); broadcastActiveDevice(null); break; case STACK_EVENT: A2dpStackEvent event = (A2dpStackEvent) message.obj; if (DBG) { Loading Loading @@ -704,6 +725,21 @@ final class A2dpStateMachine extends StateMachine { } } break; case SET_ACTIVE_DEVICE: { BluetoothDevice device = (BluetoothDevice) message.obj; if (!mCurrentDevice.equals(device)) { Log.e(TAG, "Connected: Cannot set active device to " + device + " : current connected device is " + mCurrentDevice); mActiveDevice = null; } else { if (DBG) { Log.d(TAG, "Connected: Active device set to " + device); } mActiveDevice = device; } broadcastActiveDevice(mActiveDevice); } break; case CONNECT_TIMEOUT: if (mTargetDevice == null) { Log.e(TAG, "CONNECT_TIMEOUT received for unknown device"); Loading Loading @@ -844,6 +880,15 @@ final class A2dpStateMachine extends StateMachine { return devices; } BluetoothDevice getActiveDevice() { synchronized (this) { if (getCurrentState() == mConnected) { return mActiveDevice; } } return null; } boolean isPlaying(BluetoothDevice device) { synchronized (this) { if (device.equals(mPlayingA2dpDevice)) { Loading Loading @@ -997,6 +1042,18 @@ final class A2dpStateMachine extends StateMachine { mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); } private void broadcastActiveDevice(BluetoothDevice device) { if (DBG) { Log.d(TAG, "Active device: " + device); } Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); } private void broadcastAudioState(BluetoothDevice device, int newState, int prevState) { if (DBG) { Loading @@ -1013,6 +1070,7 @@ final class A2dpStateMachine extends StateMachine { } public void dump(StringBuilder sb) { ProfileService.println(sb, "mActiveDevice: " + mActiveDevice); ProfileService.println(sb, "mCurrentDevice: " + mCurrentDevice); ProfileService.println(sb, "mTargetDevice: " + mTargetDevice); ProfileService.println(sb, "mIncomingDevice: " + mIncomingDevice); Loading
android/app/src/com/android/bluetooth/hfp/HeadsetNativeInterface.java +12 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,16 @@ public class HeadsetNativeInterface { return sendBsirNative(value, Utils.getByteAddress(device)); } /** * Set the current active headset device for SCO audio * @param device current active SCO device * @return true on success */ @VisibleForTesting public boolean setActiveDevice(BluetoothDevice device) { return setActiveDeviceNative(Utils.getByteAddress(device)); } /* Native methods */ private static native void classInitNative(); Loading Loading @@ -475,4 +485,6 @@ public class HeadsetNativeInterface { private native boolean setScoAllowedNative(boolean value); private native boolean sendBsirNative(boolean value, byte[] address); private native boolean setActiveDeviceNative(byte[] address); }
android/app/src/com/android/bluetooth/hfp/HeadsetService.java +84 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.os.BatteryManager; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; Loading @@ -47,6 +48,7 @@ public class HeadsetService extends ProfileService { private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE; private static final int MAX_HEADSET_CONNECTIONS = 1; private BluetoothDevice mActiveDevice; private HandlerThread mStateMachinesThread; private HeadsetStateMachine mStateMachine; private HeadsetNativeInterface mNativeInterface; Loading Loading @@ -443,6 +445,24 @@ public class HeadsetService extends ProfileService { } return service.sendVendorSpecificResultCode(device, command, arg); } @Override public boolean setActiveDevice(BluetoothDevice device) { HeadsetService service = getService(); if (service == null) { return false; } return service.setActiveDevice(device); } @Override public BluetoothDevice getActiveDevice() { HeadsetService service = getService(); if (service == null) { return null; } return service.getActiveDevice(); } } // API methods Loading Loading @@ -586,6 +606,47 @@ public class HeadsetService extends ProfileService { mStateMachine.setForceScoAudio(forced); } /** * Set the active device. * * @param device the active device * @return true on success, otherwise false */ public synchronized boolean setActiveDevice(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); if (DBG) { Log.d(TAG, "setActiveDevice: " + device); } if (device == null) { // Clear the active device mActiveDevice = null; broadcastActiveDevice(null); return true; } if (getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { Log.e(TAG, "setActiveDevice: Cannot set " + device + " as active, device is not connected"); return false; } if (!mNativeInterface.setActiveDevice(device)) { Log.e(TAG, "setActiveDevice: Cannot set " + device + " as active in native layer"); return false; } mActiveDevice = device; broadcastActiveDevice(mActiveDevice); return true; } /** * Get the active device. * * @return the active device or null if no device is active */ public synchronized BluetoothDevice getActiveDevice() { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); return mActiveDevice; } boolean connectAudio() { // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); Loading Loading @@ -666,6 +727,29 @@ public class HeadsetService extends ProfileService { return true; } void connectionStateChanged(BluetoothDevice device, int fromState, int toState) { if (fromState != BluetoothProfile.STATE_CONNECTED && toState == BluetoothProfile.STATE_CONNECTED) { // Assume only one connected device setActiveDevice(device); } if (fromState == BluetoothProfile.STATE_CONNECTED && toState != BluetoothProfile.STATE_CONNECTED) { setActiveDevice(null); } } private void broadcastActiveDevice(BluetoothDevice device) { if (DBG) { Log.d(TAG, "broadcastActiveDevice: " + device); } Intent intent = new Intent(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); sendBroadcastAsUser(intent, UserHandle.ALL, HeadsetService.BLUETOOTH_PERM); } @Override public void dump(StringBuilder sb) { super.dump(sb); Loading