1 /*
2  * Copyright (c) 2022 The Android Open Source Project
3  * Copyright (c) 2020 The Linux Foundation
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.btservice;
19 
20 import android.util.Log;
21 
22 /**
23  * APIs of interoperability workaround utilities. These APIs will call stack layer's interop APIs of
24  * interop.cc to do matching or entry adding/removing.
25  */
26 public class InteropUtil {
27     private static final String TAG = "InteropUtil";
28 
29     /**
30      * Add interop feature from device/include/interop.h to below InteropFeature if this feature
31      * needs to be matched at java layer. Feature's name will be passed to stack layer to do
32      * matching, so make sure that the added feature's name is exactly same as that in
33      * device/include/interop.h.
34      */
35     public enum InteropFeature {
36         INTEROP_NOT_UPDATE_AVRCP_PAUSED_TO_REMOTE,
37         INTEROP_PHONE_POLICY_INCREASED_DELAY_CONNECT_OTHER_PROFILES,
38         INTEROP_PHONE_POLICY_REDUCED_DELAY_CONNECT_OTHER_PROFILES,
39         INTEROP_HFP_FAKE_INCOMING_CALL_INDICATOR,
40         INTEROP_HFP_SEND_CALL_INDICATORS_BACK_TO_BACK,
41         INTEROP_SETUP_SCO_WITH_NO_DELAY_AFTER_SLC_DURING_CALL,
42         INTEROP_RETRY_SCO_AFTER_REMOTE_REJECT_SCO,
43         INTEROP_ADV_PBAP_VER_1_2;
44     }
45 
46     /**
47      * Check if a given address matches a known interoperability workaround identified by the
48      * interop feature.
49      *
50      * @param feature a given interop feature defined in {@link InteropFeature}.
51      * @param address a given address to be matched.
52      * @return true if matched, false otherwise.
53      */
interopMatchAddr(InteropFeature feature, String address)54     public static boolean interopMatchAddr(InteropFeature feature, String address) {
55         AdapterService adapterService = AdapterService.getAdapterService();
56         if (adapterService == null) {
57             Log.d(
58                     TAG,
59                     "interopMatchAddr: feature="
60                             + feature.name()
61                             + ", adapterService is null or vendor intf is not enabled");
62             return false;
63         }
64 
65         Log.d(TAG, "interopMatchAddr: feature=" + feature.name() + ", address=" + address);
66         if (address == null) {
67             return false;
68         }
69 
70         boolean matched = adapterService.interopMatchAddr(feature, address);
71         Log.d(TAG, "interopMatchAddr: matched=" + matched);
72         return matched;
73     }
74 
75     /**
76      * Check if a given name matches a known interoperability workaround identified by the interop
77      * feature.
78      *
79      * @param feature a given interop feature defined in {@link InteropFeature}.
80      * @param name a given name to be matched.
81      * @return true if matched, false otherwise.
82      */
interopMatchName(InteropFeature feature, String name)83     public static boolean interopMatchName(InteropFeature feature, String name) {
84         AdapterService adapterService = AdapterService.getAdapterService();
85         if (adapterService == null) {
86             Log.d(
87                     TAG,
88                     "interopMatchName: feature="
89                             + feature.name()
90                             + ", adapterService is null or vendor intf is not enabled");
91             return false;
92         }
93 
94         Log.d(TAG, "interopMatchName: feature=" + feature.name() + ", name=" + name);
95         if (name == null) {
96             return false;
97         }
98 
99         boolean matched = adapterService.interopMatchName(feature, name);
100         Log.d(TAG, "interopMatchName: matched=" + matched);
101         return matched;
102     }
103 
104     /**
105      * Check if a given address or remote device name matches a known interoperability workaround
106      * identified by the interop feature. remote device name will be fetched internally based on the
107      * given address at stack layer.
108      *
109      * @param feature a given interop feature defined in {@link InteropFeature}.
110      * @param address a given address to be matched.
111      * @return true if matched, false otherwise
112      */
interopMatchAddrOrName(InteropFeature feature, String address)113     public static boolean interopMatchAddrOrName(InteropFeature feature, String address) {
114         AdapterService adapterService = AdapterService.getAdapterService();
115         if (adapterService == null) {
116             Log.d(
117                     TAG,
118                     "interopMatchAddrOrName: feature="
119                             + feature.name()
120                             + ", adapterService is null or vendor intf is not enabled");
121             return false;
122         }
123 
124         Log.d(TAG, "interopMatchAddrOrName: feature=" + feature.name() + ", address=" + address);
125         if (address == null) {
126             return false;
127         }
128 
129         boolean matched = adapterService.interopMatchAddrOrName(feature, address);
130         Log.d(TAG, "interopMatchAddrOrName: matched=" + matched);
131         return matched;
132     }
133 
134     /**
135      * Add a dynamic address interop database entry identified by the interop feature for a device
136      * matching the first length bytes of addr.
137      *
138      * @param feature a given interop feature defined in {@link InteropFeature}.
139      * @param address a given address to be added.
140      * @param length the number of bytes of address to be stored, length must be in [1,6], and
141      *     usually it is 3.
142      */
interopDatabaseAddAddr(InteropFeature feature, String address, int length)143     public static void interopDatabaseAddAddr(InteropFeature feature, String address, int length) {
144         AdapterService adapterService = AdapterService.getAdapterService();
145         if (adapterService == null) {
146             Log.d(
147                     TAG,
148                     "interopDatabaseAddAddr: feature="
149                             + feature.name()
150                             + ", adapterService is null or vendor intf is not enabled");
151             return;
152         }
153 
154         Log.d(
155                 TAG,
156                 "interopDatabaseAddAddr: feature="
157                         + feature.name()
158                         + ", address="
159                         + address
160                         + ", length="
161                         + length);
162         if (address == null || (length <= 0 || length > 6)) {
163             return;
164         }
165 
166         adapterService.interopDatabaseAddAddr(feature, address, length);
167     }
168 
169     /**
170      * Remove a dynamic address interop database entry identified by the interop feature for a
171      * device matching the addr.
172      *
173      * @param feature a given interop feature defined in {@link InteropFeature}.
174      * @param address a given address to be removed.
175      */
interopDatabaseRemoveAddr(InteropFeature feature, String address)176     public static void interopDatabaseRemoveAddr(InteropFeature feature, String address) {
177         AdapterService adapterService = AdapterService.getAdapterService();
178         if (adapterService == null) {
179             Log.d(
180                     TAG,
181                     "interopDatabaseRemoveAddr: feature="
182                             + feature.name()
183                             + ", adapterService is null or vendor intf is not enabled");
184             return;
185         }
186 
187         Log.d(TAG, "interopDatabaseRemoveAddr: feature=" + feature.name() + ", address=" + address);
188         if (address == null) {
189             return;
190         }
191 
192         adapterService.interopDatabaseRemoveAddr(feature, address);
193     }
194 
195     /**
196      * Add a dynamic name interop database entry identified by the interop feature for the name.
197      *
198      * @param feature a given interop feature defined in {@link InteropFeature}.
199      * @param name a given name to be added.
200      */
interopDatabaseAddName(InteropFeature feature, String name)201     public static void interopDatabaseAddName(InteropFeature feature, String name) {
202         AdapterService adapterService = AdapterService.getAdapterService();
203         if (adapterService == null) {
204             Log.d(
205                     TAG,
206                     "interopDatabaseAddName: feature="
207                             + feature.name()
208                             + ", adapterService is null or vendor intf is not enabled");
209             return;
210         }
211 
212         Log.d(TAG, "interopDatabaseAddName: feature=" + feature.name() + ", name=" + name);
213         if (name == null) {
214             return;
215         }
216 
217         adapterService.interopDatabaseAddName(feature, name);
218     }
219 
220     /**
221      * Remove a dynamic name interop database entry identified by the interop feature for the name.
222      *
223      * @param feature a given interop feature defined in {@link InteropFeature}.
224      * @param name a given name to be removed.
225      */
interopDatabaseRemoveName(InteropFeature feature, String name)226     public static void interopDatabaseRemoveName(InteropFeature feature, String name) {
227         AdapterService adapterService = AdapterService.getAdapterService();
228         if (adapterService == null) {
229             Log.d(
230                     TAG,
231                     "interopDatabaseRemoveName: feature="
232                             + feature.name()
233                             + ", adapterService is null or vendor intf is not enabled");
234             return;
235         }
236 
237         Log.d(TAG, "interopDatabaseRemoveName: feature=" + feature.name() + ", name=" + name);
238         if (name == null) {
239             return;
240         }
241 
242         adapterService.interopDatabaseRemoveName(feature, name);
243     }
244 }
245