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

Commit aceaeeaa authored by Mudumba Ananth's avatar Mudumba Ananth Committed by Andre Eisenbach
Browse files

HFP 1.7 profile update (4/4)

-> Added HF Indicator support.
-> Sent a Broadcast intent upon receiving AT + BIND and
   AT + BIEV Events with the required parameters
-> Support for sending +BIND response on indicator
   status change

Bug: 19983867
Change-Id: I2580fc771080f1bc92fc4ddd5ca7c7cb57773183
parent ad4922ef
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ static jmethodID method_onAtCops;
static jmethodID method_onAtClcc;
static jmethodID method_onUnknownAt;
static jmethodID method_onKeyPressed;
static jmethodID method_onAtBind;
static jmethodID method_onAtBiev;

static const bthf_interface_t *sBluetoothHfpInterface = NULL;
static jobject mCallbacksObj = NULL;
@@ -377,6 +379,34 @@ static void key_pressed_callback(bt_bdaddr_t* bd_addr) {
    sCallbackEnv->DeleteLocalRef(addr);
}

static void at_bind_callback(char *at_string, bt_bdaddr_t *bd_addr) {
    CHECK_CALLBACK_ENV

    jbyteArray addr = marshall_bda(bd_addr);
    if (addr == NULL)
        return;

    jstring js_at_string = sCallbackEnv->NewStringUTF(at_string);

    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtBind, js_at_string, addr);
    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);

    sCallbackEnv->DeleteLocalRef(js_at_string);
    sCallbackEnv->DeleteLocalRef(addr);
}

static void at_biev_callback(bthf_hf_ind_type_t ind_id, int ind_value, bt_bdaddr_t *bd_addr) {
    CHECK_CALLBACK_ENV

    jbyteArray addr = marshall_bda(bd_addr);
    if (addr == NULL)
        return;

    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtBiev, ind_id, (jint)ind_value, addr);
    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
    sCallbackEnv->DeleteLocalRef(addr);
}

static bthf_callbacks_t sBluetoothHfpCallbacks = {
    sizeof(sBluetoothHfpCallbacks),
    connection_state_callback,
@@ -395,6 +425,8 @@ static bthf_callbacks_t sBluetoothHfpCallbacks = {
    at_cops_callback,
    at_clcc_callback,
    unknown_at_callback,
    at_bind_callback,
    at_biev_callback,
    key_pressed_callback
};

@@ -417,6 +449,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
    method_onAtClcc = env->GetMethodID(clazz, "onAtClcc", "([B)V");
    method_onUnknownAt = env->GetMethodID(clazz, "onUnknownAt", "(Ljava/lang/String;[B)V");
    method_onKeyPressed = env->GetMethodID(clazz, "onKeyPressed", "([B)V");
    method_onAtBind = env->GetMethodID(clazz, "onATBind", "(Ljava/lang/String;[B)V");
    method_onAtBiev = env->GetMethodID(clazz, "onATBiev", "(II[B)V");

    ALOGI("%s: succeeds", __FUNCTION__);
}
@@ -678,6 +712,30 @@ static jboolean cindResponseNative(JNIEnv *env, jobject object,
    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean bindResponseNative(JNIEnv *env,jobject object,
                                jint ind_id, jboolean ind_status,
                                jbyteArray address) {
    ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);

    if (!sBluetoothHfpInterface)
        return JNI_FALSE;

    jbyte *addr = env->GetByteArrayElements(address, NULL);
    if (!addr) {
        jniThrowIOException(env, EINVAL);
        return JNI_FALSE;
    }

    bt_status_t status = sBluetoothHfpInterface->bind_response((bthf_hf_ind_type_t) ind_id,
                   ind_status ? BTHF_HF_IND_ENABLED : BTHF_HF_IND_DISABLED,
                   (bt_bdaddr_t *)addr);

    if (status != BT_STATUS_SUCCESS)
        ALOGE("%s: Failed bind_response, status: %d", __FUNCTION__, status);

    env->ReleaseByteArrayElements(address, addr, 0);
    return (status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE);
}

static jboolean atResponseStringNative(JNIEnv *env, jobject object, jstring response_str,
                                                 jbyteArray address) {
@@ -806,6 +864,7 @@ static JNINativeMethod sMethods[] = {
    {"notifyDeviceStatusNative", "(IIII)Z", (void *) notifyDeviceStatusNative},
    {"copsResponseNative", "(Ljava/lang/String;[B)Z", (void *) copsResponseNative},
    {"cindResponseNative", "(IIIIIII[B)Z", (void *) cindResponseNative},
    {"bindResponseNative", "(IZ[B)Z", (void *)bindResponseNative},
    {"atResponseStringNative", "(Ljava/lang/String;[B)Z", (void *) atResponseStringNative},
    {"atResponseCodeNative", "(II[B)Z", (void *)atResponseCodeNative},
    {"clccResponseNative", "(IIIIZLjava/lang/String;I[B)Z", (void *) clccResponseNative},
+4 −0
Original line number Diff line number Diff line
@@ -64,4 +64,8 @@ final public class HeadsetHalConstants {
    final static int CALL_STATE_INCOMING = 4;
    final static int CALL_STATE_WAITING = 5;
    final static int CALL_STATE_IDLE = 6;

    // Match up with bthf_hf_ind_type_t of bt_hf.h
    final static int HF_INDICATOR_ENHANCED_DRIVER_SAFETY = 1;
    final static int HF_INDICATOR_BATTERY_LEVEL_STATUS = 2;
}
+24 −0
Original line number Diff line number Diff line
@@ -307,6 +307,12 @@ public class HeadsetService extends ProfileService {
            if (service == null) return false;
            return service.disableWBS();
        }

        public void bindResponse(int ind_id, boolean ind_status) {
            HeadsetService service = getService();
            if (service == null) return;
            service.bindResponse(ind_id, ind_status);
        }
    };

    //API methods
@@ -579,6 +585,24 @@ public class HeadsetService extends ProfileService {
        return true;
    }

    private boolean bindResponse(int ind_id, boolean ind_status) {
        for (BluetoothDevice device: getConnectedDevices()) {
            int connectionState = mStateMachine.getConnectionState(device);
            if (connectionState != BluetoothProfile.STATE_CONNECTED &&
                connectionState != BluetoothProfile.STATE_CONNECTING) {
                continue;
            }
            if (DBG) Log.d("Bind Response sent for", device.getAddress());
            Message msg = mStateMachine.obtainMessage(HeadsetStateMachine.BIND_RESPONSE);
            msg.obj = device;
            msg.arg1 = ind_id;
            msg.arg2 = (ind_status == true) ? 1 : 0;
            mStateMachine.sendMessage(msg);
            return true;
        }
        return false;
    }

    @Override
    public void dump(StringBuilder sb) {
        super.dump(sb);
+112 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ final class HeadsetStateMachine extends StateMachine {
    static final int ENABLE_WBS = 16;
    static final int DISABLE_WBS = 17;

    static final int BIND_RESPONSE = 18;

    private static final int STACK_EVENT = 101;
    private static final int DIALING_OUT_TIMEOUT = 102;
@@ -522,6 +523,15 @@ final class HeadsetStateMachine extends StateMachine {
                            }
                            processConnectionEvent(event.valueInt, event.device);
                            break;

                        case EVENT_TYPE_BIND:
                            processAtBind(event.valueString, event.device);
                            break;

                        case EVENT_TYPE_BIEV:
                            processAtBiev(event.valueInt, event.valueInt2, event.device);
                            break;

                        default:
                            Log.e(TAG, "Unexpected event: " + event.type);
                            break;
@@ -924,6 +934,13 @@ final class HeadsetStateMachine extends StateMachine {
                    configureWBSNative(getByteAddress(device),NBS_CODEC);
                }
                    break;
                case BIND_RESPONSE:
                {
                    BluetoothDevice device = (BluetoothDevice) message.obj;
                    bindResponseNative((int)message.arg1, ((message.arg2 == 1) ? true : false),
                                        getByteAddress(device));
                }
                    break;
                case START_VR_TIMEOUT:
                {
                    BluetoothDevice device = (BluetoothDevice) message.obj;
@@ -998,6 +1015,12 @@ final class HeadsetStateMachine extends StateMachine {
                        case EVENT_TYPE_KEY_PRESSED:
                            processKeyPressed(event.device);
                            break;
                        case EVENT_TYPE_BIND:
                            processAtBind(event.valueString, event.device);
                            break;
                        case EVENT_TYPE_BIEV:
                            processAtBiev(event.valueInt, event.valueInt2, event.device);
                            break;
                        default:
                            Log.e(TAG, "Unknown stack event: " + event.type);
                            break;
@@ -1428,6 +1451,12 @@ final class HeadsetStateMachine extends StateMachine {
                        case EVENT_TYPE_KEY_PRESSED:
                            processKeyPressed(event.device);
                            break;
                        case EVENT_TYPE_BIND:
                            processAtBind(event.valueString, event.device);
                            break;
                        case EVENT_TYPE_BIEV:
                            processAtBiev(event.valueInt, event.valueInt2, event.device);
                            break;
                        default:
                            Log.e(TAG, "Unknown stack event: " + event.type);
                            break;
@@ -1770,6 +1799,12 @@ final class HeadsetStateMachine extends StateMachine {
                        case EVENT_TYPE_KEY_PRESSED:
                            processKeyPressed(event.device);
                            break;
                        case EVENT_TYPE_BIND:
                            processAtBind(event.valueString, event.device);
                            break;
                        case EVENT_TYPE_BIEV:
                            processAtBiev(event.valueInt, event.valueInt2, event.device);
                            break;
                        default:
                            Log.e(TAG, "Unexpected event: " + event.type);
                            break;
@@ -3127,6 +3162,65 @@ final class HeadsetStateMachine extends StateMachine {
        }
    }

    private void sendIndicatorIntent(BluetoothDevice device, int ind_id, String ind_value)
    {
        Intent intent = new Intent(BluetoothHeadset.ACTION_HF_INDICATORS_VALUE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        intent.putExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_ID, ind_id);
        if (ind_value != null)
            intent.putExtra(BluetoothHeadset.EXTRA_HF_INDICATORS_IND_VALUE, ind_value);

        mService.sendBroadcast(intent, HeadsetService.BLUETOOTH_PERM);
    }

    private void processAtBind( String at_string, BluetoothDevice device) {
        log("processAtBind processAtBind: " + at_string);

        // Parse the AT String to find the Indicator Ids that are supported
        int ind_id = 0;
        int iter = 0;
        int iter1 = 0;

        while (iter < at_string.length()) {
            iter1 = findChar(',', at_string, iter);
            String id = at_string.substring(iter, iter1);

            try {
                ind_id = new Integer(id);
            } catch (NumberFormatException e) {
                Log.e(TAG, Log.getStackTraceString(new Throwable()));
            }

            switch (ind_id) {
                case HeadsetHalConstants.HF_INDICATOR_ENHANCED_DRIVER_SAFETY :
                    log("Send Broadcast intent for the" +
                        "Enhanced Driver Safety indicator.");
                    sendIndicatorIntent(device, ind_id, null);
                    break;
                case HeadsetHalConstants.HF_INDICATOR_BATTERY_LEVEL_STATUS :
                    log("Send Broadcast intent for the" +
                        "Battery Level indicator.");
                    sendIndicatorIntent(device, ind_id, null);
                    break;
                default:
                    log("Invalid HF Indicator Received");
                    break;
            }

            iter = iter1 + 1; // move past comma
        }
    }

    private void processAtBiev( int ind_id, int ind_value, BluetoothDevice device) {
        log(" Process AT + BIEV Command : " + ind_id + ", " + ind_value);

        String ind_value_str = Integer.toString(ind_value);

        Intent intent = new Intent(BluetoothHeadset.ACTION_HF_INDICATORS_VALUE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
        sendIndicatorIntent(device, ind_id, ind_value_str);
    }

    private void onConnectionStateChanged(int state, byte[] address) {
        StackEvent event = new StackEvent(EVENT_TYPE_CONNECTION_STATE_CHANGED);
        event.valueInt = state;
@@ -3240,6 +3334,21 @@ final class HeadsetStateMachine extends StateMachine {
        sendMessage(STACK_EVENT, event);
    }

    private void onATBind(String atString, byte[] address) {
        StackEvent event = new StackEvent(EVENT_TYPE_BIND);
        event.valueString = atString;
        event.device = getDevice(address);
        sendMessage(STACK_EVENT, event);
    }

    private void onATBiev(int ind_id, int ind_value, byte[] address) {
        StackEvent event = new StackEvent(EVENT_TYPE_BIEV);
        event.valueInt = ind_id;
        event.valueInt2 = ind_value;
        event.device = getDevice(address);
        sendMessage(STACK_EVENT, event);
    }

    private void processIntentBatteryChanged(Intent intent) {
        int batteryLevel = intent.getIntExtra("level", -1);
        int scale = intent.getIntExtra("scale", -1);
@@ -3408,6 +3517,8 @@ final class HeadsetStateMachine extends StateMachine {
    final private static int EVENT_TYPE_UNKNOWN_AT = 15;
    final private static int EVENT_TYPE_KEY_PRESSED = 16;
    final private static int EVENT_TYPE_WBS = 17;
    final private static int EVENT_TYPE_BIND = 18;
    final private static int EVENT_TYPE_BIEV = 19;

    private class StackEvent {
        int type = EVENT_TYPE_NONE;
@@ -3438,6 +3549,7 @@ final class HeadsetStateMachine extends StateMachine {
    private native boolean cindResponseNative(int service, int numActive, int numHeld,
                                              int callState, int signal, int roam,
                                              int batteryCharge, byte[] address);
    private native boolean bindResponseNative(int ind_id, boolean ind_status, byte[] address);
    private native boolean notifyDeviceStatusNative(int networkState, int serviceType, int signal,
                                                    int batteryCharge);