mirror of
https://github.com/nextcloud/talk-android
synced 2025-03-06 14:27:24 +00:00
Add Android build switch for checking bluetooth permissions
Refactored method 'hasPermission' to 'hasNoBluetoothPermission'. The new method respect the in SKD 31 introduced permission BLUETOOTH_CONNECT. For older SDK versions the permission BLUETOOTH will be used. Additionaly make methods private which need bluetooth permissions and only called locally. For public methods which need bluetooth permissions the method 'hasNoBluetoothPermission' is called to check them. Also add suppress lint annotation for 'MissingPermission'. From SDK 30 to SDK 31 the bluetooth related permissions changed and it is suggested to add the attribute 'android:maxSdkVersion="30"' to the legacy BLUETOOTH permission in the 'AndroidManifest.xml' [1]: > For your legacy Bluetooth-related permission declarations, set > android:maxSdkVersion to 30. This app compatibility step helps the system > grant your app only the Bluetooth permissions that it needs when installed > on devices that run Android 12 or higher. This is explicitly not done here! During runtime (on Android 12) while starting the 'MagicBluetoothManger' the following part in 'android.bluetooth.BluetootHeadset' constructor will be executed and results in the previous exception: // Preserve legacy compatibility where apps were depending on // registerStateChangeCallback() performing a permissions check which // has been relaxed in modern platform versions if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Need BLUETOOTH permission"); } In the 'build.gradle' the 'targetSdkVersion 30' and 'compileSdkVersion 31' is configured. Because the 'MagicBluetoothManager' checks for the 'targetSdkVersion' instead of 'Build.VERSION.SDK_INT' also on a Android 12 (SDK 31) the 'BLUETOOTH' permission is needed. So the solution is to don't set `android:maxSdkVersion="30"' for the BLUETOOTH permission and request the BLUETOOTH_CONNECT permission. Resolves: #2132 See: [1] https://web.archive.org/web/20220416121005/https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#declare-android12-or-higher Signed-off-by: Tim Krüger <t@timkrueger.me>
This commit is contained in:
parent
45c33de776
commit
4821b02729
@ -31,6 +31,7 @@
|
||||
|
||||
package com.nextcloud.talk.webrtc;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
@ -47,11 +48,14 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import org.webrtc.ThreadUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
public class MagicBluetoothManager {
|
||||
private static final String TAG = "MagicBluetoothManager";
|
||||
|
||||
@ -73,12 +77,7 @@ public class MagicBluetoothManager {
|
||||
// Runs when the Bluetooth timeout expires. We use that timeout after calling
|
||||
// startScoAudio() or stopScoAudio() because we're not guaranteed to get a
|
||||
// callback after those calls.
|
||||
private final Runnable bluetoothTimeoutRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
bluetoothTimeout();
|
||||
}
|
||||
};
|
||||
private final Runnable bluetoothTimeoutRunnable = this::bluetoothTimeout;
|
||||
|
||||
protected MagicBluetoothManager(Context context, MagicAudioManager audioManager) {
|
||||
Log.d(TAG, "ctor");
|
||||
@ -122,11 +121,11 @@ public class MagicBluetoothManager {
|
||||
* Note that the MagicAudioManager is also involved in driving this state
|
||||
* change.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
public void start() {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
Log.d(TAG, "start");
|
||||
if (!hasPermission(apprtcContext, android.Manifest.permission.BLUETOOTH)) {
|
||||
Log.w(TAG, "Process (pid=" + Process.myPid() + ") lacks BLUETOOTH permission");
|
||||
if(hasNoBluetoothPermission()){
|
||||
return;
|
||||
}
|
||||
if (bluetoothState != State.UNINITIALIZED) {
|
||||
@ -262,8 +261,12 @@ public class MagicBluetoothManager {
|
||||
* HEADSET_AVAILABLE and |bluetoothDevice| will be mapped to the connected
|
||||
* device if available.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
public void updateDevice() {
|
||||
if (bluetoothState == State.UNINITIALIZED || bluetoothHeadset == null) {
|
||||
boolean hasNoBluetoothPermissions = hasNoBluetoothPermission();
|
||||
if (hasNoBluetoothPermissions ||
|
||||
bluetoothState == State.UNINITIALIZED ||
|
||||
bluetoothHeadset == null) {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "updateDevice");
|
||||
@ -307,16 +310,28 @@ public class MagicBluetoothManager {
|
||||
return bluetoothAdapter.getProfileProxy(context, listener, profile);
|
||||
}
|
||||
|
||||
protected boolean hasPermission(Context context, String permission) {
|
||||
return apprtcContext.checkPermission(permission, Process.myPid(), Process.myUid())
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
private boolean hasNoBluetoothPermission() {
|
||||
String permission;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
permission = Manifest.permission.BLUETOOTH_CONNECT;
|
||||
} else {
|
||||
permission = Manifest.permission.BLUETOOTH;
|
||||
}
|
||||
|
||||
boolean hasPermission =
|
||||
ActivityCompat.checkSelfPermission(apprtcContext, permission) == PackageManager.PERMISSION_GRANTED;
|
||||
if(!hasPermission) {
|
||||
Log.w(TAG, "Process (pid=" + Process.myPid() + ") lacks \"" + permission + "\" permission");
|
||||
}
|
||||
return !hasPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the state of the local Bluetooth adapter.
|
||||
*/
|
||||
@SuppressLint("HardwareIds")
|
||||
protected void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
|
||||
@SuppressLint({"HardwareIds", "MissingPermission"})
|
||||
private void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
|
||||
Log.d(TAG, "BluetoothAdapter: "
|
||||
+ "enabled=" + localAdapter.isEnabled() + ", "
|
||||
+ "state=" + stateToString(localAdapter.getState()) + ", "
|
||||
@ -362,9 +377,13 @@ public class MagicBluetoothManager {
|
||||
* Called when start of the BT SCO channel takes too long time. Usually
|
||||
* happens when the BT device has been turned on during an ongoing call.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
private void bluetoothTimeout() {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
if (bluetoothState == State.UNINITIALIZED || bluetoothHeadset == null) {
|
||||
boolean hasNoBluetoothPermissions = hasNoBluetoothPermission();
|
||||
if (hasNoBluetoothPermissions ||
|
||||
bluetoothState == State.UNINITIALIZED ||
|
||||
bluetoothHeadset == null) {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "bluetoothTimeout: BT state=" + bluetoothState + ", "
|
||||
|
Loading…
Reference in New Issue
Block a user