• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.btservice;
18 
19 import android.bluetooth.BluetoothProfile;
20 import android.content.Context;
21 import android.os.SystemProperties;
22 import android.sysprop.BluetoothProperties;
23 import android.util.Log;
24 
25 import com.android.bluetooth.Utils;
26 import com.android.bluetooth.a2dp.A2dpService;
27 import com.android.bluetooth.a2dpsink.A2dpSinkService;
28 import com.android.bluetooth.avrcp.AvrcpTargetService;
29 import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
30 import com.android.bluetooth.bas.BatteryService;
31 import com.android.bluetooth.bass_client.BassClientService;
32 import com.android.bluetooth.csip.CsipSetCoordinatorService;
33 import com.android.bluetooth.flags.Flags;
34 import com.android.bluetooth.gatt.GattService;
35 import com.android.bluetooth.hap.HapClientService;
36 import com.android.bluetooth.hearingaid.HearingAidService;
37 import com.android.bluetooth.hfp.HeadsetService;
38 import com.android.bluetooth.hfpclient.HeadsetClientService;
39 import com.android.bluetooth.hid.HidDeviceService;
40 import com.android.bluetooth.hid.HidHostService;
41 import com.android.bluetooth.le_audio.LeAudioService;
42 import com.android.bluetooth.map.BluetoothMapService;
43 import com.android.bluetooth.mapclient.MapClientService;
44 import com.android.bluetooth.mcp.McpService;
45 import com.android.bluetooth.opp.BluetoothOppService;
46 import com.android.bluetooth.pan.PanService;
47 import com.android.bluetooth.pbap.BluetoothPbapService;
48 import com.android.bluetooth.pbapclient.PbapClientService;
49 import com.android.bluetooth.sap.SapService;
50 import com.android.bluetooth.tbs.TbsService;
51 import com.android.bluetooth.vc.VolumeControlService;
52 import com.android.internal.annotations.VisibleForTesting;
53 
54 import java.util.Arrays;
55 
56 public class Config {
57     private static final String TAG = "AdapterServiceConfig";
58 
59     private static final String LE_AUDIO_DYNAMIC_SWITCH_PROPERTY =
60             "ro.bluetooth.leaudio_switcher.supported";
61     private static final String LE_AUDIO_SWITCHER_DISABLED_PROPERTY =
62             "persist.bluetooth.leaudio_switcher.disabled";
63 
64     // Three modes, 1. "disabled" - all LE audio feature off. 2. "unicast" - Unicast enabled only.
65     // 3. "broadcast" - Unicast + broadcast enabled
66     private static final String LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY =
67             "persist.bluetooth.leaudio_dynamic_switcher.mode";
68 
69     private static class ProfileConfig {
70         boolean mSupported;
71         int mProfileId;
72 
ProfileConfig(boolean supported, int profileId)73         ProfileConfig(boolean supported, int profileId) {
74             mSupported = supported;
75             mProfileId = profileId;
76         }
77     }
78 
79     /** List of profile services related to LE audio */
80     private static final int[] LE_AUDIO_UNICAST_PROFILES = {
81         BluetoothProfile.LE_AUDIO,
82         BluetoothProfile.VOLUME_CONTROL,
83         BluetoothProfile.CSIP_SET_COORDINATOR,
84         BluetoothProfile.MCP_SERVER,
85         BluetoothProfile.LE_CALL_CONTROL,
86     };
87 
88     /** List of profile services with the profile-supported resource flag and bit mask. */
89     private static final ProfileConfig[] PROFILE_SERVICES_AND_FLAGS;
90 
91     static {
92         if (Flags.leaudioSynchronizeStart()) {
93             PROFILE_SERVICES_AND_FLAGS =
94                     new ProfileConfig[] {
95                         new ProfileConfig(A2dpService.isEnabled(), BluetoothProfile.A2DP),
96                         new ProfileConfig(A2dpSinkService.isEnabled(), BluetoothProfile.A2DP_SINK),
97                         new ProfileConfig(AvrcpTargetService.isEnabled(), BluetoothProfile.AVRCP),
98                         new ProfileConfig(
99                                 AvrcpControllerService.isEnabled(),
100                                 BluetoothProfile.AVRCP_CONTROLLER),
101                         new ProfileConfig(
102                                 BassClientService.isEnabled(),
103                                 BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT),
104                         new ProfileConfig(BatteryService.isEnabled(), BluetoothProfile.BATTERY),
105                         new ProfileConfig(
106                                 CsipSetCoordinatorService.isEnabled(),
107                                 BluetoothProfile.CSIP_SET_COORDINATOR),
108                         new ProfileConfig(
109                                 HapClientService.isEnabled(), BluetoothProfile.HAP_CLIENT),
110                         new ProfileConfig(HeadsetService.isEnabled(), BluetoothProfile.HEADSET),
111                         new ProfileConfig(
112                                 HeadsetClientService.isEnabled(), BluetoothProfile.HEADSET_CLIENT),
113                         new ProfileConfig(
114                                 HearingAidService.isEnabled(), BluetoothProfile.HEARING_AID),
115                         new ProfileConfig(
116                                 HidDeviceService.isEnabled(), BluetoothProfile.HID_DEVICE),
117                         new ProfileConfig(HidHostService.isEnabled(), BluetoothProfile.HID_HOST),
118                         new ProfileConfig(GattService.isEnabled(), BluetoothProfile.GATT),
119                         new ProfileConfig(TbsService.isEnabled(), BluetoothProfile.LE_CALL_CONTROL),
120                         new ProfileConfig(BluetoothMapService.isEnabled(), BluetoothProfile.MAP),
121                         new ProfileConfig(
122                                 MapClientService.isEnabled(), BluetoothProfile.MAP_CLIENT),
123                         new ProfileConfig(McpService.isEnabled(), BluetoothProfile.MCP_SERVER),
124                         new ProfileConfig(BluetoothOppService.isEnabled(), BluetoothProfile.OPP),
125                         new ProfileConfig(PanService.isEnabled(), BluetoothProfile.PAN),
126                         new ProfileConfig(BluetoothPbapService.isEnabled(), BluetoothProfile.PBAP),
127                         new ProfileConfig(
128                                 PbapClientService.isEnabled(), BluetoothProfile.PBAP_CLIENT),
129                         new ProfileConfig(SapService.isEnabled(), BluetoothProfile.SAP),
130                         new ProfileConfig(
131                                 VolumeControlService.isEnabled(), BluetoothProfile.VOLUME_CONTROL),
132                         new ProfileConfig(LeAudioService.isEnabled(), BluetoothProfile.LE_AUDIO),
133                         new ProfileConfig(
134                                 LeAudioService.isBroadcastEnabled(),
135                                 BluetoothProfile.LE_AUDIO_BROADCAST),
136                     };
137         } else {
138             PROFILE_SERVICES_AND_FLAGS =
139                     new ProfileConfig[] {
140                         new ProfileConfig(A2dpService.isEnabled(), BluetoothProfile.A2DP),
141                         new ProfileConfig(A2dpSinkService.isEnabled(), BluetoothProfile.A2DP_SINK),
142                         new ProfileConfig(AvrcpTargetService.isEnabled(), BluetoothProfile.AVRCP),
143                         new ProfileConfig(
144                                 AvrcpControllerService.isEnabled(),
145                                 BluetoothProfile.AVRCP_CONTROLLER),
146                         new ProfileConfig(
147                                 BassClientService.isEnabled(),
148                                 BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT),
149                         new ProfileConfig(BatteryService.isEnabled(), BluetoothProfile.BATTERY),
150                         new ProfileConfig(
151                                 CsipSetCoordinatorService.isEnabled(),
152                                 BluetoothProfile.CSIP_SET_COORDINATOR),
153                         new ProfileConfig(
154                                 HapClientService.isEnabled(), BluetoothProfile.HAP_CLIENT),
155                         new ProfileConfig(HeadsetService.isEnabled(), BluetoothProfile.HEADSET),
156                         new ProfileConfig(
157                                 HeadsetClientService.isEnabled(), BluetoothProfile.HEADSET_CLIENT),
158                         new ProfileConfig(
159                                 HearingAidService.isEnabled(), BluetoothProfile.HEARING_AID),
160                         new ProfileConfig(
161                                 HidDeviceService.isEnabled(), BluetoothProfile.HID_DEVICE),
162                         new ProfileConfig(HidHostService.isEnabled(), BluetoothProfile.HID_HOST),
163                         new ProfileConfig(GattService.isEnabled(), BluetoothProfile.GATT),
164                         new ProfileConfig(LeAudioService.isEnabled(), BluetoothProfile.LE_AUDIO),
165                         new ProfileConfig(
166                                 LeAudioService.isBroadcastEnabled(),
167                                 BluetoothProfile.LE_AUDIO_BROADCAST),
168                         new ProfileConfig(TbsService.isEnabled(), BluetoothProfile.LE_CALL_CONTROL),
169                         new ProfileConfig(BluetoothMapService.isEnabled(), BluetoothProfile.MAP),
170                         new ProfileConfig(
171                                 MapClientService.isEnabled(), BluetoothProfile.MAP_CLIENT),
172                         new ProfileConfig(McpService.isEnabled(), BluetoothProfile.MCP_SERVER),
173                         new ProfileConfig(BluetoothOppService.isEnabled(), BluetoothProfile.OPP),
174                         new ProfileConfig(PanService.isEnabled(), BluetoothProfile.PAN),
175                         new ProfileConfig(BluetoothPbapService.isEnabled(), BluetoothProfile.PBAP),
176                         new ProfileConfig(
177                                 PbapClientService.isEnabled(), BluetoothProfile.PBAP_CLIENT),
178                         new ProfileConfig(SapService.isEnabled(), BluetoothProfile.SAP),
179                         new ProfileConfig(
180                                 VolumeControlService.isEnabled(), BluetoothProfile.VOLUME_CONTROL),
181                     };
182         }
183     }
184 
185     /** A test function to allow for dynamic enabled */
186     @VisibleForTesting
setProfileEnabled(int profileId, boolean enabled)187     public static void setProfileEnabled(int profileId, boolean enabled) {
188         for (ProfileConfig profile : PROFILE_SERVICES_AND_FLAGS) {
189             if (profileId == profile.mProfileId) {
190                 profile.mSupported = enabled;
191                 break;
192             }
193         }
194     }
195 
init(Context ctx)196     static void init(Context ctx) {
197         if (LeAudioService.isBroadcastEnabled()) {
198             final String leAudioSwitcherMode =
199                     SystemProperties.get(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, "none");
200             if (leAudioSwitcherMode.equals("disabled")) {
201                 setLeAudioProfileStatus(false);
202                 setLeAudioBroadcastProfileStatus(false);
203             } else if (leAudioSwitcherMode.equals("unicast")) {
204                 setLeAudioProfileStatus(true);
205                 setLeAudioBroadcastProfileStatus(false);
206             } else if (leAudioSwitcherMode.equals("broadcast")) {
207                 setLeAudioProfileStatus(true);
208                 setLeAudioBroadcastProfileStatus(true);
209             }
210         } else if (LeAudioService.isEnabled()) {
211             final boolean leAudioDynamicSwitchSupported =
212                     SystemProperties.getBoolean(LE_AUDIO_DYNAMIC_SWITCH_PROPERTY, false);
213 
214             if (leAudioDynamicSwitchSupported) {
215                 final String leAudioSwitcherDisabled =
216                         SystemProperties.get(LE_AUDIO_SWITCHER_DISABLED_PROPERTY, "none");
217                 if (leAudioSwitcherDisabled.equals("true")) {
218                     setLeAudioProfileStatus(false);
219                 } else if (leAudioSwitcherDisabled.equals("false")) {
220                     setLeAudioProfileStatus(true);
221                 }
222             }
223         }
224 
225         // Disable ASHA on Automotive, TV, and Watch devices if the system property is not set
226         // This means that the OS will not automatically enable ASHA on these platforms, but these
227         // platforms can choose to enable ASHA themselves
228         if (BluetoothProperties.isProfileAshaCentralEnabled().isEmpty()) {
229             if (Utils.isAutomotive(ctx) || Utils.isTv(ctx) || Utils.isWatch(ctx)) {
230                 setProfileEnabled(BluetoothProfile.HEARING_AID, false);
231             }
232         }
233 
234         // TODO: b/321806163 Cleanup post the flag cleanup.
235         // Disable A2DP source profile for automotive devices only if sink is enabled and
236         // concurrent support is not enabled.
237         if (!Flags.a2dpConcurrentSourceSink()
238                 && Utils.isAutomotive(ctx)
239                 && A2dpSinkService.isEnabled()) {
240             setProfileEnabled(BluetoothProfile.A2DP, false);
241             setProfileEnabled(BluetoothProfile.AVRCP, false);
242         }
243 
244         // Disable ASHA if BLE is not supported on this platform even if the platform enabled ASHA
245         // accidentally
246         if (!Utils.isBleSupported(ctx)) {
247             setProfileEnabled(BluetoothProfile.HEARING_AID, false);
248         }
249 
250         for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) {
251             Log.i(
252                     TAG,
253                     String.format(
254                             "init: profile=%s, enabled=%s",
255                             BluetoothProfile.getProfileName(config.mProfileId), config.mSupported));
256         }
257     }
258 
setLeAudioProfileStatus(Boolean enable)259     static void setLeAudioProfileStatus(Boolean enable) {
260         setProfileEnabled(BluetoothProfile.CSIP_SET_COORDINATOR, enable);
261         setProfileEnabled(BluetoothProfile.HAP_CLIENT, enable);
262         setProfileEnabled(BluetoothProfile.LE_AUDIO, enable);
263         setProfileEnabled(BluetoothProfile.LE_CALL_CONTROL, enable);
264         setProfileEnabled(BluetoothProfile.MCP_SERVER, enable);
265         setProfileEnabled(BluetoothProfile.VOLUME_CONTROL, enable);
266     }
267 
setLeAudioBroadcastProfileStatus(Boolean enable)268     static void setLeAudioBroadcastProfileStatus(Boolean enable) {
269         setProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, enable);
270         setProfileEnabled(BluetoothProfile.LE_AUDIO_BROADCAST, enable);
271     }
272 
getLeAudioUnicastProfiles()273     static int[] getLeAudioUnicastProfiles() {
274         return LE_AUDIO_UNICAST_PROFILES;
275     }
276 
getSupportedProfiles()277     static int[] getSupportedProfiles() {
278         return Arrays.stream(PROFILE_SERVICES_AND_FLAGS)
279                 .filter(config -> config.mSupported)
280                 .mapToInt(config -> config.mProfileId)
281                 // LE_AUDIO_BROADCAST don't have an associated class
282                 .filter(profileId -> profileId != BluetoothProfile.LE_AUDIO_BROADCAST)
283                 .toArray();
284     }
285 
getSupportedProfilesBitMask()286     static long getSupportedProfilesBitMask() {
287         long mask = 0;
288         for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) {
289             if (config.mSupported) {
290                 mask |= (1L << config.mProfileId);
291             }
292         }
293         return mask;
294     }
295 }
296