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

Commit d5439144 authored by Edward Jee's avatar Edward Jee Committed by Android (Google) Code Review
Browse files

Merge "Enables AT+ANDROID command in Bluetooth HFP." into klp-dev

parents 766e1e09 ca327271
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -323,3 +323,13 @@ class HeadsetClccResponse {
        mType = type;
    }
}

class HeadsetVendorSpecificResultCode {
    String mCommand;
    String mArg;

    public HeadsetVendorSpecificResultCode(String command, String arg) {
        mCommand = command;
        mArg = arg;
    }
}
+28 −0
Original line number Diff line number Diff line
@@ -263,6 +263,16 @@ public class HeadsetService extends ProfileService {
            if (service == null) return;
            service.clccResponse(index, direction, status, mode, mpty, number, type);
        }

        public boolean sendVendorSpecificResultCode(BluetoothDevice device,
                                                    String command,
                                                    String arg) {
            HeadsetService service = getService();
            if (service == null) {
                return false;
            }
            return service.sendVendorSpecificResultCode(device, command, arg);
        }
    };

    //API methods
@@ -479,4 +489,22 @@ public class HeadsetService extends ProfileService {
            new HeadsetClccResponse(index, direction, status, mode, mpty, number, type));
    }

    private boolean sendVendorSpecificResultCode(BluetoothDevice device,
                                                 String command,
                                                 String arg) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        int connectionState = mStateMachine.getConnectionState(device);
        if (connectionState != BluetoothProfile.STATE_CONNECTED) {
            return false;
        }
        // Currently we support only "+ANDROID".
        if (!command.equals(BluetoothHeadset.VENDOR_RESULT_CODE_COMMAND_ANDROID)) {
            Log.w(TAG, "Disallowed unsolicited result code command: " + command);
            return false;
        }
        mStateMachine.sendMessage(HeadsetStateMachine.SEND_VENDOR_SPECIFIC_RESULT_CODE,
                new HeadsetVendorSpecificResultCode(command, arg));
        return true;
    }

}
+61 −18
Original line number Diff line number Diff line
@@ -62,7 +62,9 @@ import com.android.internal.util.IState;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

final class HeadsetStateMachine extends StateMachine {
@@ -89,9 +91,10 @@ final class HeadsetStateMachine extends StateMachine {
    static final int INTENT_BATTERY_CHANGED = 10;
    static final int DEVICE_STATE_CHANGED = 11;
    static final int SEND_CCLC_RESPONSE = 12;
    static final int SEND_VENDOR_SPECIFIC_RESULT_CODE = 13;

    static final int VIRTUAL_CALL_START = 13;
    static final int VIRTUAL_CALL_STOP = 14;
    static final int VIRTUAL_CALL_START = 14;
    static final int VIRTUAL_CALL_STOP = 15;

    private static final int STACK_EVENT = 101;
    private static final int DIALING_OUT_TIMEOUT = 102;
@@ -102,6 +105,9 @@ final class HeadsetStateMachine extends StateMachine {
    private static final int DIALING_OUT_TIMEOUT_VALUE = 10000;
    private static final int START_VR_TIMEOUT_VALUE = 5000;

    // Keys are AT commands, and values are the company IDs.
    private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID;

    private static final ParcelUuid[] HEADSET_UUIDS = {
        BluetoothUuid.HSP,
        BluetoothUuid.Handsfree,
@@ -159,6 +165,10 @@ final class HeadsetStateMachine extends StateMachine {

    static {
        classInitNative();

        VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID = new HashMap<String, Integer>();
        VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+XEVENT", BluetoothAssignedNumbers.PLANTRONICS);
        VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.put("+ANDROID", BluetoothAssignedNumbers.GOOGLE);
    }

    private HeadsetStateMachine(HeadsetService context) {
@@ -649,6 +659,10 @@ final class HeadsetStateMachine extends StateMachine {
                case SEND_CCLC_RESPONSE:
                    processSendClccResponse((HeadsetClccResponse) message.obj);
                    break;
                case SEND_VENDOR_SPECIFIC_RESULT_CODE:
                    processSendVendorSpecificResultCode(
                            (HeadsetVendorSpecificResultCode) message.obj);
                    break;
                case DIALING_OUT_TIMEOUT:
                    if (mDialingOut) {
                        mDialingOut= false;
@@ -863,6 +877,10 @@ final class HeadsetStateMachine extends StateMachine {
                case SEND_CCLC_RESPONSE:
                    processSendClccResponse((HeadsetClccResponse) message.obj);
                    break;
                case SEND_VENDOR_SPECIFIC_RESULT_CODE:
                    processSendVendorSpecificResultCode(
                            (HeadsetVendorSpecificResultCode) message.obj);
                    break;

                case VIRTUAL_CALL_START:
                    initiateScoUsingVirtualVoiceCall();
@@ -1701,21 +1719,40 @@ final class HeadsetStateMachine extends StateMachine {
        return out.toArray();
    }

    private void processAtXevent(String atString) {
        log("processAtXevent - atString = "+ atString);
        if (atString.startsWith("=") && !atString.startsWith("=?")) {
            Object[] args = generateArgs(atString.substring(1));
            broadcastVendorSpecificEventIntent("+XEVENT",
                                               BluetoothAssignedNumbers.PLANTRONICS,
    /**
     * @return {@code true} if the given string is a valid vendor-specific AT command.
     */
    private boolean processVendorSpecificAt(String atString) {
        log("processVendorSpecificAt - atString = " + atString);

        // Currently we accept only SET type commands.
        int indexOfEqual = atString.indexOf("=");
        if (indexOfEqual == -1) {
            Log.e(TAG, "processVendorSpecificAt: command type error in " + atString);
            return false;
        }

        String command = atString.substring(0, indexOfEqual);
        Integer companyId = VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID.get(command);
        if (companyId == null) {
            Log.e(TAG, "processVendorSpecificAt: unsupported command: " + atString);
            return false;
        }

        String arg = atString.substring(indexOfEqual + 1);
        if (arg.startsWith("?")) {
            Log.e(TAG, "processVendorSpecificAt: command type error in " + atString);
            return false;
        }

        Object[] args = generateArgs(arg);
        broadcastVendorSpecificEventIntent(command,
                                           companyId,
                                           BluetoothHeadset.AT_CMD_TYPE_SET,
                                           args,
                                           mCurrentDevice);
        atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_OK, 0);
        }
        else {
            Log.e(TAG, "processAtXevent: command type error");
            atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
        }
        return true;
    }

    private void processUnknownAt(String atString) {
@@ -1729,9 +1766,7 @@ final class HeadsetStateMachine extends StateMachine {
            processAtCpbs(atCommand.substring(5), commandType);
        else if (atCommand.startsWith("+CPBR"))
            processAtCpbr(atCommand.substring(5), commandType, mCurrentDevice);
        else if (atCommand.startsWith("+XEVENT"))
            processAtXevent(atCommand.substring(7));
        else
        else if (!processVendorSpecificAt(atCommand))
            atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, 0);
    }

@@ -1889,6 +1924,14 @@ final class HeadsetStateMachine extends StateMachine {
                           clcc.mNumber, clcc.mType);
    }

    private void processSendVendorSpecificResultCode(HeadsetVendorSpecificResultCode resultCode) {
        String stringToSend = resultCode.mCommand + ": ";
        if (resultCode.mArg != null) {
            stringToSend += resultCode.mArg;
        }
        atResponseStringNative(stringToSend);
    }

    private String getCurrentDeviceName() {
        String defaultName = "<unknown>";
        if (mCurrentDevice == null) {