Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5917720a authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4533842 from de0e4b04 to pi-release

Change-Id: Ide7e5b5019cc3dea664955b7d7c9749ee5cf2ad7
parents e7f0d341 de0e4b04
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -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},
@@ -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) {
+60 −0
Original line number Diff line number Diff line
@@ -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(),
@@ -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();
+60 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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;
@@ -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;
@@ -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) {
@@ -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) {
@@ -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");
@@ -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)) {
@@ -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) {
@@ -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);
+12 −0
Original line number Diff line number Diff line
@@ -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();

@@ -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);
}
+84 −0
Original line number Diff line number Diff line
@@ -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;

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