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

Commit 84f977c6 authored by Sanket Agarwal's avatar Sanket Agarwal
Browse files

Multi HFP connection handling

The basic handling mechanism is to create multiple state machines for
each connection. We route the upper layer (application) and lower layer
(callbacks) appropriately depending on the BluetoothDevice.

The following are implemented:
-- StateMachine creation (garbage collection/deletion still needs work)
-- Device awareness in service to route the messages
-- Cleanup of code and creating a new class for handling native messages

You can do the following with this change:
-- Create multiple connections (simultaneously)
-- Tear down connections

Bug: b/33554547
Bug: b/30984220

Change-Id: If08f24f744b046a393e836c99fcf2288fd698cc2
(cherry picked from commit 98c5bfdf)
parent d3c7d497
Loading
Loading
Loading
Loading
+218 −38
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ static void connection_state_cb(const bt_bdaddr_t* bd_addr,

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  ALOGD("%s: state %d peer_feat %d chld_feat %d", __func__, state, peer_feat, chld_feat);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
                               (jint)state, (jint)peer_feat, (jint)chld_feat,
                               addr);
@@ -101,88 +102,197 @@ static void network_state_cb(const bt_bdaddr_t* bd_addr,
                             bthf_client_network_state_t state) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkState,
                               (jint)state);
                               (jint)state, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void network_roaming_cb(const bt_bdaddr_t* bd_addr,
                               bthf_client_service_type_t type) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkRoaming,
                               (jint)type);
                               (jint)type, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void network_signal_cb(const bt_bdaddr_t* bd_addr, int signal) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNetworkSignal,
                               (jint)signal);
                               (jint)signal, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void battery_level_cb(const bt_bdaddr_t* bd_addr, int level) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onBatteryLevel,
                               (jint)level);
                               (jint)level, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void current_operator_cb(const bt_bdaddr_t* bd_addr, const char* name) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  jstring js_name = sCallbackEnv->NewStringUTF(name);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentOperator,
                               js_name);
                               js_name, addr);
  sCallbackEnv->DeleteLocalRef(js_name);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void call_cb(const bt_bdaddr_t* bd_addr, bthf_client_call_t call) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint)call);

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCall, (jint)call, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void callsetup_cb(const bt_bdaddr_t* bd_addr,
                         bthf_client_callsetup_t callsetup) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }
  ALOGD("callsetup_cb bdaddr %02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2],
        addr[3], addr[4], addr[5]);

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallSetup,
                               (jint)callsetup);
                               (jint)callsetup, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void callheld_cb(const bt_bdaddr_t* bd_addr,
                        bthf_client_callheld_t callheld) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallHeld,
                               (jint)callheld);
                               (jint)callheld, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void resp_and_hold_cb(const bt_bdaddr_t* bd_addr,
                             bthf_client_resp_and_hold_t resp_and_hold) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRespAndHold,
                               (jint)resp_and_hold);
                               (jint)resp_and_hold, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void clip_cb(const bt_bdaddr_t* bd_addr, const char* number) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);

  jstring js_number = sCallbackEnv->NewStringUTF(number);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClip, js_number, addr);
  sCallbackEnv->DeleteLocalRef(js_number);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void call_waiting_cb(const bt_bdaddr_t* bd_addr, const char* number) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  jstring js_number = sCallbackEnv->NewStringUTF(number);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting, js_number);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCallWaiting, js_number, addr);
  sCallbackEnv->DeleteLocalRef(js_number);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void current_calls_cb(const bt_bdaddr_t* bd_addr, int index,
@@ -193,26 +303,56 @@ static void current_calls_cb(const bt_bdaddr_t* bd_addr, int index,
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);

  jstring js_number = sCallbackEnv->NewStringUTF(number);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCurrentCalls, index, dir,
                               state, mpty, js_number);
                               state, mpty, js_number, addr);
  sCallbackEnv->DeleteLocalRef(js_number);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void volume_change_cb(const bt_bdaddr_t* bd_addr,
                             bthf_client_volume_type_t type, int volume) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChange, (jint)type,
                               (jint)volume);
                               (jint)volume, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void cmd_complete_cb(const bt_bdaddr_t* bd_addr,
                            bthf_client_cmd_complete_t type, int cme) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCmdResult, (jint)type,
                               (jint)cme);
                               (jint)cme, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void subscriber_info_cb(const bt_bdaddr_t* bd_addr, const char* name,
@@ -220,18 +360,38 @@ static void subscriber_info_cb(const bt_bdaddr_t* bd_addr, const char* name,
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);

  jstring js_name = sCallbackEnv->NewStringUTF(name);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSubscriberInfo, js_name,
                               (jint)type);
                               (jint)type, addr);
  sCallbackEnv->DeleteLocalRef(js_name);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void in_band_ring_cb(const bt_bdaddr_t* bd_addr,
                            bthf_client_in_band_ring_state_t in_band) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInBandRing,
                               (jint)in_band);
                               (jint)in_band, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void last_voice_tag_number_cb(const bt_bdaddr_t* bd_addr,
@@ -239,16 +399,36 @@ static void last_voice_tag_number_cb(const bt_bdaddr_t* bd_addr,
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);

  jstring js_number = sCallbackEnv->NewStringUTF(number);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onLastVoiceTagNumber,
                               js_number);
                               js_number, addr);
  sCallbackEnv->DeleteLocalRef(js_number);
  sCallbackEnv->DeleteLocalRef(addr);
}

static void ring_indication_cb(const bt_bdaddr_t* bd_addr) {
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid()) return;
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication);

  jbyteArray addr = sCallbackEnv->NewByteArray(sizeof(const bt_bdaddr_t));
  if (!addr) {
    ALOGE("Fail to new jbyteArray bd addr for audio state");
    return;
  }

  sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(const bt_bdaddr_t),
                                   (jbyte*)bd_addr);
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRingIndication, addr);
  sCallbackEnv->DeleteLocalRef(addr);
}

static bthf_client_callbacks_t sBluetoothHfpClientCallbacks = {
@@ -282,29 +462,29 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onAudioStateChanged =
      env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
  method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V");
  method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I)V");
  method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I)V");
  method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I)V");
  method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I)V");
  method_onNetworkState = env->GetMethodID(clazz, "onNetworkState", "(I[B)V");
  method_onNetworkRoaming = env->GetMethodID(clazz, "onNetworkRoaming", "(I[B)V");
  method_onNetworkSignal = env->GetMethodID(clazz, "onNetworkSignal", "(I[B)V");
  method_onBatteryLevel = env->GetMethodID(clazz, "onBatteryLevel", "(I[B)V");
  method_onCurrentOperator =
      env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;)V");
  method_onCall = env->GetMethodID(clazz, "onCall", "(I)V");
  method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I)V");
  method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I)V");
  method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I)V");
  method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;)V");
      env->GetMethodID(clazz, "onCurrentOperator", "(Ljava/lang/String;[B)V");
  method_onCall = env->GetMethodID(clazz, "onCall", "(I[B)V");
  method_onCallSetup = env->GetMethodID(clazz, "onCallSetup", "(I[B)V");
  method_onCallHeld = env->GetMethodID(clazz, "onCallHeld", "(I[B)V");
  method_onRespAndHold = env->GetMethodID(clazz, "onRespAndHold", "(I[B)V");
  method_onClip = env->GetMethodID(clazz, "onClip", "(Ljava/lang/String;[B)V");
  method_onCallWaiting =
      env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;)V");
      env->GetMethodID(clazz, "onCallWaiting", "(Ljava/lang/String;[B)V");
  method_onCurrentCalls =
      env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;)V");
  method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II)V");
  method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II)V");
      env->GetMethodID(clazz, "onCurrentCalls", "(IIIILjava/lang/String;[B)V");
  method_onVolumeChange = env->GetMethodID(clazz, "onVolumeChange", "(II[B)V");
  method_onCmdResult = env->GetMethodID(clazz, "onCmdResult", "(II[B)V");
  method_onSubscriberInfo =
      env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I)V");
  method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I)V");
      env->GetMethodID(clazz, "onSubscriberInfo", "(Ljava/lang/String;I[B)V");
  method_onInBandRing = env->GetMethodID(clazz, "onInBandRing", "(I[B)V");
  method_onLastVoiceTagNumber =
      env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;)V");
  method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "()V");
      env->GetMethodID(clazz, "onLastVoiceTagNumber", "(Ljava/lang/String;[B)V");
  method_onRingIndication = env->GetMethodID(clazz, "onRingIndication", "([B)V");

  ALOGI("%s succeeds", __func__);
}
@@ -729,7 +909,7 @@ static JNINativeMethod sMethods[] = {

int register_com_android_bluetooth_hfpclient(JNIEnv* env) {
  return jniRegisterNativeMethods(
      env, "com/android/bluetooth/hfpclient/HeadsetClientStateMachine",
      env, "com/android/bluetooth/hfpclient/NativeInterface",
      sMethods, NELEM(sMethods));
}

+281 −157

File changed.

Preview size limit exceeded, changes collapsed.

+123 −801

File changed.

Preview size limit exceeded, changes collapsed.

+26 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.bluetooth.hfpclient;

import android.os.HandlerThread;

// Factory so that StateMachine objected can be mocked
public class HeadsetClientStateMachineFactory {
    public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t) {
        return HeadsetClientStateMachine.make(context, t.getLooper());
    }
}
+374 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading