Loading android/app/AndroidManifest.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> Loading android/app/src/com/android/bluetooth/Utils.java +24 −0 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,12 @@ package com.android.bluetooth; import android.app.ActivityManager; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ActivityThread; import android.app.AppOpsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.Context; import android.content.ContextWrapper; import android.content.ContextWrapper; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Binder; import android.os.ParcelUuid; import android.os.ParcelUuid; Loading Loading @@ -266,6 +268,28 @@ final public class Utils { "Need BLUETOOTH_ADMIN permission"); "Need BLUETOOTH_ADMIN permission"); } } /** * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed */ public static boolean checkCallerHasLocationPermission(Context context, AppOpsManager appOps, String callingPackage) { if (context.checkCallingOrSelfPermission(android.Manifest.permission. ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } return context.checkCallingOrSelfPermission(android.Manifest.permission. ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_COARSE_LOCATION, callingPackage); } private static boolean isAppOppAllowed(AppOpsManager appOps, int op, String callingPackage) { return appOps.noteOp(op, Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED; } /** /** * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond. * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond. */ */ Loading android/app/src/com/android/bluetooth/gatt/GattService.java +13 −5 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.bluetooth.gatt; package com.android.bluetooth.gatt; import android.app.AppOpsManager; import android.app.Service; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; Loading Loading @@ -148,6 +149,7 @@ public class GattService extends ProfileService { private AdvertiseManager mAdvertiseManager; private AdvertiseManager mAdvertiseManager; private ScanManager mScanManager; private ScanManager mScanManager; private AppOpsManager mAppOps; /** /** * Reliable write queue * Reliable write queue Loading @@ -169,6 +171,7 @@ public class GattService extends ProfileService { protected boolean start() { protected boolean start() { if (DBG) Log.d(TAG, "start()"); if (DBG) Log.d(TAG, "start()"); initializeNative(); initializeNative(); mAppOps = getSystemService(AppOpsManager.class); mAdvertiseManager = new AdvertiseManager(this, AdapterService.getAdapterService()); mAdvertiseManager = new AdvertiseManager(this, AdapterService.getAdapterService()); mAdvertiseManager.start(); mAdvertiseManager.start(); Loading Loading @@ -303,10 +306,10 @@ public class GattService extends ProfileService { @Override @Override public void startScan(int appIf, boolean isServer, ScanSettings settings, public void startScan(int appIf, boolean isServer, ScanSettings settings, List<ScanFilter> filters, List storages) { List<ScanFilter> filters, List storages, String callingPackage) { GattService service = getService(); GattService service = getService(); if (service == null) return; if (service == null) return; service.startScan(appIf, isServer, settings, filters, storages); service.startScan(appIf, isServer, settings, filters, storages, callingPackage); } } public void stopScan(int appIf, boolean isServer) { public void stopScan(int appIf, boolean isServer) { Loading Loading @@ -599,7 +602,7 @@ public class GattService extends ProfileService { .getRemoteDevice(address); .getRemoteDevice(address); ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), rssi, SystemClock.elapsedRealtimeNanos()); rssi, SystemClock.elapsedRealtimeNanos()); if (matchesFilters(client, result)) { if (client.hasLocationPermission && matchesFilters(client, result)) { try { try { ScanSettings settings = client.settings; ScanSettings settings = client.settings; if ((settings.getCallbackType() & if ((settings.getCallbackType() & Loading Loading @@ -1350,13 +1353,18 @@ public class GattService extends ProfileService { } } void startScan(int appIf, boolean isServer, ScanSettings settings, void startScan(int appIf, boolean isServer, ScanSettings settings, List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages) { List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages, String callingPackage) { if (DBG) Log.d(TAG, "start scan with filters"); if (DBG) Log.d(TAG, "start scan with filters"); enforceAdminPermission(); enforceAdminPermission(); if (needsPrivilegedPermissionForScan(settings)) { if (needsPrivilegedPermissionForScan(settings)) { enforcePrivilegedPermission(); enforcePrivilegedPermission(); } } mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters, storages)); boolean hasLocationPermission = Utils.checkCallerHasLocationPermission(this, mAppOps, callingPackage); final ScanClient scanClient = new ScanClient(appIf, isServer, settings, filters, storages); scanClient.hasLocationPermission = hasLocationPermission; mScanManager.startScan(scanClient); } } void flushPendingBatchResults(int clientIf, boolean isServer) { void flushPendingBatchResults(int clientIf, boolean isServer) { Loading android/app/src/com/android/bluetooth/gatt/ScanClient.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ import java.util.UUID; List<List<ResultStorageDescriptor>> storages; List<List<ResultStorageDescriptor>> storages; // App associated with the scan client died. // App associated with the scan client died. boolean appDied; boolean appDied; boolean hasLocationPermission; private static final ScanSettings DEFAULT_SCAN_SETTINGS = new ScanSettings.Builder() private static final ScanSettings DEFAULT_SCAN_SETTINGS = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); Loading Loading
android/app/AndroidManifest.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" /> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> <uses-permission android:name="android.permission.DEVICE_POWER" /> Loading
android/app/src/com/android/bluetooth/Utils.java +24 −0 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,12 @@ package com.android.bluetooth; import android.app.ActivityManager; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ActivityThread; import android.app.AppOpsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.Context; import android.content.ContextWrapper; import android.content.ContextWrapper; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.pm.UserInfo; import android.os.Binder; import android.os.Binder; import android.os.ParcelUuid; import android.os.ParcelUuid; Loading Loading @@ -266,6 +268,28 @@ final public class Utils { "Need BLUETOOTH_ADMIN permission"); "Need BLUETOOTH_ADMIN permission"); } } /** * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed */ public static boolean checkCallerHasLocationPermission(Context context, AppOpsManager appOps, String callingPackage) { if (context.checkCallingOrSelfPermission(android.Manifest.permission. ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } return context.checkCallingOrSelfPermission(android.Manifest.permission. ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_COARSE_LOCATION, callingPackage); } private static boolean isAppOppAllowed(AppOpsManager appOps, int op, String callingPackage) { return appOps.noteOp(op, Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED; } /** /** * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond. * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond. */ */ Loading
android/app/src/com/android/bluetooth/gatt/GattService.java +13 −5 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.bluetooth.gatt; package com.android.bluetooth.gatt; import android.app.AppOpsManager; import android.app.Service; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; Loading Loading @@ -148,6 +149,7 @@ public class GattService extends ProfileService { private AdvertiseManager mAdvertiseManager; private AdvertiseManager mAdvertiseManager; private ScanManager mScanManager; private ScanManager mScanManager; private AppOpsManager mAppOps; /** /** * Reliable write queue * Reliable write queue Loading @@ -169,6 +171,7 @@ public class GattService extends ProfileService { protected boolean start() { protected boolean start() { if (DBG) Log.d(TAG, "start()"); if (DBG) Log.d(TAG, "start()"); initializeNative(); initializeNative(); mAppOps = getSystemService(AppOpsManager.class); mAdvertiseManager = new AdvertiseManager(this, AdapterService.getAdapterService()); mAdvertiseManager = new AdvertiseManager(this, AdapterService.getAdapterService()); mAdvertiseManager.start(); mAdvertiseManager.start(); Loading Loading @@ -303,10 +306,10 @@ public class GattService extends ProfileService { @Override @Override public void startScan(int appIf, boolean isServer, ScanSettings settings, public void startScan(int appIf, boolean isServer, ScanSettings settings, List<ScanFilter> filters, List storages) { List<ScanFilter> filters, List storages, String callingPackage) { GattService service = getService(); GattService service = getService(); if (service == null) return; if (service == null) return; service.startScan(appIf, isServer, settings, filters, storages); service.startScan(appIf, isServer, settings, filters, storages, callingPackage); } } public void stopScan(int appIf, boolean isServer) { public void stopScan(int appIf, boolean isServer) { Loading Loading @@ -599,7 +602,7 @@ public class GattService extends ProfileService { .getRemoteDevice(address); .getRemoteDevice(address); ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(adv_data), rssi, SystemClock.elapsedRealtimeNanos()); rssi, SystemClock.elapsedRealtimeNanos()); if (matchesFilters(client, result)) { if (client.hasLocationPermission && matchesFilters(client, result)) { try { try { ScanSettings settings = client.settings; ScanSettings settings = client.settings; if ((settings.getCallbackType() & if ((settings.getCallbackType() & Loading Loading @@ -1350,13 +1353,18 @@ public class GattService extends ProfileService { } } void startScan(int appIf, boolean isServer, ScanSettings settings, void startScan(int appIf, boolean isServer, ScanSettings settings, List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages) { List<ScanFilter> filters, List<List<ResultStorageDescriptor>> storages, String callingPackage) { if (DBG) Log.d(TAG, "start scan with filters"); if (DBG) Log.d(TAG, "start scan with filters"); enforceAdminPermission(); enforceAdminPermission(); if (needsPrivilegedPermissionForScan(settings)) { if (needsPrivilegedPermissionForScan(settings)) { enforcePrivilegedPermission(); enforcePrivilegedPermission(); } } mScanManager.startScan(new ScanClient(appIf, isServer, settings, filters, storages)); boolean hasLocationPermission = Utils.checkCallerHasLocationPermission(this, mAppOps, callingPackage); final ScanClient scanClient = new ScanClient(appIf, isServer, settings, filters, storages); scanClient.hasLocationPermission = hasLocationPermission; mScanManager.startScan(scanClient); } } void flushPendingBatchResults(int clientIf, boolean isServer) { void flushPendingBatchResults(int clientIf, boolean isServer) { Loading
android/app/src/com/android/bluetooth/gatt/ScanClient.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ import java.util.UUID; List<List<ResultStorageDescriptor>> storages; List<List<ResultStorageDescriptor>> storages; // App associated with the scan client died. // App associated with the scan client died. boolean appDied; boolean appDied; boolean hasLocationPermission; private static final ScanSettings DEFAULT_SCAN_SETTINGS = new ScanSettings.Builder() private static final ScanSettings DEFAULT_SCAN_SETTINGS = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build(); Loading