1 /* 2 * Copyright 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.RequiresPermission; 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.le.PeriodicAdvertisingCallback; 24 import android.bluetooth.le.PeriodicAdvertisingManager; 25 import android.bluetooth.le.ScanResult; 26 import android.content.ContentProviderClient; 27 import android.content.ContentResolver; 28 import android.content.ContentValues; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.res.AssetFileDescriptor; 32 import android.database.Cursor; 33 import android.net.Uri; 34 import android.os.Bundle; 35 import android.os.CancellationSignal; 36 import android.os.Handler; 37 import android.os.ParcelFileDescriptor; 38 import android.provider.Telephony; 39 import android.util.Log; 40 41 import com.android.bluetooth.gatt.AppAdvertiseStats; 42 import com.android.bluetooth.gatt.ContextMap; 43 import com.android.bluetooth.gatt.GattService; 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.obex.HeaderSet; 46 47 import java.io.FileNotFoundException; 48 import java.io.IOException; 49 import java.io.InputStream; 50 import java.util.Set; 51 52 /** 53 * Proxy class for method calls to help with unit testing 54 */ 55 public class BluetoothMethodProxy { 56 private static final String TAG = BluetoothMethodProxy.class.getSimpleName(); 57 private static final Object INSTANCE_LOCK = new Object(); 58 private static BluetoothMethodProxy sInstance; 59 BluetoothMethodProxy()60 private BluetoothMethodProxy() { 61 } 62 63 /** 64 * Get the singleton instance of proxy 65 * 66 * @return the singleton instance, guaranteed not null 67 */ getInstance()68 public static BluetoothMethodProxy getInstance() { 69 synchronized (INSTANCE_LOCK) { 70 if (sInstance == null) { 71 sInstance = new BluetoothMethodProxy(); 72 } 73 } 74 return sInstance; 75 } 76 77 /** 78 * Allow unit tests to substitute BluetoothPbapMethodCallProxy with a test instance 79 * 80 * @param proxy a test instance of the BluetoothPbapMethodCallProxy 81 */ 82 @VisibleForTesting setInstanceForTesting(BluetoothMethodProxy proxy)83 public static void setInstanceForTesting(BluetoothMethodProxy proxy) { 84 Utils.enforceInstrumentationTestMode(); 85 synchronized (INSTANCE_LOCK) { 86 Log.d(TAG, "setInstanceForTesting(), set to " + proxy); 87 sInstance = proxy; 88 } 89 } 90 91 /** 92 * Proxies {@link ContentResolver#query(Uri, String[], String, String[], String)}. 93 */ contentResolverQuery(ContentResolver contentResolver, final Uri contentUri, final String[] projection, final String selection, final String[] selectionArgs, final String sortOrder)94 public Cursor contentResolverQuery(ContentResolver contentResolver, final Uri contentUri, 95 final String[] projection, final String selection, final String[] selectionArgs, 96 final String sortOrder) { 97 return contentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder); 98 } 99 100 /** 101 * Proxies {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}. 102 */ contentResolverQuery(ContentResolver contentResolver, final Uri contentUri, final String[] projection, final Bundle queryArgs, final CancellationSignal cancellationSignal)103 public Cursor contentResolverQuery(ContentResolver contentResolver, final Uri contentUri, 104 final String[] projection, final Bundle queryArgs, 105 final CancellationSignal cancellationSignal) { 106 return contentResolver.query(contentUri, projection, queryArgs, cancellationSignal); 107 } 108 109 /** 110 * Proxies {@link ContentResolver#insert(Uri, ContentValues)}. 111 */ contentResolverInsert(ContentResolver contentResolver, final Uri contentUri, final ContentValues contentValues)112 public Uri contentResolverInsert(ContentResolver contentResolver, final Uri contentUri, 113 final ContentValues contentValues) { 114 return contentResolver.insert(contentUri, contentValues); 115 } 116 117 /** 118 * Proxies {@link ContentResolver#update(Uri, ContentValues, String, String[])}. 119 */ contentResolverUpdate(ContentResolver contentResolver, final Uri contentUri, final ContentValues contentValues, String where, String[] selectionArgs)120 public int contentResolverUpdate(ContentResolver contentResolver, final Uri contentUri, 121 final ContentValues contentValues, String where, String[] selectionArgs) { 122 return contentResolver.update(contentUri, contentValues, where, selectionArgs); 123 } 124 125 /** 126 * Proxies {@link ContentResolver#delete(Uri, String, String[])}. 127 */ contentResolverDelete(ContentResolver contentResolver, final Uri url, final String where, final String[] selectionArgs)128 public int contentResolverDelete(ContentResolver contentResolver, final Uri url, 129 final String where, 130 final String[] selectionArgs) { 131 return contentResolver.delete(url, where, selectionArgs); 132 } 133 134 /** 135 * Proxies {@link BluetoothAdapter#isEnabled()}. 136 */ bluetoothAdapterIsEnabled(BluetoothAdapter adapter)137 public boolean bluetoothAdapterIsEnabled(BluetoothAdapter adapter) { 138 return adapter.isEnabled(); 139 } 140 141 /** 142 * Proxies {@link ContentResolver#openFileDescriptor(Uri, String)}. 143 */ contentResolverOpenFileDescriptor(ContentResolver contentResolver, final Uri uri, final String mode)144 public ParcelFileDescriptor contentResolverOpenFileDescriptor(ContentResolver contentResolver, 145 final Uri uri, final String mode) throws FileNotFoundException { 146 return contentResolver.openFileDescriptor(uri, mode); 147 } 148 149 /** 150 * Proxies {@link ContentResolver#openAssetFileDescriptor(Uri, String)}. 151 */ contentResolverOpenAssetFileDescriptor( ContentResolver contentResolver, final Uri uri, final String mode)152 public AssetFileDescriptor contentResolverOpenAssetFileDescriptor( 153 ContentResolver contentResolver, final Uri uri, final String mode) 154 throws FileNotFoundException { 155 return contentResolver.openAssetFileDescriptor(uri, mode); 156 } 157 158 /** 159 * Proxies {@link ContentResolver#openInputStream(Uri)}. 160 */ contentResolverOpenInputStream(ContentResolver contentResolver, final Uri uri)161 public InputStream contentResolverOpenInputStream(ContentResolver contentResolver, 162 final Uri uri) throws FileNotFoundException { 163 return contentResolver.openInputStream(uri); 164 } 165 166 /** 167 * Proxies {@link ContentResolver#acquireUnstableContentProviderClient(String)}. 168 */ contentResolverAcquireUnstableContentProviderClient( ContentResolver contentResolver, @NonNull String name)169 public ContentProviderClient contentResolverAcquireUnstableContentProviderClient( 170 ContentResolver contentResolver, @NonNull String name) { 171 return contentResolver.acquireUnstableContentProviderClient(name); 172 } 173 174 /** 175 * Proxies {@link Context#sendBroadcast(Intent)}. 176 */ contextSendBroadcast(Context context, @RequiresPermission Intent intent)177 public void contextSendBroadcast(Context context, @RequiresPermission Intent intent) { 178 context.sendBroadcast(intent); 179 } 180 181 /** 182 * Proxies {@link Handler#sendEmptyMessage(int)}}. 183 */ handlerSendEmptyMessage(Handler handler, final int what)184 public boolean handlerSendEmptyMessage(Handler handler, final int what) { 185 return handler.sendEmptyMessage(what); 186 } 187 188 /** 189 * Proxies {@link HeaderSet#getHeader}. 190 */ getHeader(HeaderSet headerSet, int headerId)191 public Object getHeader(HeaderSet headerSet, int headerId) throws IOException { 192 return headerSet.getHeader(headerId); 193 } 194 195 /** 196 * Proxies {@link Context#getSystemService(Class)}. 197 */ getSystemService(Context context, Class<T> serviceClass)198 public <T> T getSystemService(Context context, Class<T> serviceClass) { 199 return context.getSystemService(serviceClass); 200 } 201 202 /** 203 * Proxies {@link Telephony.Threads#getOrCreateThreadId(Context, Set <String>)}. 204 */ telephonyGetOrCreateThreadId(Context context, Set<String> recipients)205 public long telephonyGetOrCreateThreadId(Context context, Set<String> recipients) { 206 return Telephony.Threads.getOrCreateThreadId(context, recipients); 207 } 208 209 /** 210 * Proxies {@link PeriodicAdvertisingManager#registerSync(ScanResult, int, int, 211 * PeriodicAdvertisingCallback, Handler)}. 212 */ periodicAdvertisingManagerRegisterSync(PeriodicAdvertisingManager manager, ScanResult scanResult, int skip, int timeout, PeriodicAdvertisingCallback callback, Handler handler)213 public void periodicAdvertisingManagerRegisterSync(PeriodicAdvertisingManager manager, 214 ScanResult scanResult, int skip, int timeout, 215 PeriodicAdvertisingCallback callback, Handler handler) { 216 manager.registerSync(scanResult, skip, timeout, callback, handler); 217 } 218 219 /** 220 * Proxies {@link PeriodicAdvertisingManager#transferSync}. 221 */ periodicAdvertisingManagerTransferSync(PeriodicAdvertisingManager manager, BluetoothDevice bda, int serviceData, int syncHandle)222 public void periodicAdvertisingManagerTransferSync(PeriodicAdvertisingManager manager, 223 BluetoothDevice bda, int serviceData, int syncHandle) { 224 manager.transferSync(bda, serviceData, syncHandle); 225 } 226 227 /** 228 * Proxies {@link PeriodicAdvertisingManager#transferSetInfo}. 229 */ periodicAdvertisingManagerTransferSetInfo( PeriodicAdvertisingManager manager, BluetoothDevice bda, int serviceData, int advHandle, PeriodicAdvertisingCallback callback)230 public void periodicAdvertisingManagerTransferSetInfo( 231 PeriodicAdvertisingManager manager, BluetoothDevice bda, int serviceData, 232 int advHandle, PeriodicAdvertisingCallback callback) { 233 manager.transferSetInfo(bda, serviceData, advHandle, callback); 234 } 235 236 /** 237 * Proxies {@link AppAdvertiseStats}. 238 */ createAppAdvertiseStats(int appUid, int id, String name, ContextMap map, GattService service)239 public AppAdvertiseStats createAppAdvertiseStats(int appUid, int id, String name, 240 ContextMap map, GattService service) { 241 return new AppAdvertiseStats(appUid, id, name, map, service); 242 } 243 } 244