Skip to content

Commit 5e9e6dc

Browse files
committed
CATROID-1607 Fix bluetooth for Android API 31 onward
Bluetooth now works again across all devices. Depending on the device running the app either the new or the legacy bluetooth permissions are used. This is achieved by streamlining/simplifying the permission handling process for all features that require bluetooth permissions. And a little bit of boyscouting through the code.
1 parent 742862c commit 5e9e6dc

File tree

6 files changed

+81
-53
lines changed

6 files changed

+81
-53
lines changed

catroid/src/main/AndroidManifest.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@
5555
<uses-feature
5656
android:name="android.hardware.bluetooth"
5757
android:required="false" />
58-
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
59-
<uses-permission android:name="android.permission.BLUETOOTH" />
60-
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
58+
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
59+
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
60+
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
6161
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
6262
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
63+
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
6364
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"
6465
tools:ignore="ProtectedPermissions" />
6566

catroid/src/main/java/org/catrobat/catroid/content/Project.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Catroid: An on-device visual programming system for Android devices
3-
* Copyright (C) 2010-2022 The Catrobat Team
3+
* Copyright (C) 2010-2025 The Catrobat Team
44
* (<http://developer.catrobat.org/credits>)
55
*
66
* This program is free software: you can redistribute it and/or modify
@@ -165,7 +165,7 @@ public void removeScene(Scene scene) {
165165
}
166166

167167
public boolean hasScene() {
168-
return (sceneList.size() > 0);
168+
return !sceneList.isEmpty();
169169
}
170170

171171
public Scene getDefaultScene() {
@@ -337,7 +337,7 @@ public UserVariable getMultiplayerVariable(String name) {
337337
}
338338

339339
public boolean hasMultiplayerVariables() {
340-
return multiplayerVariables.size() > 0;
340+
return !multiplayerVariables.isEmpty();
341341
}
342342

343343
public boolean addMultiplayerVariable(UserVariable multiplayerVariable) {
@@ -422,6 +422,11 @@ public Brick.ResourcesSet getRequiredResources() {
422422
if (isCastProject()) {
423423
resourcesSet.add(Brick.CAST_REQUIRED);
424424
}
425+
426+
if (hasMultiplayerVariables()) {
427+
resourcesSet.add(Brick.BLUETOOTH_MULTIPLAYER);
428+
}
429+
425430
ActionFactory physicsActionFactory = new ActionPhysicsFactory();
426431
ActionFactory actionFactory = new ActionFactory();
427432

@@ -436,6 +441,7 @@ public Brick.ResourcesSet getRequiredResources() {
436441
}
437442
}
438443
}
444+
439445
return resourcesSet;
440446
}
441447

catroid/src/main/java/org/catrobat/catroid/content/bricks/Brick.java

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Catroid: An on-device visual programming system for Android devices
3-
* Copyright (C) 2010-2022 The Catrobat Team
3+
* Copyright (C) 2010-2025 The Catrobat Team
44
* (<http://developer.catrobat.org/credits>)
55
*
66
* This program is free software: you can redistribute it and/or modify
@@ -45,12 +45,13 @@ interface FormulaField extends Serializable {
4545
}
4646

4747
enum BrickField implements FormulaField {
48-
COLOR, COLOR_CHANGE, BRIGHTNESS, BRIGHTNESS_CHANGE, X_POSITION, Y_POSITION, X_POSITION_CHANGE, Y_POSITION_CHANGE,
49-
TRANSPARENCY, TRANSPARENCY_CHANGE, SIZE, SIZE_CHANGE, VOLUME, VOLUME_CHANGE, X_DESTINATION, Y_DESTINATION, STEPS,
50-
DURATION_IN_SECONDS, DEGREES, TURN_RIGHT_DEGREES, TURN_LEFT_DEGREES, TIME_TO_WAIT_IN_SECONDS, VARIABLE,
48+
COLOR, COLOR_CHANGE, BRIGHTNESS, BRIGHTNESS_CHANGE, X_POSITION, Y_POSITION,
49+
X_POSITION_CHANGE, Y_POSITION_CHANGE, TRANSPARENCY, TRANSPARENCY_CHANGE, SIZE, SIZE_CHANGE,
50+
VOLUME, VOLUME_CHANGE, X_DESTINATION, Y_DESTINATION, STEPS, DURATION_IN_SECONDS, DEGREES,
51+
TURN_RIGHT_DEGREES, TURN_LEFT_DEGREES, TIME_TO_WAIT_IN_SECONDS, VARIABLE,
5152

52-
VARIABLE_CHANGE, WEB_REQUEST, LOOK_REQUEST, LOOK_NEW, LOOK_COPY, BACKGROUND_REQUEST, WRITE_FILENAME,
53-
READ_FILENAME, TEMPO, HORIZONTAL_FLEXIBILITY, VERTICAL_FLEXIBILITY,
53+
VARIABLE_CHANGE, WEB_REQUEST, LOOK_REQUEST, LOOK_NEW, LOOK_COPY, BACKGROUND_REQUEST,
54+
WRITE_FILENAME, READ_FILENAME, TEMPO, HORIZONTAL_FLEXIBILITY, VERTICAL_FLEXIBILITY,
5455
TEMPO_CHANGE, BEATS_TO_PAUSE, NOTE_TO_PLAY, BEATS_TO_PLAY_NOTE, OPEN_URL, PLAY_DRUM,
5556
PLAY_SOUND_AT,
5657

@@ -66,19 +67,22 @@ enum BrickField implements FormulaField {
6667
LEGO_EV3_FREQUENCY, LEGO_EV3_DURATION_IN_SECONDS, LEGO_EV3_VOLUME,
6768
LEGO_EV3_SPEED, LEGO_EV3_POWER, LEGO_EV3_PERIOD_IN_SECONDS, LEGO_EV3_DEGREES,
6869

69-
DRONE_TIME_TO_FLY_IN_SECONDS, LIST_ADD_ITEM, LIST_DELETE_ITEM, INSERT_ITEM_INTO_USERLIST_VALUE,
70-
INSERT_ITEM_INTO_USERLIST_INDEX, REPLACE_ITEM_IN_USERLIST_VALUE, REPLACE_ITEM_IN_USERLIST_INDEX, DRONE_POWER_IN_PERCENT,
70+
DRONE_TIME_TO_FLY_IN_SECONDS, LIST_ADD_ITEM, LIST_DELETE_ITEM,
71+
INSERT_ITEM_INTO_USERLIST_VALUE, INSERT_ITEM_INTO_USERLIST_INDEX,
72+
REPLACE_ITEM_IN_USERLIST_VALUE, REPLACE_ITEM_IN_USERLIST_INDEX, DRONE_POWER_IN_PERCENT,
7173

7274
DRONE_ALTITUDE_LIMIT, DRONE_VERTICAL_SPEED_MAX, DRONE_ROTATION_MAX, DRONE_TILT_ANGLE,
7375

74-
JUMPING_SUMO_SPEED, JUMPING_SUMO_TIME_TO_DRIVE_IN_SECONDS, JUMPING_SUMO_VOLUME, JUMPING_SUMO_ROTATE,
76+
JUMPING_SUMO_SPEED, JUMPING_SUMO_TIME_TO_DRIVE_IN_SECONDS, JUMPING_SUMO_VOLUME,
77+
JUMPING_SUMO_ROTATE,
7578

7679
PHIRO_SPEED, PHIRO_DURATION_IN_SECONDS, PHIRO_LIGHT_RED, PHIRO_LIGHT_GREEN, PHIRO_LIGHT_BLUE,
7780

7881
PHYSICS_BOUNCE_FACTOR, PHYSICS_FRICTION, PHYSICS_GRAVITY_X, PHYSICS_GRAVITY_Y, PHYSICS_MASS,
7982
PHYSICS_VELOCITY_X, PHYSICS_VELOCITY_Y, PHYSICS_TURN_LEFT_SPEED, PHYSICS_TURN_RIGHT_SPEED,
8083

81-
ARDUINO_ANALOG_PIN_VALUE, ARDUINO_ANALOG_PIN_NUMBER, ARDUINO_DIGITAL_PIN_VALUE, ARDUINO_DIGITAL_PIN_NUMBER,
84+
ARDUINO_ANALOG_PIN_VALUE, ARDUINO_ANALOG_PIN_NUMBER, ARDUINO_DIGITAL_PIN_VALUE,
85+
ARDUINO_DIGITAL_PIN_NUMBER,
8286

8387
RASPI_DIGITAL_PIN_VALUE, RASPI_DIGITAL_PIN_NUMBER, RASPI_PWM_PERCENTAGE, RASPI_PWM_FREQUENCY,
8488

@@ -90,7 +94,8 @@ enum BrickField implements FormulaField {
9094

9195
ASSERT_LOOP_ACTUAL;
9296

93-
public static final BrickField[] EXPECTS_STRING_VALUE = {VARIABLE, NOTE, SPEAK, STRING, ASK_QUESTION,
97+
public static final BrickField[] EXPECTS_STRING_VALUE = {
98+
VARIABLE, NOTE, SPEAK, STRING, ASK_QUESTION,
9499
NFC_NDEF_MESSAGE, ASK_SPEECH_QUESTION, LIST_ADD_ITEM, INSERT_ITEM_INTO_USERLIST_VALUE,
95100
REPLACE_ITEM_IN_USERLIST_VALUE};
96101

@@ -123,10 +128,11 @@ public static boolean isUserList(BrickData field) {
123128

124129
@Retention(RetentionPolicy.SOURCE)
125130
@IntDef({TEXT_TO_SPEECH, BLUETOOTH_LEGO_NXT, PHYSICS, FACE_DETECTION,
126-
BLUETOOTH_SENSORS_ARDUINO, SOCKET_RASPI, CAMERA_FLASH, VIBRATION, BLUETOOTH_PHIRO, CAMERA_BACK, CAMERA_FRONT,
127-
SENSOR_ACCELERATION, SENSOR_INCLINATION, SENSOR_COMPASS, NFC_ADAPTER, VIDEO, SENSOR_GPS, COLLISION,
128-
BLUETOOTH_LEGO_EV3, NETWORK_CONNECTION, CAST_REQUIRED, MICROPHONE, STORAGE_WRITE, STORAGE_READ,
129-
SPEECH_RECOGNITION, TEXT_DETECTION, POSE_DETECTION, OBJECT_DETECTION})
131+
BLUETOOTH_SENSORS_ARDUINO, SOCKET_RASPI, CAMERA_FLASH, VIBRATION, BLUETOOTH_PHIRO,
132+
CAMERA_BACK, CAMERA_FRONT, SENSOR_ACCELERATION, SENSOR_INCLINATION, SENSOR_COMPASS,
133+
NFC_ADAPTER, VIDEO, SENSOR_GPS, COLLISION, BLUETOOTH_LEGO_EV3, NETWORK_CONNECTION,
134+
CAST_REQUIRED, MICROPHONE, STORAGE_WRITE, STORAGE_READ, SPEECH_RECOGNITION,
135+
TEXT_DETECTION, POSE_DETECTION, OBJECT_DETECTION, BLUETOOTH_MULTIPLAYER})
130136
@interface Resources {
131137
}
132138

@@ -158,6 +164,7 @@ public static boolean isUserList(BrickData field) {
158164
int STORAGE_WRITE = 26;
159165
int POSE_DETECTION = 27;
160166
int OBJECT_DETECTION = 28;
167+
int BLUETOOTH_MULTIPLAYER = 29;
161168

162169
class ResourcesSet extends HashSet<Integer> {
163170
@Override

catroid/src/main/java/org/catrobat/catroid/stage/StageLifeCycleController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Catroid: An on-device visual programming system for Android devices
3-
* Copyright (C) 2010-2022 The Catrobat Team
3+
* Copyright (C) 2010-2025 The Catrobat Team
44
* (<http://developer.catrobat.org/credits>)
55
*
66
* This program is free software: you can redistribute it and/or modify
@@ -184,7 +184,7 @@ public static void stageResume(final StageActivity stageActivity) {
184184
SensorHandler.startSensorListener(stageActivity);
185185

186186
for (Sprite sprite : spriteList) {
187-
if (sprite.getPlaySoundBricks().size() > 0) {
187+
if (!sprite.getPlaySoundBricks().isEmpty()) {
188188
stageActivity.stageAudioFocus.requestAudioFocus();
189189
break;
190190
}
@@ -203,9 +203,10 @@ public static void stageResume(final StageActivity stageActivity) {
203203
}
204204

205205
if (resourcesSet.contains(Brick.BLUETOOTH_LEGO_NXT)
206+
|| resourcesSet.contains(Brick.BLUETOOTH_LEGO_EV3)
206207
|| resourcesSet.contains(Brick.BLUETOOTH_PHIRO)
207208
|| resourcesSet.contains(Brick.BLUETOOTH_SENSORS_ARDUINO)
208-
|| ProjectManager.getInstance().getCurrentProject().hasMultiplayerVariables()) {
209+
|| resourcesSet.contains(Brick.BLUETOOTH_MULTIPLAYER)) {
209210
try {
210211
ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE).start();
211212
} catch (MindstormsException e) {

catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Catroid: An on-device visual programming system for Android devices
3-
* Copyright (C) 2010-2022 The Catrobat Team
3+
* Copyright (C) 2010-2025 The Catrobat Team
44
* (<http://developer.catrobat.org/credits>)
55
*
66
* This program is free software: you can redistribute it and/or modify
@@ -23,7 +23,6 @@
2323

2424
package org.catrobat.catroid.stage;
2525

26-
import android.annotation.SuppressLint;
2726
import android.app.AlertDialog;
2827
import android.app.PendingIntent;
2928
import android.content.Context;
@@ -85,8 +84,9 @@ public class StageResourceHolder implements GatherCollisionInformationTask.OnPol
8584
private int requiredResourceCounter;
8685
private Set<Integer> failedResources;
8786

88-
private StageActivity stageActivity;
89-
private final SpeechRecognitionHolderFactory speechRecognitionHolderFactory = get(SpeechRecognitionHolderFactory.class);
87+
private final StageActivity stageActivity;
88+
private final SpeechRecognitionHolderFactory speechRecognitionHolderFactory =
89+
get(SpeechRecognitionHolderFactory.class);
9090

9191
StageResourceHolder(final StageActivity stageActivity) {
9292
this.stageActivity = stageActivity;
@@ -170,8 +170,7 @@ public void initResources() {
170170
connectBTDevice(BluetoothDevice.ARDUINO);
171171
}
172172

173-
if (ProjectManager.getInstance().getCurrentProject().hasMultiplayerVariables()) {
174-
requiredResourceCounter++;
173+
if (requiredResourcesSet.contains(Brick.BLUETOOTH_MULTIPLAYER)) {
175174
connectBTDevice(BluetoothDevice.MULTIPLAYER);
176175
}
177176

@@ -510,10 +509,11 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
510509
}
511510
}
512511

513-
private void connectBTDevice(Class<? extends BluetoothDevice> service) {
514-
BluetoothDeviceService btService = ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE);
512+
private void connectBTDevice(Class<? extends BluetoothDevice> deviceType) {
513+
BluetoothDeviceService btService =
514+
ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE);
515515

516-
if (btService.connectDevice(service, stageActivity, REQUEST_CONNECT_DEVICE)
516+
if (btService.connectDevice(deviceType, stageActivity, REQUEST_CONNECT_DEVICE)
517517
== BluetoothDeviceService.ConnectDeviceResult.ALREADY_CONNECTED) {
518518
resourceInitialized();
519519
}
@@ -526,7 +526,9 @@ private void connectRaspberrySocket() {
526526
if (RaspberryPiService.getInstance().connect(host, port)) {
527527
resourceInitialized();
528528
} else {
529-
ToastUtil.showError(stageActivity, stageActivity.getString(R.string.error_connecting_to, host, port));
529+
ToastUtil.showError(
530+
stageActivity,
531+
stageActivity.getString(R.string.error_connecting_to, host, port));
530532
endStageActivity();
531533
}
532534
}
@@ -544,7 +546,8 @@ private void nfcInitialize() {
544546
resourceInitialized();
545547
}
546548

547-
// for GatherCollisionInformationTask.OnPolygonLoadedListener, this is NOT any Activity or Lifecycle event
549+
// for GatherCollisionInformationTask.OnPolygonLoadedListener,
550+
// this is NOT any Activity or Lifecycle event
548551
@Override
549552
public void onFinished() {
550553
resourceInitialized();

catroid/src/main/java/org/catrobat/catroid/ui/runtimepermissions/BrickResourcesToRuntimePermissions.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Catroid: An on-device visual programming system for Android devices
3-
* Copyright (C) 2010-2022 The Catrobat Team
3+
* Copyright (C) 2010-2025 The Catrobat Team
44
* (<http://developer.catrobat.org/credits>)
55
*
66
* This program is free software: you can redistribute it and/or modify
@@ -24,12 +24,12 @@
2424
package org.catrobat.catroid.ui.runtimepermissions;
2525

2626
import android.annotation.SuppressLint;
27+
import android.os.Build;
2728

2829
import org.catrobat.catroid.content.bricks.Brick;
2930

3031
import java.util.ArrayList;
3132
import java.util.Arrays;
32-
import java.util.Collections;
3333
import java.util.HashMap;
3434
import java.util.HashSet;
3535
import java.util.List;
@@ -41,6 +41,9 @@
4141
import static android.Manifest.permission.ACCESS_WIFI_STATE;
4242
import static android.Manifest.permission.BLUETOOTH;
4343
import static android.Manifest.permission.BLUETOOTH_ADMIN;
44+
import static android.Manifest.permission.BLUETOOTH_ADVERTISE;
45+
import static android.Manifest.permission.BLUETOOTH_CONNECT;
46+
import static android.Manifest.permission.BLUETOOTH_SCAN;
4447
import static android.Manifest.permission.CAMERA;
4548
import static android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE;
4649
import static android.Manifest.permission.CHANGE_WIFI_STATE;
@@ -58,27 +61,34 @@ private BrickResourcesToRuntimePermissions() {
5861
@SuppressLint("UseSparseArrays")
5962
public static List<String> translate(Brick.ResourcesSet brickResources) {
6063
Map<Integer, List<String>> brickResourcesToPermissions = new HashMap<>();
61-
brickResourcesToPermissions.put(Brick.SENSOR_GPS, Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION));
62-
List<String> bluetoothPermissions = Arrays.asList(BLUETOOTH_ADMIN, BLUETOOTH);
64+
brickResourcesToPermissions.put(
65+
Brick.SENSOR_GPS, Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION));
66+
67+
List<String> bluetoothPermissions = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
68+
? Arrays.asList(BLUETOOTH_ADVERTISE, BLUETOOTH_SCAN, BLUETOOTH_CONNECT)
69+
: Arrays.asList(BLUETOOTH_ADMIN, BLUETOOTH);
6370
brickResourcesToPermissions.put(Brick.BLUETOOTH_LEGO_NXT, bluetoothPermissions);
6471
brickResourcesToPermissions.put(Brick.BLUETOOTH_LEGO_EV3, bluetoothPermissions);
6572
brickResourcesToPermissions.put(Brick.BLUETOOTH_PHIRO, bluetoothPermissions);
6673
brickResourcesToPermissions.put(Brick.BLUETOOTH_SENSORS_ARDUINO, bluetoothPermissions);
67-
List<String> wifiPermissions = Arrays.asList(CHANGE_WIFI_MULTICAST_STATE, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE);
74+
brickResourcesToPermissions.put(Brick.BLUETOOTH_MULTIPLAYER, bluetoothPermissions);
75+
76+
List<String> wifiPermissions = Arrays.asList(
77+
CHANGE_WIFI_MULTICAST_STATE, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE);
6878
brickResourcesToPermissions.put(Brick.CAST_REQUIRED, wifiPermissions);
69-
brickResourcesToPermissions.put(Brick.CAMERA_BACK, Arrays.asList(CAMERA));
70-
brickResourcesToPermissions.put(Brick.CAMERA_FRONT, Arrays.asList(CAMERA));
71-
brickResourcesToPermissions.put(Brick.VIDEO, Arrays.asList(CAMERA));
72-
brickResourcesToPermissions.put(Brick.CAMERA_FLASH, Arrays.asList(CAMERA));
73-
brickResourcesToPermissions.put(Brick.VIBRATION, Arrays.asList(VIBRATE));
74-
brickResourcesToPermissions.put(Brick.NFC_ADAPTER, Arrays.asList(NFC));
75-
brickResourcesToPermissions.put(Brick.FACE_DETECTION, Collections.singletonList(CAMERA));
76-
brickResourcesToPermissions.put(Brick.OBJECT_DETECTION, Collections.singletonList(CAMERA));
77-
brickResourcesToPermissions.put(Brick.POSE_DETECTION, Collections.singletonList(CAMERA));
78-
brickResourcesToPermissions.put(Brick.TEXT_DETECTION, Collections.singletonList(CAMERA));
79-
brickResourcesToPermissions.put(Brick.MICROPHONE, Arrays.asList(RECORD_AUDIO));
80-
brickResourcesToPermissions.put(Brick.STORAGE_READ, Arrays.asList(READ_EXTERNAL_STORAGE));
81-
brickResourcesToPermissions.put(Brick.STORAGE_WRITE, Arrays.asList(WRITE_EXTERNAL_STORAGE));
79+
brickResourcesToPermissions.put(Brick.CAMERA_BACK, List.of(CAMERA));
80+
brickResourcesToPermissions.put(Brick.CAMERA_FRONT, List.of(CAMERA));
81+
brickResourcesToPermissions.put(Brick.VIDEO, List.of(CAMERA));
82+
brickResourcesToPermissions.put(Brick.CAMERA_FLASH, List.of(CAMERA));
83+
brickResourcesToPermissions.put(Brick.VIBRATION, List.of(VIBRATE));
84+
brickResourcesToPermissions.put(Brick.NFC_ADAPTER, List.of(NFC));
85+
brickResourcesToPermissions.put(Brick.FACE_DETECTION, List.of(CAMERA));
86+
brickResourcesToPermissions.put(Brick.OBJECT_DETECTION, List.of(CAMERA));
87+
brickResourcesToPermissions.put(Brick.POSE_DETECTION, List.of(CAMERA));
88+
brickResourcesToPermissions.put(Brick.TEXT_DETECTION, List.of(CAMERA));
89+
brickResourcesToPermissions.put(Brick.MICROPHONE, List.of(RECORD_AUDIO));
90+
brickResourcesToPermissions.put(Brick.STORAGE_READ, List.of(READ_EXTERNAL_STORAGE));
91+
brickResourcesToPermissions.put(Brick.STORAGE_WRITE, List.of(WRITE_EXTERNAL_STORAGE));
8292

8393
Set<String> requiredPermissions = new HashSet<>();
8494
for (int brickResource : brickResources) {

0 commit comments

Comments
 (0)