Loading android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java +9 −8 Original line number Diff line number Diff line Loading @@ -846,16 +846,13 @@ public class MediaControlGattService implements MediaControlGattServiceInterface @VisibleForTesting int handleMediaControlPointRequest(BluetoothDevice device, byte[] value) { if (DBG) { Log.d(TAG, "handleMediaControlPointRequest"); } final int payloadOffset = 1; final int opcode = value[0]; // Test for RFU bits and currently supported opcodes if (!isOpcodeSupported(opcode)) { Log.e(TAG, "handleMediaControlPointRequest: opcode or feature not supported"); Log.i(TAG, "handleMediaControlPointRequest: " + Request.Opcodes.toString(opcode) + " not supported"); mHandler.post(() -> { setMediaControlRequestResult(new Request(opcode, 0), Request.Results.OPCODE_NOT_SUPPORTED); Loading @@ -864,6 +861,8 @@ public class MediaControlGattService implements MediaControlGattServiceInterface } if (getMediaControlPointRequestPayloadLength(opcode) != (value.length - payloadOffset)) { Log.w(TAG, "handleMediaControlPointRequest: " + Request.Opcodes.toString(opcode) + " bad payload length"); return BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH; } Loading @@ -885,8 +884,9 @@ public class MediaControlGattService implements MediaControlGattServiceInterface Request req = new Request(opcode, intVal); if (VDBG) { Log.d(TAG, "handleMediaControlPointRequest: sending request up"); if (DBG) { Log.d(TAG, "handleMediaControlPointRequest: sending " + Request.Opcodes.toString(opcode) + " request up"); } if (req.getOpcode() == Request.Opcodes.PLAY) { Loading Loading @@ -1626,7 +1626,8 @@ public class MediaControlGattService implements MediaControlGattServiceInterface private boolean isFeatureSupported(long featureBit) { if (DBG) { Log.w(TAG, "Feature " + featureBit + " support: " + ((mFeatures & featureBit) != 0)); Log.w(TAG, "Feature " + ServiceFeature.toString(featureBit) + " support: " + ((mFeatures & featureBit) != 0)); } return (mFeatures & featureBit) != 0; } Loading android/app/src/com/android/bluetooth/mcp/Request.java +49 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,55 @@ public final class Request { public static final int FIRST_GROUP = 0x42; public static final int LAST_GROUP = 0x43; public static final int GOTO_GROUP = 0x44; static String toString(int opcode) { switch(opcode) { case 0x01: return "PLAY(0x01)"; case 0x02: return "PAUSE(0x02)"; case 0x03: return "FAST_REWIND(0x03)"; case 0x04: return "FAST_FORWARD(0x04)"; case 0x05: return "STOP(0x05)"; case 0x10: return "MOVE_RELATIVE(0x10)"; case 0x20: return "PREVIOUS_SEGMENT(0x20)"; case 0x21: return "NEXT_SEGMENT(0x21)"; case 0x22: return "FIRST_SEGMENT(0x22)"; case 0x23: return "LAST_SEGMENT(0x23)"; case 0x24: return "GOTO_SEGMENT(0x24)"; case 0x30: return "PREVIOUS_TRACK(0x30)"; case 0x31: return "NEXT_TRACK(0x31)"; case 0x32: return "FIRST_TRACK(0x32)"; case 0x33: return "LAST_TRACK(0x33)"; case 0x34: return "GOTO_TRACK(0x34)"; case 0x40: return "PREVIOUS_GROUP(0x40)"; case 0x41: return "NEXT_GROUP(0x41)"; case 0x42: return "FIRST_GROUP(0x42)"; case 0x43: return "LAST_GROUP(0x43)"; case 0x44: return "GOTO_GROUP(0x44)"; default: return "UNKNOWN(0x" + Integer.toHexString(opcode) + ")"; } } } /* Map opcodes which are written to 'Media Control Point' characteristics to their corresponding Loading android/app/src/com/android/bluetooth/mcp/ServiceFeature.java +39 −0 Original line number Diff line number Diff line Loading @@ -64,4 +64,43 @@ public final class ServiceFeature { // Table 3.1. public static final long ALL_MANDATORY_SERVICE_FEATURES = PLAYER_NAME | TRACK_CHANGED | TRACK_TITLE | TRACK_DURATION | TRACK_POSITION | MEDIA_STATE | CONTENT_CONTROL_ID; static String toString(long serviceFeature) { if (serviceFeature == PLAYER_NAME) return "PLAYER_NAME(BIT 1)"; if (serviceFeature == PLAYER_ICON_OBJ_ID) return "PLAYER_ICON_OBJ_ID(BIT 2)"; if (serviceFeature == PLAYER_ICON_URL) return "PLAYER_ICON_URL(BIT 3)"; if (serviceFeature == TRACK_CHANGED) return "TRACK_CHANGED(BIT 4)"; if (serviceFeature == TRACK_TITLE) return "TRACK_TITLE(BIT 5)"; if (serviceFeature == TRACK_DURATION) return "TRACK_DURATION(BIT 6)"; if (serviceFeature == TRACK_POSITION) return "TRACK_POSITION(BIT 7)"; if (serviceFeature == PLAYBACK_SPEED) return "PLAYBACK_SPEED(BIT 8)"; if (serviceFeature == SEEKING_SPEED) return "SEEKING_SPEED(BIT 9)"; if (serviceFeature == CURRENT_TRACK_SEGMENT_OBJ_ID) return "CURRENT_TRACK_SEGMENT_OBJ_ID(BIT 10)"; if (serviceFeature == CURRENT_TRACK_OBJ_ID) return "CURRENT_TRACK_OBJ_ID(BIT 11)"; if (serviceFeature == NEXT_TRACK_OBJ_ID) return "NEXT_TRACK_OBJ_ID(BIT 12)"; if (serviceFeature == CURRENT_GROUP_OBJ_ID) return "CURRENT_GROUP_OBJ_ID(BIT 13)"; if (serviceFeature == PARENT_GROUP_OBJ_ID) return "PARENT_GROUP_OBJ_ID(BIT 14)"; if (serviceFeature == PLAYING_ORDER) return "PLAYING_ORDER(BIT 15)"; if (serviceFeature == PLAYING_ORDER_SUPPORTED) return "PLAYING_ORDER_SUPPORTED(BIT 16)"; if (serviceFeature == MEDIA_STATE) return "MEDIA_STATE(BIT 17)"; if (serviceFeature == MEDIA_CONTROL_POINT) return "MEDIA_CONTROL_POINT(BIT 18)"; if (serviceFeature == MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) return "MEDIA_CONTROL_POINT_OPCODES_SUPPORTED(BIT 19)"; if (serviceFeature == SEARCH_RESULT_OBJ_ID) return "SEARCH_RESULT_OBJ_ID(BIT 20)"; if (serviceFeature == SEARCH_CONTROL_POINT) return "SEARCH_CONTROL_POINT(BIT 21)"; if (serviceFeature == CONTENT_CONTROL_ID) return "CONTENT_CONTROL_ID(BIT 22)"; if (serviceFeature == PLAYER_NAME_NOTIFY) return "PLAYER_NAME_NOTIFY"; if (serviceFeature == TRACK_TITLE_NOTIFY) return "TRACK_TITLE_NOTIFY"; if (serviceFeature == TRACK_DURATION_NOTIFY) return "TRACK_DURATION_NOTIFY"; if (serviceFeature == TRACK_POSITION_NOTIFY) return "TRACK_POSITION_NOTIFY"; if (serviceFeature == PLAYBACK_SPEED_NOTIFY) return "PLAYBACK_SPEED_NOTIFY"; if (serviceFeature == SEEKING_SPEED_NOTIFY) return "SEEKING_SPEED_NOTIFY"; if (serviceFeature == CURRENT_TRACK_OBJ_ID_NOTIFY) return "CURRENT_TRACK_OBJ_ID_NOTIFY"; if (serviceFeature == NEXT_TRACK_OBJ_ID_NOTIFY) return "NEXT_TRACK_OBJ_ID_NOTIFY"; if (serviceFeature == CURRENT_GROUP_OBJ_ID_NOTIFY) return "CURRENT_GROUP_OBJ_ID_NOTIFY"; if (serviceFeature == PARENT_GROUP_OBJ_ID_NOTIFY) return "PARENT_GROUP_OBJ_ID_NOTIFY"; if (serviceFeature == PLAYING_ORDER_NOTIFY) return "PLAYING_ORDER_NOTIFY"; if (serviceFeature == MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY) return "MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY"; return "UNKNOWN(0x" + Long.toHexString(serviceFeature) + ")"; } } Loading
android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java +9 −8 Original line number Diff line number Diff line Loading @@ -846,16 +846,13 @@ public class MediaControlGattService implements MediaControlGattServiceInterface @VisibleForTesting int handleMediaControlPointRequest(BluetoothDevice device, byte[] value) { if (DBG) { Log.d(TAG, "handleMediaControlPointRequest"); } final int payloadOffset = 1; final int opcode = value[0]; // Test for RFU bits and currently supported opcodes if (!isOpcodeSupported(opcode)) { Log.e(TAG, "handleMediaControlPointRequest: opcode or feature not supported"); Log.i(TAG, "handleMediaControlPointRequest: " + Request.Opcodes.toString(opcode) + " not supported"); mHandler.post(() -> { setMediaControlRequestResult(new Request(opcode, 0), Request.Results.OPCODE_NOT_SUPPORTED); Loading @@ -864,6 +861,8 @@ public class MediaControlGattService implements MediaControlGattServiceInterface } if (getMediaControlPointRequestPayloadLength(opcode) != (value.length - payloadOffset)) { Log.w(TAG, "handleMediaControlPointRequest: " + Request.Opcodes.toString(opcode) + " bad payload length"); return BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH; } Loading @@ -885,8 +884,9 @@ public class MediaControlGattService implements MediaControlGattServiceInterface Request req = new Request(opcode, intVal); if (VDBG) { Log.d(TAG, "handleMediaControlPointRequest: sending request up"); if (DBG) { Log.d(TAG, "handleMediaControlPointRequest: sending " + Request.Opcodes.toString(opcode) + " request up"); } if (req.getOpcode() == Request.Opcodes.PLAY) { Loading Loading @@ -1626,7 +1626,8 @@ public class MediaControlGattService implements MediaControlGattServiceInterface private boolean isFeatureSupported(long featureBit) { if (DBG) { Log.w(TAG, "Feature " + featureBit + " support: " + ((mFeatures & featureBit) != 0)); Log.w(TAG, "Feature " + ServiceFeature.toString(featureBit) + " support: " + ((mFeatures & featureBit) != 0)); } return (mFeatures & featureBit) != 0; } Loading
android/app/src/com/android/bluetooth/mcp/Request.java +49 −0 Original line number Diff line number Diff line Loading @@ -130,6 +130,55 @@ public final class Request { public static final int FIRST_GROUP = 0x42; public static final int LAST_GROUP = 0x43; public static final int GOTO_GROUP = 0x44; static String toString(int opcode) { switch(opcode) { case 0x01: return "PLAY(0x01)"; case 0x02: return "PAUSE(0x02)"; case 0x03: return "FAST_REWIND(0x03)"; case 0x04: return "FAST_FORWARD(0x04)"; case 0x05: return "STOP(0x05)"; case 0x10: return "MOVE_RELATIVE(0x10)"; case 0x20: return "PREVIOUS_SEGMENT(0x20)"; case 0x21: return "NEXT_SEGMENT(0x21)"; case 0x22: return "FIRST_SEGMENT(0x22)"; case 0x23: return "LAST_SEGMENT(0x23)"; case 0x24: return "GOTO_SEGMENT(0x24)"; case 0x30: return "PREVIOUS_TRACK(0x30)"; case 0x31: return "NEXT_TRACK(0x31)"; case 0x32: return "FIRST_TRACK(0x32)"; case 0x33: return "LAST_TRACK(0x33)"; case 0x34: return "GOTO_TRACK(0x34)"; case 0x40: return "PREVIOUS_GROUP(0x40)"; case 0x41: return "NEXT_GROUP(0x41)"; case 0x42: return "FIRST_GROUP(0x42)"; case 0x43: return "LAST_GROUP(0x43)"; case 0x44: return "GOTO_GROUP(0x44)"; default: return "UNKNOWN(0x" + Integer.toHexString(opcode) + ")"; } } } /* Map opcodes which are written to 'Media Control Point' characteristics to their corresponding Loading
android/app/src/com/android/bluetooth/mcp/ServiceFeature.java +39 −0 Original line number Diff line number Diff line Loading @@ -64,4 +64,43 @@ public final class ServiceFeature { // Table 3.1. public static final long ALL_MANDATORY_SERVICE_FEATURES = PLAYER_NAME | TRACK_CHANGED | TRACK_TITLE | TRACK_DURATION | TRACK_POSITION | MEDIA_STATE | CONTENT_CONTROL_ID; static String toString(long serviceFeature) { if (serviceFeature == PLAYER_NAME) return "PLAYER_NAME(BIT 1)"; if (serviceFeature == PLAYER_ICON_OBJ_ID) return "PLAYER_ICON_OBJ_ID(BIT 2)"; if (serviceFeature == PLAYER_ICON_URL) return "PLAYER_ICON_URL(BIT 3)"; if (serviceFeature == TRACK_CHANGED) return "TRACK_CHANGED(BIT 4)"; if (serviceFeature == TRACK_TITLE) return "TRACK_TITLE(BIT 5)"; if (serviceFeature == TRACK_DURATION) return "TRACK_DURATION(BIT 6)"; if (serviceFeature == TRACK_POSITION) return "TRACK_POSITION(BIT 7)"; if (serviceFeature == PLAYBACK_SPEED) return "PLAYBACK_SPEED(BIT 8)"; if (serviceFeature == SEEKING_SPEED) return "SEEKING_SPEED(BIT 9)"; if (serviceFeature == CURRENT_TRACK_SEGMENT_OBJ_ID) return "CURRENT_TRACK_SEGMENT_OBJ_ID(BIT 10)"; if (serviceFeature == CURRENT_TRACK_OBJ_ID) return "CURRENT_TRACK_OBJ_ID(BIT 11)"; if (serviceFeature == NEXT_TRACK_OBJ_ID) return "NEXT_TRACK_OBJ_ID(BIT 12)"; if (serviceFeature == CURRENT_GROUP_OBJ_ID) return "CURRENT_GROUP_OBJ_ID(BIT 13)"; if (serviceFeature == PARENT_GROUP_OBJ_ID) return "PARENT_GROUP_OBJ_ID(BIT 14)"; if (serviceFeature == PLAYING_ORDER) return "PLAYING_ORDER(BIT 15)"; if (serviceFeature == PLAYING_ORDER_SUPPORTED) return "PLAYING_ORDER_SUPPORTED(BIT 16)"; if (serviceFeature == MEDIA_STATE) return "MEDIA_STATE(BIT 17)"; if (serviceFeature == MEDIA_CONTROL_POINT) return "MEDIA_CONTROL_POINT(BIT 18)"; if (serviceFeature == MEDIA_CONTROL_POINT_OPCODES_SUPPORTED) return "MEDIA_CONTROL_POINT_OPCODES_SUPPORTED(BIT 19)"; if (serviceFeature == SEARCH_RESULT_OBJ_ID) return "SEARCH_RESULT_OBJ_ID(BIT 20)"; if (serviceFeature == SEARCH_CONTROL_POINT) return "SEARCH_CONTROL_POINT(BIT 21)"; if (serviceFeature == CONTENT_CONTROL_ID) return "CONTENT_CONTROL_ID(BIT 22)"; if (serviceFeature == PLAYER_NAME_NOTIFY) return "PLAYER_NAME_NOTIFY"; if (serviceFeature == TRACK_TITLE_NOTIFY) return "TRACK_TITLE_NOTIFY"; if (serviceFeature == TRACK_DURATION_NOTIFY) return "TRACK_DURATION_NOTIFY"; if (serviceFeature == TRACK_POSITION_NOTIFY) return "TRACK_POSITION_NOTIFY"; if (serviceFeature == PLAYBACK_SPEED_NOTIFY) return "PLAYBACK_SPEED_NOTIFY"; if (serviceFeature == SEEKING_SPEED_NOTIFY) return "SEEKING_SPEED_NOTIFY"; if (serviceFeature == CURRENT_TRACK_OBJ_ID_NOTIFY) return "CURRENT_TRACK_OBJ_ID_NOTIFY"; if (serviceFeature == NEXT_TRACK_OBJ_ID_NOTIFY) return "NEXT_TRACK_OBJ_ID_NOTIFY"; if (serviceFeature == CURRENT_GROUP_OBJ_ID_NOTIFY) return "CURRENT_GROUP_OBJ_ID_NOTIFY"; if (serviceFeature == PARENT_GROUP_OBJ_ID_NOTIFY) return "PARENT_GROUP_OBJ_ID_NOTIFY"; if (serviceFeature == PLAYING_ORDER_NOTIFY) return "PLAYING_ORDER_NOTIFY"; if (serviceFeature == MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY) return "MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY"; return "UNKNOWN(0x" + Long.toHexString(serviceFeature) + ")"; } }