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

Commit e3b51585 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "HFP: Add APIs for set and get active device (2/3)"

parents 8de411ee a0f99bf1
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) {
+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);
+11 −2
Original line number Diff line number Diff line
@@ -308,6 +308,7 @@ final class HeadsetStateMachine extends StateMachine {
                // Headset is disconnecting, stop Virtual call if active.
                terminateScoUsingVirtualVoiceCall();
            }
            mService.connectionStateChanged(device, fromState, toState);
            Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
            intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, fromState);
            intent.putExtra(BluetoothProfile.EXTRA_STATE, toState);
@@ -2443,8 +2444,16 @@ final class HeadsetStateMachine extends StateMachine {
        if (mForceScoAudio) {
            return true;
        }
        return mAudioRouteAllowed && (mVoiceRecognitionStarted || isInCall() || (
                BluetoothHeadset.isInbandRingingSupported(mService) && isRinging()));
        if (!mService.getAudioRouteAllowed()) {
            return false;
        }
        if (isInCall() || mVoiceRecognitionStarted) {
            return true;
        }
        if (isRinging() && BluetoothHeadset.isInbandRingingSupported(mService)) {
            return true;
        }
        return false;
    }

    private boolean okToAcceptConnection(BluetoothDevice device) {