diff --git a/catroid/build.gradle b/catroid/build.gradle
index 1a455ca26e8..8dd46aa5bc2 100644
--- a/catroid/build.gradle
+++ b/catroid/build.gradle
@@ -55,7 +55,7 @@ ext {
espressoVersion = "3.1.0"
playServicesVersion = '17.0.1'
cameraXVersion = "1.0.0-beta07"
- room_version = "2.3.0"
+ room_version = "2.4.3"
coroutines_version = "1.3.2"
work_manager_version = '2.7.1'
}
diff --git a/catroid/src/main/AndroidManifest.xml b/catroid/src/main/AndroidManifest.xml
index 61f06800d87..9e71d3a1636 100644
--- a/catroid/src/main/AndroidManifest.xml
+++ b/catroid/src/main/AndroidManifest.xml
@@ -55,11 +55,12 @@
-
-
-
+
+
+
+
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/Project.java b/catroid/src/main/java/org/catrobat/catroid/content/Project.java
index 2cc4817fb50..9aebd986364 100644
--- a/catroid/src/main/java/org/catrobat/catroid/content/Project.java
+++ b/catroid/src/main/java/org/catrobat/catroid/content/Project.java
@@ -165,7 +165,7 @@ public void removeScene(Scene scene) {
}
public boolean hasScene() {
- return (sceneList.size() > 0);
+ return !sceneList.isEmpty();
}
public Scene getDefaultScene() {
@@ -337,7 +337,7 @@ public UserVariable getMultiplayerVariable(String name) {
}
public boolean hasMultiplayerVariables() {
- return multiplayerVariables.size() > 0;
+ return !multiplayerVariables.isEmpty();
}
public boolean addMultiplayerVariable(UserVariable multiplayerVariable) {
@@ -422,6 +422,11 @@ public Brick.ResourcesSet getRequiredResources() {
if (isCastProject()) {
resourcesSet.add(Brick.CAST_REQUIRED);
}
+
+ if (hasMultiplayerVariables()) {
+ resourcesSet.add(Brick.BLUETOOTH_MULTIPLAYER);
+ }
+
ActionFactory physicsActionFactory = new ActionPhysicsFactory();
ActionFactory actionFactory = new ActionFactory();
@@ -436,6 +441,7 @@ public Brick.ResourcesSet getRequiredResources() {
}
}
}
+
return resourcesSet;
}
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/bricks/Brick.java b/catroid/src/main/java/org/catrobat/catroid/content/bricks/Brick.java
index 3287060acf1..5aa272896cc 100644
--- a/catroid/src/main/java/org/catrobat/catroid/content/bricks/Brick.java
+++ b/catroid/src/main/java/org/catrobat/catroid/content/bricks/Brick.java
@@ -45,12 +45,13 @@ interface FormulaField extends Serializable {
}
enum BrickField implements FormulaField {
- COLOR, COLOR_CHANGE, BRIGHTNESS, BRIGHTNESS_CHANGE, X_POSITION, Y_POSITION, X_POSITION_CHANGE, Y_POSITION_CHANGE,
- TRANSPARENCY, TRANSPARENCY_CHANGE, SIZE, SIZE_CHANGE, VOLUME, VOLUME_CHANGE, X_DESTINATION, Y_DESTINATION, STEPS,
- DURATION_IN_SECONDS, DEGREES, TURN_RIGHT_DEGREES, TURN_LEFT_DEGREES, TIME_TO_WAIT_IN_SECONDS, VARIABLE,
+ COLOR, COLOR_CHANGE, BRIGHTNESS, BRIGHTNESS_CHANGE, X_POSITION, Y_POSITION,
+ X_POSITION_CHANGE, Y_POSITION_CHANGE, TRANSPARENCY, TRANSPARENCY_CHANGE, SIZE, SIZE_CHANGE,
+ VOLUME, VOLUME_CHANGE, X_DESTINATION, Y_DESTINATION, STEPS, DURATION_IN_SECONDS, DEGREES,
+ TURN_RIGHT_DEGREES, TURN_LEFT_DEGREES, TIME_TO_WAIT_IN_SECONDS, VARIABLE,
- VARIABLE_CHANGE, WEB_REQUEST, LOOK_REQUEST, LOOK_NEW, LOOK_COPY, BACKGROUND_REQUEST, WRITE_FILENAME,
- READ_FILENAME, TEMPO, HORIZONTAL_FLEXIBILITY, VERTICAL_FLEXIBILITY,
+ VARIABLE_CHANGE, WEB_REQUEST, LOOK_REQUEST, LOOK_NEW, LOOK_COPY, BACKGROUND_REQUEST,
+ WRITE_FILENAME, READ_FILENAME, TEMPO, HORIZONTAL_FLEXIBILITY, VERTICAL_FLEXIBILITY,
TEMPO_CHANGE, BEATS_TO_PAUSE, NOTE_TO_PLAY, BEATS_TO_PLAY_NOTE, OPEN_URL, PLAY_DRUM,
PLAY_SOUND_AT,
@@ -66,19 +67,22 @@ enum BrickField implements FormulaField {
LEGO_EV3_FREQUENCY, LEGO_EV3_DURATION_IN_SECONDS, LEGO_EV3_VOLUME,
LEGO_EV3_SPEED, LEGO_EV3_POWER, LEGO_EV3_PERIOD_IN_SECONDS, LEGO_EV3_DEGREES,
- DRONE_TIME_TO_FLY_IN_SECONDS, LIST_ADD_ITEM, LIST_DELETE_ITEM, INSERT_ITEM_INTO_USERLIST_VALUE,
- INSERT_ITEM_INTO_USERLIST_INDEX, REPLACE_ITEM_IN_USERLIST_VALUE, REPLACE_ITEM_IN_USERLIST_INDEX, DRONE_POWER_IN_PERCENT,
+ DRONE_TIME_TO_FLY_IN_SECONDS, LIST_ADD_ITEM, LIST_DELETE_ITEM,
+ INSERT_ITEM_INTO_USERLIST_VALUE, INSERT_ITEM_INTO_USERLIST_INDEX,
+ REPLACE_ITEM_IN_USERLIST_VALUE, REPLACE_ITEM_IN_USERLIST_INDEX, DRONE_POWER_IN_PERCENT,
DRONE_ALTITUDE_LIMIT, DRONE_VERTICAL_SPEED_MAX, DRONE_ROTATION_MAX, DRONE_TILT_ANGLE,
- JUMPING_SUMO_SPEED, JUMPING_SUMO_TIME_TO_DRIVE_IN_SECONDS, JUMPING_SUMO_VOLUME, JUMPING_SUMO_ROTATE,
+ JUMPING_SUMO_SPEED, JUMPING_SUMO_TIME_TO_DRIVE_IN_SECONDS, JUMPING_SUMO_VOLUME,
+ JUMPING_SUMO_ROTATE,
PHIRO_SPEED, PHIRO_DURATION_IN_SECONDS, PHIRO_LIGHT_RED, PHIRO_LIGHT_GREEN, PHIRO_LIGHT_BLUE,
PHYSICS_BOUNCE_FACTOR, PHYSICS_FRICTION, PHYSICS_GRAVITY_X, PHYSICS_GRAVITY_Y, PHYSICS_MASS,
PHYSICS_VELOCITY_X, PHYSICS_VELOCITY_Y, PHYSICS_TURN_LEFT_SPEED, PHYSICS_TURN_RIGHT_SPEED,
- ARDUINO_ANALOG_PIN_VALUE, ARDUINO_ANALOG_PIN_NUMBER, ARDUINO_DIGITAL_PIN_VALUE, ARDUINO_DIGITAL_PIN_NUMBER,
+ ARDUINO_ANALOG_PIN_VALUE, ARDUINO_ANALOG_PIN_NUMBER, ARDUINO_DIGITAL_PIN_VALUE,
+ ARDUINO_DIGITAL_PIN_NUMBER,
RASPI_DIGITAL_PIN_VALUE, RASPI_DIGITAL_PIN_NUMBER, RASPI_PWM_PERCENTAGE, RASPI_PWM_FREQUENCY,
@@ -90,7 +94,8 @@ enum BrickField implements FormulaField {
ASSERT_LOOP_ACTUAL;
- public static final BrickField[] EXPECTS_STRING_VALUE = {VARIABLE, NOTE, SPEAK, STRING, ASK_QUESTION,
+ private static final BrickField[] EXPECTS_STRING_VALUE = {
+ VARIABLE, NOTE, SPEAK, STRING, ASK_QUESTION,
NFC_NDEF_MESSAGE, ASK_SPEECH_QUESTION, LIST_ADD_ITEM, INSERT_ITEM_INTO_USERLIST_VALUE,
REPLACE_ITEM_IN_USERLIST_VALUE};
@@ -123,10 +128,11 @@ public static boolean isUserList(BrickData field) {
@Retention(RetentionPolicy.SOURCE)
@IntDef({TEXT_TO_SPEECH, BLUETOOTH_LEGO_NXT, PHYSICS, FACE_DETECTION,
- BLUETOOTH_SENSORS_ARDUINO, SOCKET_RASPI, CAMERA_FLASH, VIBRATION, BLUETOOTH_PHIRO, CAMERA_BACK, CAMERA_FRONT,
- SENSOR_ACCELERATION, SENSOR_INCLINATION, SENSOR_COMPASS, NFC_ADAPTER, VIDEO, SENSOR_GPS, COLLISION,
- BLUETOOTH_LEGO_EV3, NETWORK_CONNECTION, CAST_REQUIRED, MICROPHONE, STORAGE_WRITE, STORAGE_READ,
- SPEECH_RECOGNITION, TEXT_DETECTION, POSE_DETECTION, OBJECT_DETECTION})
+ BLUETOOTH_SENSORS_ARDUINO, SOCKET_RASPI, CAMERA_FLASH, VIBRATION, BLUETOOTH_PHIRO,
+ CAMERA_BACK, CAMERA_FRONT, SENSOR_ACCELERATION, SENSOR_INCLINATION, SENSOR_COMPASS,
+ NFC_ADAPTER, VIDEO, SENSOR_GPS, COLLISION, BLUETOOTH_LEGO_EV3, NETWORK_CONNECTION,
+ CAST_REQUIRED, MICROPHONE, STORAGE_WRITE, STORAGE_READ, SPEECH_RECOGNITION,
+ TEXT_DETECTION, POSE_DETECTION, OBJECT_DETECTION, BLUETOOTH_MULTIPLAYER})
@interface Resources {
}
@@ -158,6 +164,7 @@ public static boolean isUserList(BrickData field) {
int STORAGE_WRITE = 26;
int POSE_DETECTION = 27;
int OBJECT_DETECTION = 28;
+ int BLUETOOTH_MULTIPLAYER = 29;
class ResourcesSet extends HashSet {
@Override
diff --git a/catroid/src/main/java/org/catrobat/catroid/stage/StageLifeCycleController.java b/catroid/src/main/java/org/catrobat/catroid/stage/StageLifeCycleController.java
index 5e9958361ff..019527769bf 100644
--- a/catroid/src/main/java/org/catrobat/catroid/stage/StageLifeCycleController.java
+++ b/catroid/src/main/java/org/catrobat/catroid/stage/StageLifeCycleController.java
@@ -184,7 +184,7 @@ public static void stageResume(final StageActivity stageActivity) {
SensorHandler.startSensorListener(stageActivity);
for (Sprite sprite : spriteList) {
- if (sprite.getPlaySoundBricks().size() > 0) {
+ if (!sprite.getPlaySoundBricks().isEmpty()) {
stageActivity.stageAudioFocus.requestAudioFocus();
break;
}
@@ -203,9 +203,10 @@ public static void stageResume(final StageActivity stageActivity) {
}
if (resourcesSet.contains(Brick.BLUETOOTH_LEGO_NXT)
+ || resourcesSet.contains(Brick.BLUETOOTH_LEGO_EV3)
|| resourcesSet.contains(Brick.BLUETOOTH_PHIRO)
|| resourcesSet.contains(Brick.BLUETOOTH_SENSORS_ARDUINO)
- || ProjectManager.getInstance().getCurrentProject().hasMultiplayerVariables()) {
+ || resourcesSet.contains(Brick.BLUETOOTH_MULTIPLAYER)) {
try {
ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE).start();
} catch (MindstormsException e) {
diff --git a/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java b/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java
index 5d1dc8d12fa..7162e3bde73 100644
--- a/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java
+++ b/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java
@@ -23,7 +23,6 @@
package org.catrobat.catroid.stage;
-import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
@@ -85,8 +84,9 @@ public class StageResourceHolder implements GatherCollisionInformationTask.OnPol
private int requiredResourceCounter;
private Set failedResources;
- private StageActivity stageActivity;
- private final SpeechRecognitionHolderFactory speechRecognitionHolderFactory = get(SpeechRecognitionHolderFactory.class);
+ private final StageActivity stageActivity;
+ private final SpeechRecognitionHolderFactory speechRecognitionHolderFactory =
+ get(SpeechRecognitionHolderFactory.class);
StageResourceHolder(final StageActivity stageActivity) {
this.stageActivity = stageActivity;
@@ -170,8 +170,7 @@ public void initResources() {
connectBTDevice(BluetoothDevice.ARDUINO);
}
- if (ProjectManager.getInstance().getCurrentProject().hasMultiplayerVariables()) {
- requiredResourceCounter++;
+ if (requiredResourcesSet.contains(Brick.BLUETOOTH_MULTIPLAYER)) {
connectBTDevice(BluetoothDevice.MULTIPLAYER);
}
@@ -510,10 +509,11 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}
- private void connectBTDevice(Class extends BluetoothDevice> service) {
- BluetoothDeviceService btService = ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE);
+ private void connectBTDevice(Class extends BluetoothDevice> deviceType) {
+ BluetoothDeviceService btService =
+ ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE);
- if (btService.connectDevice(service, stageActivity, REQUEST_CONNECT_DEVICE)
+ if (btService.connectDevice(deviceType, stageActivity, REQUEST_CONNECT_DEVICE)
== BluetoothDeviceService.ConnectDeviceResult.ALREADY_CONNECTED) {
resourceInitialized();
}
@@ -526,7 +526,9 @@ private void connectRaspberrySocket() {
if (RaspberryPiService.getInstance().connect(host, port)) {
resourceInitialized();
} else {
- ToastUtil.showError(stageActivity, stageActivity.getString(R.string.error_connecting_to, host, port));
+ ToastUtil.showError(
+ stageActivity,
+ stageActivity.getString(R.string.error_connecting_to, host, port));
endStageActivity();
}
}
@@ -544,7 +546,8 @@ private void nfcInitialize() {
resourceInitialized();
}
- // for GatherCollisionInformationTask.OnPolygonLoadedListener, this is NOT any Activity or Lifecycle event
+ // for GatherCollisionInformationTask.OnPolygonLoadedListener,
+ // this is NOT any Activity or Lifecycle event
@Override
public void onFinished() {
resourceInitialized();
diff --git a/catroid/src/main/java/org/catrobat/catroid/ui/runtimepermissions/BrickResourcesToRuntimePermissions.java b/catroid/src/main/java/org/catrobat/catroid/ui/runtimepermissions/BrickResourcesToRuntimePermissions.java
index 744f0c12434..52b54f018fd 100644
--- a/catroid/src/main/java/org/catrobat/catroid/ui/runtimepermissions/BrickResourcesToRuntimePermissions.java
+++ b/catroid/src/main/java/org/catrobat/catroid/ui/runtimepermissions/BrickResourcesToRuntimePermissions.java
@@ -24,12 +24,12 @@
package org.catrobat.catroid.ui.runtimepermissions;
import android.annotation.SuppressLint;
+import android.os.Build;
import org.catrobat.catroid.content.bricks.Brick;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -41,6 +41,9 @@
import static android.Manifest.permission.ACCESS_WIFI_STATE;
import static android.Manifest.permission.BLUETOOTH;
import static android.Manifest.permission.BLUETOOTH_ADMIN;
+import static android.Manifest.permission.BLUETOOTH_ADVERTISE;
+import static android.Manifest.permission.BLUETOOTH_CONNECT;
+import static android.Manifest.permission.BLUETOOTH_SCAN;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE;
import static android.Manifest.permission.CHANGE_WIFI_STATE;
@@ -58,27 +61,34 @@ private BrickResourcesToRuntimePermissions() {
@SuppressLint("UseSparseArrays")
public static List translate(Brick.ResourcesSet brickResources) {
Map> brickResourcesToPermissions = new HashMap<>();
- brickResourcesToPermissions.put(Brick.SENSOR_GPS, Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION));
- List bluetoothPermissions = Arrays.asList(BLUETOOTH_ADMIN, BLUETOOTH);
+ brickResourcesToPermissions.put(
+ Brick.SENSOR_GPS, Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION));
+
+ List bluetoothPermissions = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
+ ? Arrays.asList(BLUETOOTH_ADVERTISE, BLUETOOTH_SCAN, BLUETOOTH_CONNECT)
+ : Arrays.asList(BLUETOOTH_ADMIN, BLUETOOTH);
brickResourcesToPermissions.put(Brick.BLUETOOTH_LEGO_NXT, bluetoothPermissions);
brickResourcesToPermissions.put(Brick.BLUETOOTH_LEGO_EV3, bluetoothPermissions);
brickResourcesToPermissions.put(Brick.BLUETOOTH_PHIRO, bluetoothPermissions);
brickResourcesToPermissions.put(Brick.BLUETOOTH_SENSORS_ARDUINO, bluetoothPermissions);
- List wifiPermissions = Arrays.asList(CHANGE_WIFI_MULTICAST_STATE, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE);
+ brickResourcesToPermissions.put(Brick.BLUETOOTH_MULTIPLAYER, bluetoothPermissions);
+
+ List wifiPermissions = Arrays.asList(
+ CHANGE_WIFI_MULTICAST_STATE, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE);
brickResourcesToPermissions.put(Brick.CAST_REQUIRED, wifiPermissions);
- brickResourcesToPermissions.put(Brick.CAMERA_BACK, Arrays.asList(CAMERA));
- brickResourcesToPermissions.put(Brick.CAMERA_FRONT, Arrays.asList(CAMERA));
- brickResourcesToPermissions.put(Brick.VIDEO, Arrays.asList(CAMERA));
- brickResourcesToPermissions.put(Brick.CAMERA_FLASH, Arrays.asList(CAMERA));
- brickResourcesToPermissions.put(Brick.VIBRATION, Arrays.asList(VIBRATE));
- brickResourcesToPermissions.put(Brick.NFC_ADAPTER, Arrays.asList(NFC));
- brickResourcesToPermissions.put(Brick.FACE_DETECTION, Collections.singletonList(CAMERA));
- brickResourcesToPermissions.put(Brick.OBJECT_DETECTION, Collections.singletonList(CAMERA));
- brickResourcesToPermissions.put(Brick.POSE_DETECTION, Collections.singletonList(CAMERA));
- brickResourcesToPermissions.put(Brick.TEXT_DETECTION, Collections.singletonList(CAMERA));
- brickResourcesToPermissions.put(Brick.MICROPHONE, Arrays.asList(RECORD_AUDIO));
- brickResourcesToPermissions.put(Brick.STORAGE_READ, Arrays.asList(READ_EXTERNAL_STORAGE));
- brickResourcesToPermissions.put(Brick.STORAGE_WRITE, Arrays.asList(WRITE_EXTERNAL_STORAGE));
+ brickResourcesToPermissions.put(Brick.CAMERA_BACK, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.CAMERA_FRONT, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.VIDEO, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.CAMERA_FLASH, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.VIBRATION, List.of(VIBRATE));
+ brickResourcesToPermissions.put(Brick.NFC_ADAPTER, List.of(NFC));
+ brickResourcesToPermissions.put(Brick.FACE_DETECTION, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.OBJECT_DETECTION, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.POSE_DETECTION, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.TEXT_DETECTION, List.of(CAMERA));
+ brickResourcesToPermissions.put(Brick.MICROPHONE, List.of(RECORD_AUDIO));
+ brickResourcesToPermissions.put(Brick.STORAGE_READ, List.of(READ_EXTERNAL_STORAGE));
+ brickResourcesToPermissions.put(Brick.STORAGE_WRITE, List.of(WRITE_EXTERNAL_STORAGE));
Set requiredPermissions = new HashSet<>();
for (int brickResource : brickResources) {