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

Commit 6653a60c authored by Jakub Tyszkowski's avatar Jakub Tyszkowski
Browse files

MediaControl: Improve logging

Adds the event history logging and improves the existing logs.

Bug: 278964409
Test: atest BluetoothInstrumentationTests
Change-Id: I1f44a3efd67f26f48ad11f2da68734c10c1679fb
parent 78ba78c9
Loading
Loading
Loading
Loading
+161 −44
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;

import com.android.bluetooth.BluetoothEventLogger;
import com.android.bluetooth.Utils;
import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.AdapterService;
@@ -133,7 +134,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    private static final int INTERVAL_UNAVAILABLE = 0xFFFFFFFF;

    private final int mCcid;
    private HashMap<String, HashMap<UUID, Short>> mCccDescriptorValues;
    private Map<String, Map<UUID, Short>> mCccDescriptorValues = new HashMap<>();
    private long mFeatures;
    private Context mContext;
    private MediaControlServiceCallbacks mCallbacks;
@@ -147,6 +148,9 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    private LeAudioService mLeAudioService;
    private AdapterService mAdapterService;

    private static final int LOG_NB_EVENTS = 200;
    private final BluetoothEventLogger mEventLogger;

    private static String mcsUuidToString(UUID uuid) {
        if (uuid.equals(UUID_PLAYER_NAME)) {
            return "PLAYER_NAME";
@@ -388,9 +392,20 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    }

    private void onUnauthorizedGattOperation(BluetoothDevice device, GattOpContext op) {
        if (VDBG) {
            Log.d(TAG, "onUnauthorizedGattOperation device: " + device);
        }
        UUID charUuid =
                (op.mCharacteristic != null
                        ? op.mCharacteristic.getUuid()
                        : (op.mDescriptor != null
                                ? op.mDescriptor.getCharacteristic().getUuid()
                                : null));
        mEventLogger.logw(
                TAG,
                "onUnauthorizedGattOperation: device= "
                        + device
                        + ", opcode= "
                        + op.mOperation
                        + ", characteristic= "
                        + (charUuid != null ? mcsUuidToString(charUuid) : "UNKNOWN"));

        synchronized (mPendingGattOperations) {
            List<GattOpContext> operations = mPendingGattOperations.get(device);
@@ -408,11 +423,23 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    }

    private void onAuthorizedGattOperation(BluetoothDevice device, GattOpContext op) {
        int status = BluetoothGatt.GATT_SUCCESS;
        UUID charUuid =
                (op.mCharacteristic != null
                        ? op.mCharacteristic.getUuid()
                        : (op.mDescriptor != null
                                ? op.mDescriptor.getCharacteristic().getUuid()
                                : null));
        mEventLogger.logd(
                DBG,
                TAG,
                "onAuthorizedGattOperation: device= "
                        + device
                        + ", opcode= "
                        + op.mOperation
                        + ", characteristic= "
                        + (charUuid != null ? mcsUuidToString(charUuid) : "UNKNOWN"));

        if (VDBG) {
            Log.d(TAG, "onAuthorizedGattOperation device: " + device);
        }
        int status = BluetoothGatt.GATT_SUCCESS;

        switch (op.mOperation) {
            case READ_CHARACTERISTIC:
@@ -511,7 +538,20 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    }

    private void onRejectedAuthorizationGattOperation(BluetoothDevice device, GattOpContext op) {
        Log.w(TAG, "onRejectedAuthorizationGattOperation device: " + device);
        UUID charUuid =
                (op.mCharacteristic != null
                        ? op.mCharacteristic.getUuid()
                        : (op.mDescriptor != null
                                ? op.mDescriptor.getCharacteristic().getUuid()
                                : null));
        mEventLogger.logw(
                TAG,
                "onRejectedAuthorizationGattOperation: device= "
                        + device
                        + ", opcode= "
                        + op.mOperation
                        + ", characteristic= "
                        + (charUuid != null ? mcsUuidToString(charUuid) : "UNKNOWN"));

        switch (op.mOperation) {
            case READ_CHARACTERISTIC:
@@ -548,7 +588,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

    private void ClearUnauthorizedGattOperations(BluetoothDevice device) {
        if (VDBG) {
            Log.d(TAG, "ClearUnauthorizedGattOperations device: " + device);
            Log.d(TAG, "ClearUnauthorizedGattOperations: device= " + device);
        }

        synchronized (mPendingGattOperations) {
@@ -558,7 +598,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

    private void ProcessPendingGattOperations(BluetoothDevice device) {
        if (VDBG) {
            Log.d(TAG, "ProcessPendingGattOperations device: " + device);
            Log.d(TAG, "ProcessPendingGattOperations: device= " + device);
        }

        synchronized (mPendingGattOperations) {
@@ -589,6 +629,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

            /* Restore CCCD values for device */
            for (ParcelUuid uuid : uuidList) {
                mEventLogger.logd(
                        DBG,
                        TAG,
                        "restoreCccValuesForStoredDevices: device= " + device + ", char= " + uuid);
                setCcc(device, uuid.getUuid(), 0,
                        BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE, false);
            }
@@ -797,6 +841,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    }

    private void setInitialCharacteristicValues(boolean notify) {
        mEventLogger.logd(DBG, TAG, "setInitialCharacteristicValues");
        updateMediaStateChar(mCurrentMediaState.getValue());
        updatePlayerNameChar("", notify);
        updatePlayerIconUrlChar("");
@@ -889,11 +934,13 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
                throw e.rethrowFromSystemServer();
            }
        }

        mEventLogger =
                new BluetoothEventLogger(
                        LOG_NB_EVENTS, TAG + " instance (CCID= " + ccid + ") event log");
    }

    protected boolean init(UUID scvUuid) {
        mCccDescriptorValues = new HashMap<>();

        mFeatures = mCallbacks.onGetFeatureFlags();

        // Verify the minimum required set of supported player features
@@ -903,20 +950,25 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
            return false;
        }

        mEventLogger.add("Initializing");

        // Init attribute database
        return initGattService(scvUuid);
    }

    private void handleObjectIdRequest(int objField, long objId) {
        mEventLogger.add("handleObjectIdRequest: obj= " + objField + ", objId= " + objId);
        mCallbacks.onSetObjectIdRequest(objField, objId);
    }

    private void handlePlayingOrderRequest(int order) {
        mEventLogger.add("handlePlayingOrderRequest: order= " + order);
        mCallbacks.onPlayingOrderSetRequest(order);
    }

    private void handlePlaybackSpeedRequest(int speed) {
        float floatingSpeed = (float) Math.pow(2, speed / 64);
        mEventLogger.add("handlePlaybackSpeedRequest: floatingSpeed= " + floatingSpeed);
        mCallbacks.onPlaybackSpeedSetRequest(floatingSpeed);
    }

@@ -924,7 +976,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        final long positionMs = (position != INTERVAL_UNAVAILABLE)
                ? mcsIntervalToMilliseconds(position)
                : TRACK_POSITION_UNAVAILABLE;

        mEventLogger.add("handleTrackPositionRequest: positionMs= " + positionMs);
        mCallbacks.onTrackPositionSetRequest(positionMs);
    }

@@ -979,11 +1031,12 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        }

        Request req = new Request(opcode, intVal);

        if (DBG) {
            Log.d(TAG, "handleMediaControlPointRequest: sending " + Request.Opcodes.toString(opcode)
        mEventLogger.logd(
                DBG,
                TAG,
                "handleMediaControlPointRequest: sending "
                        + Request.Opcodes.toString(opcode)
                        + " request up");
        }

        // TODO: Activate/deactivate devices with ActiveDeviceManager
        if (req.getOpcode() == Request.Opcodes.PLAY) {
@@ -1023,9 +1076,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    }

    private boolean initGattService(UUID serviceUuid) {
        if (DBG) {
            Log.d(TAG, "initGattService uuid: " + serviceUuid);
        }
        mEventLogger.logd(DBG, TAG, "initGattService: uuid= " + serviceUuid);

        if (mBluetoothGattServer == null) {
            BluetoothManager manager = mContext.getSystemService(BluetoothManager.class);
@@ -1099,6 +1150,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

        uuidList.remove(charUuid);

        mEventLogger.logd(
                DBG,
                TAG,
                "removeUuidFromMetadata: device= " + device + ", char= " + charUuid.toString());
        if (!device.setMetadata(METADATA_GMCS_CCCD,
                Utils.uuidsToByteArray(uuidList.toArray(new ParcelUuid[0])))) {
            Log.e(TAG, "Can't set CCCD for GMCS characteristic UUID: " + charUuid.toString()
@@ -1123,6 +1178,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

        uuidList.add(charUuid);

        mEventLogger.logd(
                DBG,
                TAG,
                "addUuidToMetadata: device= " + device + ", char= " + charUuid.toString());
        if (!device.setMetadata(METADATA_GMCS_CCCD,
                Utils.uuidsToByteArray(uuidList.toArray(new ParcelUuid[0])))) {
            Log.e(TAG, "Can't set CCCD for GMCS characteristic UUID: " + charUuid.toString()
@@ -1132,7 +1191,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

    @VisibleForTesting
    void setCcc(BluetoothDevice device, UUID charUuid, int offset, byte[] value, boolean store) {
        HashMap<UUID, Short> characteristicCcc = mCccDescriptorValues.get(device.getAddress());
        Map<UUID, Short> characteristicCcc = mCccDescriptorValues.get(device.getAddress());
        if (characteristicCcc == null) {
            characteristicCcc = new HashMap<>();
            mCccDescriptorValues.put(device.getAddress(), characteristicCcc);
@@ -1146,8 +1205,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        }

        if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
            mEventLogger.add("setCcc: device= " + device + ", notify= " + true);
            addUuidToMetadata(new ParcelUuid(charUuid), device);
        } else if (Arrays.equals(value, BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) {
            mEventLogger.add("setCcc: device= " + device + ", notify= " + false);
            removeUuidFromMetadata(new ParcelUuid(charUuid), device);
        } else {
            Log.e(TAG, "Not handled CCC value: " + Arrays.toString(value));
@@ -1196,14 +1257,12 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    @VisibleForTesting
    void updateMediaStateChar(int state) {
        if (DBG) {
            Log.d(TAG, "updateMediaStateChar");
            Log.d(TAG, "updateMediaStateChar: state= " + MediaState.toString(state));
        }

        if (!isFeatureSupported(ServiceFeature.MEDIA_STATE)) return;

        if (DBG) {
            Log.d(TAG, "updateMediaStateChar setting to state= " + state);
        }
        mEventLogger.logd(DBG, TAG, "updateMediaStateChar: state= " + MediaState.toString(state));

        BluetoothGattCharacteristic stateChar =
                mCharacteristics.get(CharId.MEDIA_STATE);
@@ -1219,6 +1278,13 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

        if (!isFeatureSupported(feature)) return;

        mEventLogger.logd(
                DBG,
                TAG,
                "updateObjectIdChar: charId= "
                        + CharId.FromFeature(feature)
                        + ", objId= "
                        + objectIdValue);
        updateObjectIdChar(mCharacteristics.get(CharId.FromFeature(feature)),
                objectIdValue, null, notify);
    }
@@ -1420,6 +1486,18 @@ public class MediaControlGattService implements MediaControlGattServiceInterface

    @Override
    public void onDeviceAuthorizationSet(BluetoothDevice device) {
        int auth = getDeviceAuthorization(device);
        mEventLogger.logd(
                DBG,
                TAG,
                "onDeviceAuthorizationSet: device= "
                        + device
                        + ", authorization= "
                        + (auth == BluetoothDevice.ACCESS_ALLOWED
                                ? "ALLOWED"
                                : (auth == BluetoothDevice.ACCESS_REJECTED
                                        ? "REJECTED"
                                        : "UNKNOWN")));
        ProcessPendingGattOperations(device);
    }

@@ -1445,7 +1523,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    @VisibleForTesting
    void updatePlayingOrderChar(PlayingOrder order, boolean notify) {
        if (VDBG) {
            Log.d(TAG, "updatePlayingOrderChar: " + order);
            Log.d(TAG, "updatePlayingOrderChar: order= " + order);
        }
        if (!isFeatureSupported(ServiceFeature.PLAYING_ORDER)) return;

@@ -1461,6 +1539,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
            if (notify && isFeatureSupported(ServiceFeature.PLAYING_ORDER_NOTIFY)) {
                notifyCharacteristic(orderChar, null);
            }
            mEventLogger.logd(DBG, TAG, "updatePlayingOrderChar: order= " + order);
        }
    }

@@ -1472,19 +1551,22 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
                continue;
            }

            HashMap<UUID, Short> charCccMap = mCccDescriptorValues.get(device.getAddress());
            Map<UUID, Short> charCccMap = mCccDescriptorValues.get(device.getAddress());
            if (charCccMap == null) continue;

            byte[] ccc = getCccBytes(device, characteristic.getUuid());
            if (VDBG) {
                Log.d(TAG, "notifyCharacteristic char= " + characteristic.getUuid().toString()
                Log.d(
                        TAG,
                        "notifyCharacteristic: char= "
                                + characteristic.getUuid().toString()
                                + " cccVal= "
                                + ByteBuffer.wrap(ccc).order(ByteOrder.LITTLE_ENDIAN).getShort());
            }

            if (!Arrays.equals(ccc, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) continue;

            if (VDBG) Log.d(TAG, "notifyCharacteristic sending notification");
            if (VDBG) Log.d(TAG, "notifyCharacteristic: sending notification");

            mBluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
        }
@@ -1529,7 +1611,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    @VisibleForTesting
    void updateSeekingSpeedChar(float speed, boolean notify) {
        if (VDBG) {
            Log.d(TAG, "updateSeekingSpeedChar: " + speed);
            Log.d(TAG, "updateSeekingSpeedChar: speed= " + speed);
        }
        if (isFeatureSupported(ServiceFeature.SEEKING_SPEED)) {
            if ((getSeekingSpeedChar() == null) || (getSeekingSpeedChar() != speed)) {
@@ -1540,6 +1622,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
                if (notify && isFeatureSupported(ServiceFeature.SEEKING_SPEED_NOTIFY)) {
                    notifyCharacteristic(characteristic, null);
                }
                mEventLogger.logd(
                        DBG,
                        TAG,
                        "updateSeekingSpeedChar: intSpeed=" + intSpeed + ", speed= " + speed);
            }
        }
    }
@@ -1577,6 +1663,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
            if (notify && isFeatureSupported(ServiceFeature.PLAYBACK_SPEED_NOTIFY)) {
                notifyCharacteristic(characteristic, null);
            }
            mEventLogger.logd(
                    DBG,
                    TAG,
                    "updatePlaybackSpeedChar: intSpeed=" + intSpeed + ", speed= " + speed);
        }
    }

@@ -1604,6 +1694,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
                notifyCharacteristic(characteristic, null);
            }
        }
        mEventLogger.logd(
                DBG,
                TAG,
                "updateTrackPositionChar: positionMs= " + positionMs + ", position= " + position);
    }

    private long getTrackDurationChar() {
@@ -1635,6 +1729,13 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
            if (notify && isFeatureSupported(ServiceFeature.TRACK_DURATION_NOTIFY)) {
                notifyCharacteristic(characteristic, null);
            }
            mEventLogger.logd(
                    DBG,
                    TAG,
                    "updateTrackDurationChar: durationMs= "
                            + durationMs
                            + ", duration= "
                            + duration);
        }
    }

@@ -1662,15 +1763,18 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
            if (notify && isFeatureSupported(ServiceFeature.TRACK_TITLE_NOTIFY)) {
                notifyCharacteristic(characteristic, null);
            }
            mEventLogger.logd(DBG, TAG, "updateTrackTitleChar: title= '" + title + "'");
        }
    }

    @VisibleForTesting
    void updateSupportedOpcodesChar(int opcodes, boolean notify) {
        if (VDBG) {
            Log.d(TAG, "updateSupportedOpcodesChar: " + opcodes);
            Log.d(
                    TAG,
                    "updateSupportedOpcodesChar: opcodes= "
                            + Request.SupportedOpcodes.toString(opcodes));
        }

        if (!isFeatureSupported(ServiceFeature.MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)) return;

        BluetoothGattCharacteristic characteristic = mCharacteristics.get(
@@ -1681,17 +1785,17 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
            return;
        }

        if (VDBG) {
            Log.d(TAG, "updateSupportedOpcodesChar setting char");
        }

        characteristic.setValue(opcodes, BluetoothGattCharacteristic.FORMAT_UINT32, 0);
        if (notify
                && isFeatureSupported(
                ServiceFeature.MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY)) {
            notifyCharacteristic(characteristic, null);
        }

        mEventLogger.logd(
                DBG,
                TAG,
                "updateSupportedOpcodesChar: opcodes= "
                        + Request.SupportedOpcodes.toString(opcodes));
    }

    @VisibleForTesting
@@ -1702,11 +1806,20 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        if (isFeatureSupported(ServiceFeature.PLAYING_ORDER_SUPPORTED)) {
            mCharacteristics.get(CharId.PLAYING_ORDER_SUPPORTED)
                    .setValue(supportedOrder, BluetoothGattCharacteristic.FORMAT_UINT16, 0);
            mEventLogger.logd(
                    DBG, TAG, "updatePlayingOrderSupportedChar: order= " + supportedOrder);
        }
    }

    private void updateIconObjIdChar(Long objId) {
        if (isFeatureSupported(ServiceFeature.PLAYER_ICON_OBJ_ID)) {
            mEventLogger.logd(
                    DBG,
                    TAG,
                    "updateObjectIdChar charId= "
                            + CharId.PLAYER_ICON_OBJ_ID
                            + ", objId= "
                            + objId);
            updateObjectIdChar(mCharacteristics.get(CharId.PLAYER_ICON_OBJ_ID), objId,
                    null, true);
        }
@@ -1751,6 +1864,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        }
        if (isFeatureSupported(ServiceFeature.PLAYER_ICON_URL)) {
            mCharacteristics.get(CharId.PLAYER_ICON_URL).setValue(url);
            mEventLogger.logd(DBG, TAG, "updatePlayerIconUrlChar: " + url);
        }
    }

@@ -1775,6 +1889,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        BluetoothGattCharacteristic characteristic =
                mCharacteristics.get(CharId.PLAYER_NAME);
        characteristic.setValue(name);
        mEventLogger.logd(DBG, TAG, "updatePlayerNameChar: name= '" + name + "'");
        if (notify && isFeatureSupported(ServiceFeature.PLAYER_NAME_NOTIFY)) {
            notifyCharacteristic(characteristic, null);
        }
@@ -2000,7 +2115,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
    }

    public void dump(StringBuilder sb) {
        sb.append("\tMediaControlService instance:");
        sb.append("\tMediaControlService instance current state:");
        sb.append("\n\t\tCcid = " + mCcid);
        sb.append("\n\t\tFeatures:" + ServiceFeature.featuresToString(mFeatures, "\n\t\t\t"));

@@ -2013,8 +2128,7 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
        }

        sb.append("\n\t\tCurrentPlaybackState = " + mCurrentMediaState);
        for (Map.Entry<String, HashMap<UUID, Short>> deviceEntry
                : mCccDescriptorValues.entrySet()) {
        for (Map.Entry<String, Map<UUID, Short>> deviceEntry : mCccDescriptorValues.entrySet()) {
            sb.append("\n\t\tCCC states for device: " + "xx:xx:xx:xx:"
                    + deviceEntry.getKey().substring(12));
            for (Map.Entry<UUID, Short> entry : deviceEntry.getValue().entrySet()) {
@@ -2022,5 +2136,8 @@ public class MediaControlGattService implements MediaControlGattServiceInterface
                        + Utils.cccIntToStr(entry.getValue()));
            }
        }

        sb.append("\n\n");
        mEventLogger.dump(sb);
    }
}
+84 −33

File changed.

Preview size limit exceeded, changes collapsed.

+16 −0
Original line number Diff line number Diff line
@@ -37,4 +37,20 @@ public enum MediaState {
    public int getValue() {
        return mValue;
    }

    /** Converts the state to string. */
    public static String toString(int value) {
        switch (value) {
            case 0x00:
                return "INACTIVE(0x00)";
            case 0x01:
                return "PLAYING(0x01)";
            case 0x02:
                return "PAUSED(0x02)";
            case 0x03:
                return "SEEKING(0x03)";
            default:
                return "UNKNOWN(0x" + Integer.toHexString(value) + ")";
        }
    }
}
+69 −0
Original line number Diff line number Diff line
@@ -103,6 +103,75 @@ public final class Request {
        public static final int FIRST_GROUP = 0x040000;
        public static final int LAST_GROUP = 0x080000;
        public static final int GOTO_GROUP = 0x100000;

        static String toString(int opcodes) {
            StringBuilder sb = new StringBuilder();
            boolean is_complex = false;

            sb.append("0x" + Integer.toHexString(opcodes) + " (");
            for (int i = 1; i <= opcodes; i <<= 1) {
                int opcode = opcodes & i;
                if (opcode != 0) {
                    if (is_complex) {
                        sb.append(" | ");
                    } else {
                        is_complex = true;
                    }
                    sb.append(singleOpcodeToString(opcode));
                }
            }
            sb.append(")");
            return sb.toString();
        }

        private static String singleOpcodeToString(int opcode) {
            switch (opcode) {
                case 0x01:
                    return "PLAY";
                case 0x02:
                    return "PAUSE";
                case 0x04:
                    return "FAST_REWIND";
                case 0x08:
                    return "FAST_FORWARD";
                case 0x10:
                    return "STOP";
                case 0x20:
                    return "MOVE_RELATIVE";
                case 0x40:
                    return "PREVIOUS_SEGMENT";
                case 0x80:
                    return "NEXT_SEGMENT";
                case 0x0100:
                    return "FIRST_SEGMENT";
                case 0x0200:
                    return "LAST_SEGMENT";
                case 0x0400:
                    return "GOTO_SEGMENT";
                case 0x0800:
                    return "PREVIOUS_TRACK";
                case 0x1000:
                    return "NEXT_TRACK";
                case 0x2000:
                    return "FIRST_TRACK";
                case 0x4000:
                    return "LAST_TRACK";
                case 0x8000:
                    return "GOTO_TRACK";
                case 0x010000:
                    return "PREVIOUS_GROUP";
                case 0x020000:
                    return "NEXT_GROUP";
                case 0x040000:
                    return "FIRST_GROUP";
                case 0x080000:
                    return "LAST_GROUP";
                case 0x100000:
                    return "GOTO_GROUP";
                default:
                    return "0x" + Integer.toHexString(opcode);
            }
        }
    }

    /**
+7 −1
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.le_audio.LeAudioService;
@@ -1187,4 +1186,11 @@ public class MediaControlGattServiceTest {
        state_map.put(PlayerStateField.PLAYBACK_STATE, playback_state);
        mMcpService.updatePlayerState(state_map);
    }

    @Test
    public void testDumpDoesNotCrash() {
        mMcpService.dump(new StringBuilder());
        BluetoothGattService service = initAllFeaturesGattService();
        mMcpService.dump(new StringBuilder());
    }
}