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