• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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;
18 
19 import android.annotation.NonNull;
20 import android.annotation.SuppressLint;
21 import android.app.ComponentCaller;
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothDevice;
24 import android.bluetooth.le.PeriodicAdvertisingCallback;
25 import android.bluetooth.le.PeriodicAdvertisingManager;
26 import android.bluetooth.le.ScanResult;
27 import android.content.ContentProviderClient;
28 import android.content.ContentResolver;
29 import android.content.ContentValues;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.res.AssetFileDescriptor;
33 import android.database.Cursor;
34 import android.media.session.MediaController;
35 import android.media.session.MediaSessionManager;
36 import android.net.Uri;
37 import android.os.Build;
38 import android.os.Bundle;
39 import android.os.CancellationSignal;
40 import android.os.Handler;
41 import android.os.HandlerThread;
42 import android.os.Looper;
43 import android.os.Message;
44 import android.os.ParcelFileDescriptor;
45 import android.provider.Telephony;
46 import android.util.Log;
47 
48 import androidx.annotation.RequiresApi;
49 
50 import com.android.bluetooth.bass_client.BassClientPeriodicAdvertisingManager;
51 import com.android.internal.annotations.VisibleForTesting;
52 import com.android.obex.HeaderSet;
53 
54 import java.io.FileNotFoundException;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.io.OutputStream;
58 import java.util.List;
59 import java.util.Set;
60 
61 /** Proxy class for method calls to help with unit testing */
62 // TODO: Remove this entire class, as it is abused and provide helper to call framework code which
63 // should be avoided
64 public class BluetoothMethodProxy {
65     private static final String TAG = BluetoothMethodProxy.class.getSimpleName();
66 
67     private static final Object INSTANCE_LOCK = new Object();
68     private static BluetoothMethodProxy sInstance;
69 
BluetoothMethodProxy()70     private BluetoothMethodProxy() {}
71 
72     /**
73      * Get the singleton instance of proxy
74      *
75      * @return the singleton instance, guaranteed not null
76      */
getInstance()77     public static BluetoothMethodProxy getInstance() {
78         synchronized (INSTANCE_LOCK) {
79             if (sInstance == null) {
80                 sInstance = new BluetoothMethodProxy();
81             }
82         }
83         return sInstance;
84     }
85 
86     /**
87      * Allow unit tests to substitute BluetoothPbapMethodCallProxy with a test instance
88      *
89      * @param proxy a test instance of the BluetoothPbapMethodCallProxy
90      */
91     @VisibleForTesting
setInstanceForTesting(BluetoothMethodProxy proxy)92     public static void setInstanceForTesting(BluetoothMethodProxy proxy) {
93         Utils.enforceInstrumentationTestMode();
94         synchronized (INSTANCE_LOCK) {
95             Log.d(TAG, "setInstanceForTesting(), set to " + proxy);
96             sInstance = proxy;
97         }
98     }
99 
100     /** Proxies {@link ContentResolver#query(Uri, String[], String, String[], String)}. */
contentResolverQuery( ContentResolver contentResolver, final Uri contentUri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder)101     public Cursor contentResolverQuery(
102             ContentResolver contentResolver,
103             final Uri contentUri,
104             final String[] projection,
105             final String selection,
106             final String[] selectionArgs,
107             final String sortOrder) {
108         try {
109             return contentResolver.query(
110                     contentUri, projection, selection, selectionArgs, sortOrder);
111         } catch (Exception e) {
112             Log.e(TAG, "Exception happened" + e + "\n" + Log.getStackTraceString(new Throwable()));
113             return null;
114         }
115     }
116 
117     /** Proxies {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}. */
contentResolverQuery( ContentResolver contentResolver, final Uri contentUri, final String[] projection, final Bundle queryArgs, final CancellationSignal cancellationSignal)118     public Cursor contentResolverQuery(
119             ContentResolver contentResolver,
120             final Uri contentUri,
121             final String[] projection,
122             final Bundle queryArgs,
123             final CancellationSignal cancellationSignal) {
124         try {
125             return contentResolver.query(contentUri, projection, queryArgs, cancellationSignal);
126         } catch (Exception e) {
127             Log.e(TAG, "Exception happened " + e + "\n" + Log.getStackTraceString(new Throwable()));
128             return null;
129         }
130     }
131 
132     /** Proxies {@link ContentResolver#insert(Uri, ContentValues)}. */
contentResolverInsert( ContentResolver contentResolver, final Uri contentUri, final ContentValues contentValues)133     public Uri contentResolverInsert(
134             ContentResolver contentResolver,
135             final Uri contentUri,
136             final ContentValues contentValues) {
137         return contentResolver.insert(contentUri, contentValues);
138     }
139 
140     /** Proxies {@link ContentResolver#update(Uri, ContentValues, String, String[])}. */
contentResolverUpdate( ContentResolver contentResolver, final Uri contentUri, final ContentValues contentValues, String where, String[] selectionArgs)141     public int contentResolverUpdate(
142             ContentResolver contentResolver,
143             final Uri contentUri,
144             final ContentValues contentValues,
145             String where,
146             String[] selectionArgs) {
147         return contentResolver.update(contentUri, contentValues, where, selectionArgs);
148     }
149 
150     /** Proxies {@link ContentResolver#delete(Uri, String, String[])}. */
contentResolverDelete( ContentResolver contentResolver, final Uri url, final String where, final String[] selectionArgs)151     public int contentResolverDelete(
152             ContentResolver contentResolver,
153             final Uri url,
154             final String where,
155             final String[] selectionArgs) {
156         return contentResolver.delete(url, where, selectionArgs);
157     }
158 
159     /** Proxies {@link BluetoothAdapter#isEnabled()}. */
bluetoothAdapterIsEnabled(BluetoothAdapter adapter)160     public boolean bluetoothAdapterIsEnabled(BluetoothAdapter adapter) {
161         return adapter.isEnabled();
162     }
163 
164     /**
165      * Proxies {@link BluetoothAdapter#getRemoteLeDevice(String, int)} on default Bluetooth Adapter.
166      */
getDefaultAdapterRemoteLeDevice(String address, int addressType)167     public BluetoothDevice getDefaultAdapterRemoteLeDevice(String address, int addressType) {
168         return BluetoothAdapter.getDefaultAdapter().getRemoteLeDevice(address, addressType);
169     }
170 
171     /** Proxies {@link ContentResolver#openFileDescriptor(Uri, String)}. */
contentResolverOpenFileDescriptor( ContentResolver contentResolver, final Uri uri, final String mode)172     public ParcelFileDescriptor contentResolverOpenFileDescriptor(
173             ContentResolver contentResolver, final Uri uri, final String mode)
174             throws FileNotFoundException {
175         return contentResolver.openFileDescriptor(uri, mode);
176     }
177 
178     /** Proxies {@link ContentResolver#openAssetFileDescriptor(Uri, String)}. */
contentResolverOpenAssetFileDescriptor( ContentResolver contentResolver, final Uri uri, final String mode)179     public AssetFileDescriptor contentResolverOpenAssetFileDescriptor(
180             ContentResolver contentResolver, final Uri uri, final String mode)
181             throws FileNotFoundException {
182         return contentResolver.openAssetFileDescriptor(uri, mode);
183     }
184 
185     /** Proxies {@link ContentResolver#openInputStream(Uri)}. */
contentResolverOpenInputStream( ContentResolver contentResolver, final Uri uri)186     public InputStream contentResolverOpenInputStream(
187             ContentResolver contentResolver, final Uri uri) throws FileNotFoundException {
188         return contentResolver.openInputStream(uri);
189     }
190 
191     /** Proxies {@link ContentResolver#acquireUnstableContentProviderClient(String)}. */
contentResolverAcquireUnstableContentProviderClient( ContentResolver contentResolver, @NonNull String name)192     public ContentProviderClient contentResolverAcquireUnstableContentProviderClient(
193             ContentResolver contentResolver, @NonNull String name) {
194         return contentResolver.acquireUnstableContentProviderClient(name);
195     }
196 
197     /** Proxies {@link ContentResolver#openOutputStream(Uri)}. */
contentResolverOpenOutputStream(ContentResolver contentResolver, Uri uri)198     public OutputStream contentResolverOpenOutputStream(ContentResolver contentResolver, Uri uri)
199             throws FileNotFoundException {
200         return contentResolver.openOutputStream(uri);
201     }
202 
203     /** Proxies {@link Context#sendBroadcast(Intent)}. */
204     @SuppressLint("AndroidFrameworkRequiresPermission") // only intent is ACTION_OPEN
contextSendBroadcast(Context context, Intent intent)205     public void contextSendBroadcast(Context context, Intent intent) {
206         context.sendBroadcast(intent);
207     }
208 
209     /** Proxies {@link Handler#sendEmptyMessage(int)}}. */
handlerSendEmptyMessage(Handler handler, final int what)210     public boolean handlerSendEmptyMessage(Handler handler, final int what) {
211         return handler.sendEmptyMessage(what);
212     }
213 
214     /** Proxies {@link Handler#sendMessageDelayed(Message, long)}. */
handlerSendMessageDelayed( Handler handler, final int what, final long delayMillis)215     public boolean handlerSendMessageDelayed(
216             Handler handler, final int what, final long delayMillis) {
217         return handler.sendMessageDelayed(handler.obtainMessage(what), delayMillis);
218     }
219 
220     /** Proxies {@link HeaderSet#getHeader}. */
getHeader(HeaderSet headerSet, int headerId)221     public Object getHeader(HeaderSet headerSet, int headerId) throws IOException {
222         return headerSet.getHeader(headerId);
223     }
224 
225     /** Proxies {@link Context#getSystemService(Class)}. */
getSystemService(Context context, Class<T> serviceClass)226     public <T> T getSystemService(Context context, Class<T> serviceClass) {
227         return context.getSystemService(serviceClass);
228     }
229 
230     /** Proxies {@link Telephony.Threads#getOrCreateThreadId(Context, Set <String>)}. */
telephonyGetOrCreateThreadId(Context context, Set<String> recipients)231     public long telephonyGetOrCreateThreadId(Context context, Set<String> recipients) {
232         return Telephony.Threads.getOrCreateThreadId(context, recipients);
233     }
234 
235     /**
236      * Proxies {@link
237      * BassClientPeriodicAdvertisingManager#initializePeriodicAdvertisingManagerOnDefaultAdapter}.
238      */
initializePeriodicAdvertisingManagerOnDefaultAdapter()239     public boolean initializePeriodicAdvertisingManagerOnDefaultAdapter() {
240         return BassClientPeriodicAdvertisingManager
241                 .initializePeriodicAdvertisingManagerOnDefaultAdapter();
242     }
243 
244     /**
245      * Proxies {@link PeriodicAdvertisingManager#registerSync(ScanResult, int, int,
246      * PeriodicAdvertisingCallback, Handler)}.
247      */
248     @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786
periodicAdvertisingManagerRegisterSync( PeriodicAdvertisingManager manager, ScanResult scanResult, int skip, int timeout, PeriodicAdvertisingCallback callback, Handler handler)249     public void periodicAdvertisingManagerRegisterSync(
250             PeriodicAdvertisingManager manager,
251             ScanResult scanResult,
252             int skip,
253             int timeout,
254             PeriodicAdvertisingCallback callback,
255             Handler handler) {
256         manager.registerSync(scanResult, skip, timeout, callback, handler);
257     }
258 
259     /** Proxies {@link PeriodicAdvertisingManager#unregisterSync(PeriodicAdvertisingCallback)}. */
260     @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786
periodicAdvertisingManagerUnregisterSync( PeriodicAdvertisingManager manager, PeriodicAdvertisingCallback callback)261     public void periodicAdvertisingManagerUnregisterSync(
262             PeriodicAdvertisingManager manager, PeriodicAdvertisingCallback callback) {
263         manager.unregisterSync(callback);
264     }
265 
266     /** Proxies {@link PeriodicAdvertisingManager#transferSync}. */
267     @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786
periodicAdvertisingManagerTransferSync( PeriodicAdvertisingManager manager, BluetoothDevice bda, int serviceData, int syncHandle)268     public void periodicAdvertisingManagerTransferSync(
269             PeriodicAdvertisingManager manager,
270             BluetoothDevice bda,
271             int serviceData,
272             int syncHandle) {
273         manager.transferSync(bda, serviceData, syncHandle);
274     }
275 
276     /** Proxies {@link PeriodicAdvertisingManager#transferSetInfo}. */
277     @SuppressLint("AndroidFrameworkRequiresPermission") // TODO: b/350563786
periodicAdvertisingManagerTransferSetInfo( PeriodicAdvertisingManager manager, BluetoothDevice bda, int serviceData, int advHandle, PeriodicAdvertisingCallback callback)278     public void periodicAdvertisingManagerTransferSetInfo(
279             PeriodicAdvertisingManager manager,
280             BluetoothDevice bda,
281             int serviceData,
282             int advHandle,
283             PeriodicAdvertisingCallback callback) {
284         manager.transferSetInfo(bda, serviceData, advHandle, callback);
285     }
286 
287     /** Proxies {@link Thread#start()}. */
threadStart(Thread thread)288     public void threadStart(Thread thread) {
289         thread.start();
290     }
291 
292     /** Proxies {@link HandlerThread#getLooper()}. */
handlerThreadGetLooper(HandlerThread handlerThread)293     public Looper handlerThreadGetLooper(HandlerThread handlerThread) {
294         return handlerThread.getLooper();
295     }
296 
297     /** Proxies {@link MediaSessionManager#getActiveSessions} */
mediaSessionManagerGetActiveSessions( MediaSessionManager manager)298     public @NonNull List<MediaController> mediaSessionManagerGetActiveSessions(
299             MediaSessionManager manager) {
300         return manager.getActiveSessions(null);
301     }
302 
303     /** Proxies {@link ComponentCaller#checkContentUriPermission(Uri, int)}. } */
304     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
componentCallerCheckContentUriPermission( ComponentCaller caller, Uri uri, int modeFlags)305     public int componentCallerCheckContentUriPermission(
306             ComponentCaller caller, Uri uri, int modeFlags) {
307         return caller.checkContentUriPermission(uri, modeFlags);
308     }
309 
310     /** Proxies {@link Context#grantUriPermission(String, Uri, int)}. } */
grantUriPermission(Context context, String packageName, Uri uri, int modeFlags)311     public void grantUriPermission(Context context, String packageName, Uri uri, int modeFlags) {
312         context.grantUriPermission(packageName, uri, modeFlags);
313     }
314 }
315