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

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

Merge "HapClientService: use looper in test" into main

parents 4cf93b2a 772b68e8
Loading
Loading
Loading
Loading
+73 −70
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.bluetooth.hap;

import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;

import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNullElseGet;
@@ -76,8 +78,9 @@ public class HapClientService extends ProfileService {
    private final AdapterService mAdapterService;
    private final DatabaseManager mDatabaseManager;
    private final Handler mHandler;
    private final Looper mStateMachinesLooper;
    private final HandlerThread mStateMachinesThread;
    private final HapClientNativeInterface mHapClientNativeInterface;
    private final HapClientNativeInterface mNativeInterface;

    @VisibleForTesting
    @GuardedBy("mCallbacks")
@@ -114,14 +117,17 @@ public class HapClientService extends ProfileService {
    }

    public HapClientService(AdapterService adapterService) {
        this(adapterService, null);
        this(adapterService, null, null);
    }

    @VisibleForTesting
    HapClientService(AdapterService adapterService, HapClientNativeInterface nativeInterface) {
    HapClientService(
            AdapterService adapterService,
            Looper looper,
            HapClientNativeInterface nativeInterface) {
        super(adapterService);
        mAdapterService = requireNonNull(adapterService);
        mHapClientNativeInterface =
        mNativeInterface =
                requireNonNullElseGet(
                        nativeInterface,
                        () ->
@@ -129,14 +135,19 @@ public class HapClientService extends ProfileService {
                                        new HapClientNativeCallback(adapterService, this)));
        mDatabaseManager = requireNonNull(mAdapterService.getDatabase());

        // Start handler thread for state machines
        mHandler = new Handler(Looper.getMainLooper());
        mStateMachines.clear();
        if (looper == null) {
            mHandler = new Handler(requireNonNull(Looper.getMainLooper()));
            mStateMachinesThread = new HandlerThread("HapClientService.StateMachines");
            mStateMachinesThread.start();
            mStateMachinesLooper = mStateMachinesThread.getLooper();
        } else {
            mHandler = new Handler(looper);
            mStateMachinesThread = null;
            mStateMachinesLooper = looper;
        }

        // Initialize native interface
        mHapClientNativeInterface.init();
        mNativeInterface.init();

        // Mark service as started
        setHapClient(this);
@@ -162,23 +173,24 @@ public class HapClientService extends ProfileService {
        synchronized (mStateMachines) {
            for (HapClientStateMachine sm : mStateMachines.values()) {
                sm.doQuit();
                sm.cleanup();
            }
            mStateMachines.clear();
        }

        if (mStateMachinesThread != null) {
            try {
                mStateMachinesThread.quitSafely();
                mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS);
            } catch (InterruptedException e) {
                // Do not rethrow as we are shutting down anyway
            }
        }

        // Unregister Handler and stop all queued messages.
        mHandler.removeCallbacksAndMessages(null);

        // Cleanup GATT interface
        mHapClientNativeInterface.cleanup();
        mNativeInterface.cleanup();

        // Cleanup the internals
        mDeviceCurrentPresetMap.clear();
@@ -233,7 +245,6 @@ public class HapClientService extends ProfileService {
            }
            Log.i(TAG, "removeStateMachine: removing state machine for device: " + device);
            sm.doQuit();
            sm.cleanup();
            mStateMachines.remove(device);
        }
    }
@@ -423,7 +434,7 @@ public class HapClientService extends ProfileService {
            if (smConnect == null) {
                Log.e(TAG, "Cannot connect to " + device + " : no state machine");
            }
            smConnect.sendMessage(HapClientStateMachine.CONNECT);
            smConnect.sendMessage(HapClientStateMachine.MESSAGE_CONNECT);
        }

        return true;
@@ -444,7 +455,7 @@ public class HapClientService extends ProfileService {
        synchronized (mStateMachines) {
            HapClientStateMachine sm = mStateMachines.get(device);
            if (sm != null) {
                sm.sendMessage(HapClientStateMachine.DISCONNECT);
                sm.sendMessage(HapClientStateMachine.MESSAGE_DISCONNECT);
            }
        }

@@ -470,12 +481,7 @@ public class HapClientService extends ProfileService {
                return null;
            }
            Log.d(TAG, "Creating a new state machine for " + device);
            sm =
                    HapClientStateMachine.make(
                            device,
                            this,
                            mHapClientNativeInterface,
                            mStateMachinesThread.getLooper());
            sm = new HapClientStateMachine(this, device, mNativeInterface, mStateMachinesLooper);
            mStateMachines.put(device, sm);
            return sm;
        }
@@ -542,7 +548,7 @@ public class HapClientService extends ProfileService {
            return;
        }

        mHapClientNativeInterface.selectActivePreset(device, presetIndex);
        mNativeInterface.selectActivePreset(device, presetIndex);
    }

    @VisibleForTesting
@@ -558,23 +564,23 @@ public class HapClientService extends ProfileService {
            return;
        }

        mHapClientNativeInterface.groupSelectActivePreset(groupId, presetIndex);
        mNativeInterface.groupSelectActivePreset(groupId, presetIndex);
    }

    void switchToNextPreset(BluetoothDevice device) {
        mHapClientNativeInterface.nextActivePreset(device);
        mNativeInterface.nextActivePreset(device);
    }

    void switchToNextPresetForGroup(int groupId) {
        mHapClientNativeInterface.groupNextActivePreset(groupId);
        mNativeInterface.groupNextActivePreset(groupId);
    }

    void switchToPreviousPreset(BluetoothDevice device) {
        mHapClientNativeInterface.previousActivePreset(device);
        mNativeInterface.previousActivePreset(device);
    }

    void switchToPreviousPresetForGroup(int groupId) {
        mHapClientNativeInterface.groupPreviousActivePreset(groupId);
        mNativeInterface.groupPreviousActivePreset(groupId);
    }

    BluetoothHapPresetInfo getPresetInfo(BluetoothDevice device, int presetIndex) {
@@ -585,7 +591,7 @@ public class HapClientService extends ProfileService {
            /* We want native to be called for PTS testing even we have all
             * the data in the cache here
             */
            mHapClientNativeInterface.getPresetInfo(device, presetIndex);
            mNativeInterface.getPresetInfo(device, presetIndex);
        }
        List<BluetoothHapPresetInfo> current_presets = mPresetsMap.get(device);
        if (current_presets != null) {
@@ -614,20 +620,19 @@ public class HapClientService extends ProfileService {
    }

    private int stackEventPresetInfoReasonToProfileStatus(int statusCode) {
        switch (statusCode) {
            case HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO:
                return BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE:
                return BluetoothStatusCodes.REASON_REMOTE_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_DELETED:
                return BluetoothStatusCodes.REASON_REMOTE_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED:
                return BluetoothStatusCodes.REASON_REMOTE_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE:
                return BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST;
            default:
                return BluetoothStatusCodes.ERROR_UNKNOWN;
        }
        return switch (statusCode) {
            case HapClientStackEvent.PRESET_INFO_REASON_ALL_PRESET_INFO ->
                    BluetoothStatusCodes.REASON_LOCAL_STACK_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_UPDATE ->
                    BluetoothStatusCodes.REASON_REMOTE_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_DELETED ->
                    BluetoothStatusCodes.REASON_REMOTE_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_AVAILABILITY_CHANGED ->
                    BluetoothStatusCodes.REASON_REMOTE_REQUEST;
            case HapClientStackEvent.PRESET_INFO_REASON_PRESET_INFO_REQUEST_RESPONSE ->
                    BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST;
            default -> BluetoothStatusCodes.ERROR_UNKNOWN;
        };
    }

    private void notifyPresetInfoChanged(BluetoothDevice device, int infoReason) {
@@ -643,24 +648,23 @@ public class HapClientService extends ProfileService {
    }

    private int stackEventStatusToProfileStatus(int statusCode) {
        switch (statusCode) {
            case HapClientStackEvent.STATUS_SET_NAME_NOT_ALLOWED:
                return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED;
            case HapClientStackEvent.STATUS_OPERATION_NOT_SUPPORTED:
                return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED;
            case HapClientStackEvent.STATUS_OPERATION_NOT_POSSIBLE:
                return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED;
            case HapClientStackEvent.STATUS_INVALID_PRESET_NAME_LENGTH:
                return BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG;
            case HapClientStackEvent.STATUS_INVALID_PRESET_INDEX:
                return BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX;
            case HapClientStackEvent.STATUS_GROUP_OPERATION_NOT_SUPPORTED:
                return BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED;
            case HapClientStackEvent.STATUS_PROCEDURE_ALREADY_IN_PROGRESS:
                return BluetoothStatusCodes.ERROR_UNKNOWN;
            default:
                return BluetoothStatusCodes.ERROR_UNKNOWN;
        }
        return switch (statusCode) {
            case HapClientStackEvent.STATUS_SET_NAME_NOT_ALLOWED ->
                    BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED;
            case HapClientStackEvent.STATUS_OPERATION_NOT_SUPPORTED ->
                    BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED;
            case HapClientStackEvent.STATUS_OPERATION_NOT_POSSIBLE ->
                    BluetoothStatusCodes.ERROR_REMOTE_OPERATION_REJECTED;
            case HapClientStackEvent.STATUS_INVALID_PRESET_NAME_LENGTH ->
                    BluetoothStatusCodes.ERROR_HAP_PRESET_NAME_TOO_LONG;
            case HapClientStackEvent.STATUS_INVALID_PRESET_INDEX ->
                    BluetoothStatusCodes.ERROR_HAP_INVALID_PRESET_INDEX;
            case HapClientStackEvent.STATUS_GROUP_OPERATION_NOT_SUPPORTED ->
                    BluetoothStatusCodes.ERROR_REMOTE_OPERATION_NOT_SUPPORTED;
            case HapClientStackEvent.STATUS_PROCEDURE_ALREADY_IN_PROGRESS ->
                    BluetoothStatusCodes.ERROR_UNKNOWN;
            default -> BluetoothStatusCodes.ERROR_UNKNOWN;
        };
    }

    private boolean isPresetIndexValid(BluetoothDevice device, int presetIndex) {
@@ -717,7 +721,7 @@ public class HapClientService extends ProfileService {
        // WARNING: We should check cache if preset exists and is writable, but then we would still
        //          need a way to trigger this action with an invalid index or on a non-writable
        //          preset for tests purpose.
        mHapClientNativeInterface.setPresetName(device, presetIndex, name);
        mNativeInterface.setPresetName(device, presetIndex, name);
    }

    @VisibleForTesting
@@ -733,7 +737,7 @@ public class HapClientService extends ProfileService {
            return;
        }

        mHapClientNativeInterface.groupSetPresetName(groupId, presetIndex, name);
        mNativeInterface.groupSetPresetName(groupId, presetIndex, name);
    }

    @Override
@@ -912,8 +916,7 @@ public class HapClientService extends ProfileService {
            if (sm == null) {
                if (stackEvent.type == HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED) {
                    switch (stackEvent.valueInt1) {
                        case HapClientStackEvent.CONNECTION_STATE_CONNECTED,
                                HapClientStackEvent.CONNECTION_STATE_CONNECTING -> {
                        case STATE_CONNECTED, STATE_CONNECTING -> {
                            sm = getOrCreateStateMachine(device);
                        }
                        default -> {}
@@ -924,7 +927,7 @@ public class HapClientService extends ProfileService {
                Log.e(TAG, "Cannot process stack event: no state machine: " + stackEvent);
                return;
            }
            sm.sendMessage(HapClientStateMachine.STACK_EVENT, stackEvent);
            sm.sendMessage(HapClientStateMachine.MESSAGE_STACK_EVENT, stackEvent);
        }
    }

+3 −22
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@

package com.android.bluetooth.hap;

import static android.bluetooth.BluetoothProfile.getConnectionStateName;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.IBluetoothHapClient;

@@ -40,12 +42,6 @@ public class HapClientStackEvent {
    public static final int EVENT_TYPE_ON_PRESET_NAME_SET_ERROR = 7;
    public static final int EVENT_TYPE_ON_PRESET_INFO_ERROR = 8;

    // Connection state values as defined in bt_has.h
    static final int CONNECTION_STATE_DISCONNECTED = 0;
    static final int CONNECTION_STATE_CONNECTING = 1;
    static final int CONNECTION_STATE_CONNECTED = 2;
    static final int CONNECTION_STATE_DISCONNECTING = 3;

    // Possible operation results
    /* WARNING: Matches status codes defined in bta_has.h */
    static final int STATUS_NO_ERROR = 0;
@@ -117,7 +113,7 @@ public class HapClientStackEvent {
    private String eventTypeValueInt1ToString(int type, int value) {
        switch (type) {
            case EVENT_TYPE_CONNECTION_STATE_CHANGED:
                return "{state: " + connectionStateValueToString(value) + "}";
                return "{state: " + getConnectionStateName(value) + "}";
            case EVENT_TYPE_DEVICE_AVAILABLE:
                return "{features: " + featuresToString(value) + "}";
            case EVENT_TYPE_DEVICE_FEATURES:
@@ -181,21 +177,6 @@ public class HapClientStackEvent {
        }
    }

    private String connectionStateValueToString(int value) {
        switch (value) {
            case CONNECTION_STATE_DISCONNECTED:
                return "CONNECTION_STATE_DISCONNECTED";
            case CONNECTION_STATE_CONNECTING:
                return "CONNECTION_STATE_CONNECTING";
            case CONNECTION_STATE_CONNECTED:
                return "CONNECTION_STATE_CONNECTED";
            case CONNECTION_STATE_DISCONNECTING:
                return "CONNECTION_STATE_DISCONNECTING";
            default:
                return "CONNECTION_STATE_UNKNOWN!";
        }
    }

    private String statusCodeValueToString(int value) {
        switch (value) {
            case STATUS_NO_ERROR:
+197 −334

File changed.

Preview size limit exceeded, changes collapsed.

+199 −406

File changed.

Preview size limit exceeded, changes collapsed.

+0 −22
Original line number Diff line number Diff line
@@ -37,28 +37,6 @@ public final class HapClientStackEventTest {
        eventStr = event.toString();
        assertThat(eventStr).contains("EVENT_TYPE_UNKNOWN");

        event = new HapClientStackEvent(HapClientStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
        event.valueInt1 = -1;
        eventStr = event.toString();
        assertThat(eventStr).contains("EVENT_TYPE_CONNECTION_STATE_CHANGED");
        assertThat(eventStr).contains("CONNECTION_STATE_UNKNOWN");

        event.valueInt1 = HapClientStackEvent.CONNECTION_STATE_DISCONNECTED;
        eventStr = event.toString();
        assertThat(eventStr).contains("CONNECTION_STATE_DISCONNECTED");

        event.valueInt1 = HapClientStackEvent.CONNECTION_STATE_CONNECTING;
        eventStr = event.toString();
        assertThat(eventStr).contains("CONNECTION_STATE_CONNECTING");

        event.valueInt1 = HapClientStackEvent.CONNECTION_STATE_CONNECTED;
        eventStr = event.toString();
        assertThat(eventStr).contains("CONNECTION_STATE_CONNECTED");

        event.valueInt1 = HapClientStackEvent.CONNECTION_STATE_DISCONNECTING;
        eventStr = event.toString();
        assertThat(eventStr).contains("CONNECTION_STATE_DISCONNECTING");

        event = new HapClientStackEvent(HapClientStackEvent.EVENT_TYPE_DEVICE_AVAILABLE);
        eventStr = event.toString();
        assertThat(eventStr).contains("EVENT_TYPE_DEVICE_AVAILABLE");
Loading