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 service) { - BluetoothDeviceService btService = ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE); + private void connectBTDevice(Class 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) {