• 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.BluetoothAdapter;
20 import android.bluetooth.BluetoothProfile;
21 import android.bluetooth.IBluetoothManager;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.os.IBinder;
26 import android.os.RemoteException;
27 import android.os.ServiceManager;
28 import android.os.SystemProperties;
29 import android.provider.Settings;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import com.android.bluetooth.R;
34 import com.android.bluetooth.a2dp.A2dpService;
35 import com.android.bluetooth.a2dpsink.A2dpSinkService;
36 import com.android.bluetooth.avrcp.AvrcpTargetService;
37 import com.android.bluetooth.avrcpcontroller.AvrcpControllerService;
38 import com.android.bluetooth.gatt.GattService;
39 import com.android.bluetooth.hearingaid.HearingAidService;
40 import com.android.bluetooth.hfp.HeadsetService;
41 import com.android.bluetooth.hfpclient.HeadsetClientService;
42 import com.android.bluetooth.hid.HidDeviceService;
43 import com.android.bluetooth.hid.HidHostService;
44 import com.android.bluetooth.map.BluetoothMapService;
45 import com.android.bluetooth.mapclient.MapClientService;
46 import com.android.bluetooth.opp.BluetoothOppService;
47 import com.android.bluetooth.pan.PanService;
48 import com.android.bluetooth.pbap.BluetoothPbapService;
49 import com.android.bluetooth.pbapclient.PbapClientService;
50 import com.android.bluetooth.sap.SapService;
51 
52 import java.util.ArrayList;
53 import java.util.List;
54 
55 public class Config {
56     private static final String TAG = "AdapterServiceConfig";
57 
58     private static class ProfileConfig {
59         Class mClass;
60         int mSupported;
61         long mMask;
62 
ProfileConfig(Class theClass, int supportedFlag, long mask)63         ProfileConfig(Class theClass, int supportedFlag, long mask) {
64             mClass = theClass;
65             mSupported = supportedFlag;
66             mMask = mask;
67         }
68     }
69 
70     /**
71      * List of profile services with the profile-supported resource flag and bit mask.
72      */
73     private static final ProfileConfig[] PROFILE_SERVICES_AND_FLAGS = {
74             new ProfileConfig(HeadsetService.class, R.bool.profile_supported_hs_hfp,
75                     (1 << BluetoothProfile.HEADSET)),
76             new ProfileConfig(A2dpService.class, R.bool.profile_supported_a2dp,
77                     (1 << BluetoothProfile.A2DP)),
78             new ProfileConfig(A2dpSinkService.class, R.bool.profile_supported_a2dp_sink,
79                     (1 << BluetoothProfile.A2DP_SINK)),
80             new ProfileConfig(HidHostService.class, R.bool.profile_supported_hid_host,
81                     (1 << BluetoothProfile.HID_HOST)),
82             new ProfileConfig(PanService.class, R.bool.profile_supported_pan,
83                     (1 << BluetoothProfile.PAN)),
84             new ProfileConfig(GattService.class, R.bool.profile_supported_gatt,
85                     (1 << BluetoothProfile.GATT)),
86             new ProfileConfig(BluetoothMapService.class, R.bool.profile_supported_map,
87                     (1 << BluetoothProfile.MAP)),
88             new ProfileConfig(HeadsetClientService.class, R.bool.profile_supported_hfpclient,
89                     (1 << BluetoothProfile.HEADSET_CLIENT)),
90             new ProfileConfig(AvrcpTargetService.class, R.bool.profile_supported_avrcp_target,
91                     (1 << BluetoothProfile.AVRCP)),
92             new ProfileConfig(AvrcpControllerService.class,
93                     R.bool.profile_supported_avrcp_controller,
94                     (1 << BluetoothProfile.AVRCP_CONTROLLER)),
95             new ProfileConfig(SapService.class, R.bool.profile_supported_sap,
96                     (1 << BluetoothProfile.SAP)),
97             new ProfileConfig(PbapClientService.class, R.bool.profile_supported_pbapclient,
98                     (1 << BluetoothProfile.PBAP_CLIENT)),
99             new ProfileConfig(MapClientService.class, R.bool.profile_supported_mapmce,
100                     (1 << BluetoothProfile.MAP_CLIENT)),
101             new ProfileConfig(HidDeviceService.class, R.bool.profile_supported_hid_device,
102                     (1 << BluetoothProfile.HID_DEVICE)),
103             new ProfileConfig(BluetoothOppService.class, R.bool.profile_supported_opp,
104                     (1 << BluetoothProfile.OPP)),
105             new ProfileConfig(BluetoothPbapService.class, R.bool.profile_supported_pbap,
106                     (1 << BluetoothProfile.PBAP)),
107             new ProfileConfig(HearingAidService.class,
108                     com.android.internal.R.bool.config_hearing_aid_profile_supported,
109                     (1 << BluetoothProfile.HEARING_AID))
110     };
111 
112     private static Class[] sSupportedProfiles = new Class[0];
113 
114     private static boolean sIsGdEnabledUptoScanningLayer = false;
115 
init(Context ctx)116     static void init(Context ctx) {
117         if (ctx == null) {
118             return;
119         }
120         Resources resources = ctx.getResources();
121         if (resources == null) {
122             return;
123         }
124         List<String> enabledProfiles =
125                 getSystemConfigEnabledProfilesForPackage(ctx.getPackageName());
126 
127         ArrayList<Class> profiles = new ArrayList<>(PROFILE_SERVICES_AND_FLAGS.length);
128         for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) {
129             boolean supported = resources.getBoolean(config.mSupported);
130 
131             if (!supported && (config.mClass == HearingAidService.class) && isHearingAidSettingsEnabled(ctx)) {
132                 Log.v(TAG, "Feature Flag enables support for HearingAidService");
133                 supported = true;
134             }
135 
136             if (enabledProfiles != null && enabledProfiles.contains(config.mClass.getName())) {
137                 supported = true;
138                 Log.v(TAG, config.mClass.getSimpleName() + " Feature Flag set to " + supported
139                         + " by components configuration");
140             }
141 
142             if (supported && !isProfileDisabled(ctx, config.mMask)) {
143                 Log.v(TAG, "Adding " + config.mClass.getSimpleName());
144                 profiles.add(config.mClass);
145             }
146         }
147         sSupportedProfiles = profiles.toArray(new Class[profiles.size()]);
148         sIsGdEnabledUptoScanningLayer = resources.getBoolean(R.bool.enable_gd_up_to_scanning_layer);
149     }
150 
getSupportedProfiles()151     static Class[] getSupportedProfiles() {
152         return sSupportedProfiles;
153     }
154 
isGdEnabledUpToScanningLayer()155     static boolean isGdEnabledUpToScanningLayer() {
156         return sIsGdEnabledUptoScanningLayer;
157     }
158 
getProfileMask(Class profile)159     private static long getProfileMask(Class profile) {
160         for (ProfileConfig config : PROFILE_SERVICES_AND_FLAGS) {
161             if (config.mClass == profile) {
162                 return config.mMask;
163             }
164         }
165         Log.w(TAG, "Could not find profile bit mask for " + profile.getSimpleName());
166         return 0;
167     }
168 
getSupportedProfilesBitMask()169     static long getSupportedProfilesBitMask() {
170         long mask = 0;
171         for (final Class profileClass : getSupportedProfiles()) {
172             mask |= getProfileMask(profileClass);
173         }
174         return mask;
175     }
176 
isProfileDisabled(Context context, long profileMask)177     private static boolean isProfileDisabled(Context context, long profileMask) {
178         final ContentResolver resolver = context.getContentResolver();
179         final long disabledProfilesBitMask =
180                 Settings.Global.getLong(resolver, Settings.Global.BLUETOOTH_DISABLED_PROFILES, 0);
181 
182         return (disabledProfilesBitMask & profileMask) != 0;
183     }
184 
isHearingAidSettingsEnabled(Context context)185     private static boolean isHearingAidSettingsEnabled(Context context) {
186         final String flagOverridePrefix = "sys.fflag.override.";
187         final String hearingAidSettings = "settings_bluetooth_hearing_aid";
188 
189         // Override precedence:
190         // Settings.Global -> sys.fflag.override.* -> static list
191 
192         // Step 1: check if hearing aid flag is set in Settings.Global.
193         String value;
194         if (context != null) {
195             value = Settings.Global.getString(context.getContentResolver(), hearingAidSettings);
196             if (!TextUtils.isEmpty(value)) {
197                 return Boolean.parseBoolean(value);
198             }
199         }
200 
201         // Step 2: check if hearing aid flag has any override.
202         value = SystemProperties.get(flagOverridePrefix + hearingAidSettings);
203         if (!TextUtils.isEmpty(value)) {
204             return Boolean.parseBoolean(value);
205         }
206 
207         // Step 3: return default value.
208         return false;
209     }
210 
getSystemConfigEnabledProfilesForPackage(String packageName)211     private static List<String> getSystemConfigEnabledProfilesForPackage(String packageName) {
212         IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE);
213         if (b == null) {
214             Log.e(TAG, "Bluetooth binder is null");
215         }
216 
217         IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
218         try {
219             return managerService.getSystemConfigEnabledProfilesForPackage(packageName);
220         } catch (RemoteException e) {
221             return null;
222         }
223 
224     }
225 }
226