1 /*
2  * Copyright 2021 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.bluetooth.mcp;
19 
20 import java.util.BitSet;
21 
22 /** Service features definition */
23 public final class ServiceFeature {
24     // LS word is used for the characteristic support bits
25     public static final long PLAYER_NAME = 0x00000001;
26     public static final long PLAYER_ICON_OBJ_ID = 0x00000002;
27     public static final long PLAYER_ICON_URL = 0x00000004;
28     public static final long TRACK_CHANGED = 0x00000008;
29     public static final long TRACK_TITLE = 0x00000010;
30     public static final long TRACK_DURATION = 0x00000020;
31     public static final long TRACK_POSITION = 0x00000040;
32     public static final long PLAYBACK_SPEED = 0x00000080;
33     public static final long SEEKING_SPEED = 0x00000100;
34     public static final long CURRENT_TRACK_SEGMENT_OBJ_ID = 0x00000200;
35     public static final long CURRENT_TRACK_OBJ_ID = 0x00000400;
36     public static final long NEXT_TRACK_OBJ_ID = 0x00000800;
37     public static final long CURRENT_GROUP_OBJ_ID = 0x00001000;
38     public static final long PARENT_GROUP_OBJ_ID = 0x00002000;
39     public static final long PLAYING_ORDER = 0x00004000;
40     public static final long PLAYING_ORDER_SUPPORTED = 0x00008000;
41     public static final long MEDIA_STATE = 0x00010000;
42     public static final long MEDIA_CONTROL_POINT = 0x00020000;
43     public static final long MEDIA_CONTROL_POINT_OPCODES_SUPPORTED = 0x00040000;
44     public static final long SEARCH_RESULT_OBJ_ID = 0x00080000;
45     public static final long SEARCH_CONTROL_POINT = 0x00100000;
46     public static final long CONTENT_CONTROL_ID = 0x00200000;
47 
48     // MS word is used for the optional notification support bits
49     public static final long PLAYER_NAME_NOTIFY = PLAYER_NAME << 32;
50     public static final long TRACK_TITLE_NOTIFY = TRACK_TITLE << 32;
51     public static final long TRACK_DURATION_NOTIFY = TRACK_DURATION << 32;
52     public static final long TRACK_POSITION_NOTIFY = TRACK_POSITION << 32;
53     public static final long PLAYBACK_SPEED_NOTIFY = PLAYBACK_SPEED << 32;
54     public static final long SEEKING_SPEED_NOTIFY = SEEKING_SPEED << 32;
55     public static final long CURRENT_TRACK_OBJ_ID_NOTIFY = CURRENT_TRACK_OBJ_ID << 32;
56     public static final long NEXT_TRACK_OBJ_ID_NOTIFY = NEXT_TRACK_OBJ_ID << 32;
57     public static final long CURRENT_GROUP_OBJ_ID_NOTIFY = CURRENT_GROUP_OBJ_ID << 32;
58     public static final long PARENT_GROUP_OBJ_ID_NOTIFY = PARENT_GROUP_OBJ_ID << 32;
59     public static final long PLAYING_ORDER_NOTIFY = PLAYING_ORDER << 32;
60     public static final long MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY =
61             MEDIA_CONTROL_POINT_OPCODES_SUPPORTED << 32;
62 
63     // This is set according to the Media Control Service Specification, v1.0, Section 3,
64     // Table 3.1.
65     public static final long ALL_MANDATORY_SERVICE_FEATURES =
66             PLAYER_NAME
67                     | TRACK_CHANGED
68                     | TRACK_TITLE
69                     | TRACK_DURATION
70                     | TRACK_POSITION
71                     | MEDIA_STATE
72                     | CONTENT_CONTROL_ID;
73 
toString(long serviceFeature)74     static String toString(long serviceFeature) {
75         if (serviceFeature == PLAYER_NAME) return "PLAYER_NAME(BIT 1)";
76         if (serviceFeature == PLAYER_ICON_OBJ_ID) return "PLAYER_ICON_OBJ_ID(BIT 2)";
77         if (serviceFeature == PLAYER_ICON_URL) return "PLAYER_ICON_URL(BIT 3)";
78         if (serviceFeature == TRACK_CHANGED) return "TRACK_CHANGED(BIT 4)";
79         if (serviceFeature == TRACK_TITLE) return "TRACK_TITLE(BIT 5)";
80         if (serviceFeature == TRACK_DURATION) return "TRACK_DURATION(BIT 6)";
81         if (serviceFeature == TRACK_POSITION) return "TRACK_POSITION(BIT 7)";
82         if (serviceFeature == PLAYBACK_SPEED) return "PLAYBACK_SPEED(BIT 8)";
83         if (serviceFeature == SEEKING_SPEED) return "SEEKING_SPEED(BIT 9)";
84         if (serviceFeature == CURRENT_TRACK_SEGMENT_OBJ_ID)
85             return "CURRENT_TRACK_SEGMENT_OBJ_ID(BIT 10)";
86         if (serviceFeature == CURRENT_TRACK_OBJ_ID) return "CURRENT_TRACK_OBJ_ID(BIT 11)";
87         if (serviceFeature == NEXT_TRACK_OBJ_ID) return "NEXT_TRACK_OBJ_ID(BIT 12)";
88         if (serviceFeature == CURRENT_GROUP_OBJ_ID) return "CURRENT_GROUP_OBJ_ID(BIT 13)";
89         if (serviceFeature == PARENT_GROUP_OBJ_ID) return "PARENT_GROUP_OBJ_ID(BIT 14)";
90         if (serviceFeature == PLAYING_ORDER) return "PLAYING_ORDER(BIT 15)";
91         if (serviceFeature == PLAYING_ORDER_SUPPORTED) return "PLAYING_ORDER_SUPPORTED(BIT 16)";
92         if (serviceFeature == MEDIA_STATE) return "MEDIA_STATE(BIT 17)";
93         if (serviceFeature == MEDIA_CONTROL_POINT) return "MEDIA_CONTROL_POINT(BIT 18)";
94         if (serviceFeature == MEDIA_CONTROL_POINT_OPCODES_SUPPORTED)
95             return "MEDIA_CONTROL_POINT_OPCODES_SUPPORTED(BIT 19)";
96         if (serviceFeature == SEARCH_RESULT_OBJ_ID) return "SEARCH_RESULT_OBJ_ID(BIT 20)";
97         if (serviceFeature == SEARCH_CONTROL_POINT) return "SEARCH_CONTROL_POINT(BIT 21)";
98         if (serviceFeature == CONTENT_CONTROL_ID) return "CONTENT_CONTROL_ID(BIT 22)";
99         if (serviceFeature == PLAYER_NAME_NOTIFY) return "PLAYER_NAME_NOTIFY";
100         if (serviceFeature == TRACK_TITLE_NOTIFY) return "TRACK_TITLE_NOTIFY";
101         if (serviceFeature == TRACK_DURATION_NOTIFY) return "TRACK_DURATION_NOTIFY";
102         if (serviceFeature == TRACK_POSITION_NOTIFY) return "TRACK_POSITION_NOTIFY";
103         if (serviceFeature == PLAYBACK_SPEED_NOTIFY) return "PLAYBACK_SPEED_NOTIFY";
104         if (serviceFeature == SEEKING_SPEED_NOTIFY) return "SEEKING_SPEED_NOTIFY";
105         if (serviceFeature == CURRENT_TRACK_OBJ_ID_NOTIFY) return "CURRENT_TRACK_OBJ_ID_NOTIFY";
106         if (serviceFeature == NEXT_TRACK_OBJ_ID_NOTIFY) return "NEXT_TRACK_OBJ_ID_NOTIFY";
107         if (serviceFeature == CURRENT_GROUP_OBJ_ID_NOTIFY) return "CURRENT_GROUP_OBJ_ID_NOTIFY";
108         if (serviceFeature == PARENT_GROUP_OBJ_ID_NOTIFY) return "PARENT_GROUP_OBJ_ID_NOTIFY";
109         if (serviceFeature == PLAYING_ORDER_NOTIFY) return "PLAYING_ORDER_NOTIFY";
110         if (serviceFeature == MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY)
111             return "MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_NOTIFY";
112 
113         return "UNKNOWN(0x" + Long.toHexString(serviceFeature) + ")";
114     }
115 
featuresToString(long serviceFeatures, String indent)116     static String featuresToString(long serviceFeatures, String indent) {
117         BitSet bs = BitSet.valueOf(new long[] {serviceFeatures});
118         String string = "";
119 
120         for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
121             if (i == Integer.MAX_VALUE) {
122                 break;
123             } else {
124                 string += indent + toString(1 << i);
125             }
126         }
127 
128         return string;
129     }
130 }
131