Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtBluetoothUtility.java
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4package org.qtproject.qt.android.bluetooth;
5
6import android.Manifest;
7import android.os.Build;
8import android.content.Context;
9import android.content.pm.PackageInfo;
10import android.content.pm.PackageManager;
11import android.util.Log;
12
13class QtBluetoothUtility {
14
15 private static final String TAG = "QtBluetoothUtility";
16
17 // The check if bluetooth scanning requires location is somewhat computationally
18 // expensive and doesn't change at runtime, so we cache the result
19 private static boolean isScanRequiresLocationChecked = false;
20 private static boolean scanRequiresLocation = true;
21
22 // Returns whether or not Location + Location permission is required for Bluetooth scan
23 //
24 // API-level < 31: returns always true
25 //
26 // API-level >= 31: returns true if BLUETOOTH_SCAN doesn't have 'neverForLocation' set,
27 // or if the BLUETOOTH_SCAN permission is not present.
28 // Returns false if BLUETOOTH_SCAN has 'neverForLocation' set, or in case of any
29 // unexpected failure.
30 public static synchronized boolean bluetoothScanRequiresLocation(final Context qtContext)
31 {
32 Log.d(TAG, "Checking if Location is required for bluetooth scan");
33 if (isScanRequiresLocationChecked) {
34 Log.d(TAG, "Using cached result for scan needing location: " + scanRequiresLocation);
35 return scanRequiresLocation;
36 }
37
38 // API-levels below 31 always need location
39 if (Build.VERSION.SDK_INT < 31) {
40 Log.d(TAG, "SDK version is below 31, assuming Location needed");
41 scanRequiresLocation = true;
42 isScanRequiresLocationChecked = true;
43 return scanRequiresLocation;
44 }
45 if (qtContext == null) {
46 Log.w(TAG, "No context object provided");
47 return false;
48 }
49
50 try {
51 // API-levels 31+ require Location if there is no 'neverForLocation' assertion.
52 // Therefore check for BLUETOOTH_SCAN and its permission flags. Note that the
53 // permissions and their flags are indeed "parallel" arrays, i.e. permissions[i]
54 // corresponds with permissionsFlags[i]
55 PackageManager pm = qtContext.getPackageManager();
56 PackageInfo pi = pm.getPackageInfo(qtContext.getPackageName(),
57 PackageManager.GET_PERMISSIONS);
58 String[] permissions = pi.requestedPermissions;
59 int[] permissionsFlags = pi.requestedPermissionsFlags;
60
61 if (permissions != null && permissionsFlags != null) {
62 for (int i = 0; i < permissions.length; ++i) {
63 if (Manifest.permission.BLUETOOTH_SCAN.equals(permissions[i])) {
64 if ((permissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION) != 0) {
65 Log.d(TAG, "BLUETOOTH_SCAN with 'neverForLocation' found");
66 scanRequiresLocation = false;
67 } else {
68 Log.d(TAG, "BLUETOOTH_SCAN without 'neverForLocation' found");
69 scanRequiresLocation = true;
70 }
71 isScanRequiresLocationChecked = true;
72 return scanRequiresLocation;
73 }
74 }
75 }
76 } catch (Exception ex) {
77 Log.w(TAG, "An error occurred while checking Bluetooth's location need: " + ex);
78 scanRequiresLocation = false;
79 }
80 Log.d(TAG, "BLUETOOTH_SCAN permission not found");
81 isScanRequiresLocationChecked = true;
82 return scanRequiresLocation;
83 }
84}
QPainter Context