From 0c6e305aea38132ad9d67fd2ef948f7a0bc381f4 Mon Sep 17 00:00:00 2001 From: Trishun Date: Fri, 4 Aug 2023 02:31:31 +0200 Subject: [PATCH] Garmin connection (DIRTY) --- app/build.gradle | 18 +- app/src/main/AndroidManifest.xml | 68 ++-- app/src/main/java/eu/ztsh/garmin/Garmin.kt | 112 +++++++ .../main/java/eu/ztsh/garmin/MainActivity.kt | 118 ++++++- .../java/eu/ztsh/garmin/bt/BluetoothSerial.kt | 310 ++++++++++++++++++ .../java/eu/ztsh/garmin/ExampleUnitTest.kt | 4 +- .../test/java/eu/ztsh/garmin/GarminTest.kt | 22 ++ build.gradle | 7 +- gradle.properties | 26 +- gradle/wrapper/gradle-wrapper.properties | 12 +- 10 files changed, 638 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/eu/ztsh/garmin/Garmin.kt create mode 100644 app/src/main/java/eu/ztsh/garmin/bt/BluetoothSerial.kt create mode 100644 app/src/test/java/eu/ztsh/garmin/GarminTest.kt diff --git a/app/build.gradle b/app/build.gradle index 908ad39..7ad2bb2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,16 +1,17 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' + id "de.mannodermaus.android-junit5" } android { namespace 'eu.ztsh.garmin' - compileSdk 33 + compileSdk 31 defaultConfig { applicationId "eu.ztsh.garmin" minSdk 29 - targetSdk 33 + targetSdk 31 versionCode 1 versionName "1.0" @@ -36,17 +37,18 @@ dependencies { // Notification parser implementation 'com.github.3v1n0.GMapsParser:navparser:0.2.1' - - // Bluetooth serial - implementation 'com.github.harry1453:android-bluetooth-serial:v1.1' - implementation 'io.reactivex.rxjava2:rxjava:2.1.12' - implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' +// +// // Bluetooth serial +// implementation 'com.github.harry1453:android-bluetooth-serial:v1.1' +// implementation 'io.reactivex.rxjava2:rxjava:2.1.12' +// implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' - testImplementation 'junit:junit:4.13.2' +// testImplementation 'junit:junit:4.13.2' + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4c8451d..fce5820 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,25 +1,43 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/eu/ztsh/garmin/Garmin.kt b/app/src/main/java/eu/ztsh/garmin/Garmin.kt new file mode 100644 index 0000000..21071f5 --- /dev/null +++ b/app/src/main/java/eu/ztsh/garmin/Garmin.kt @@ -0,0 +1,112 @@ +package eu.ztsh.garmin + +import android.annotation.SuppressLint +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothSocket +import android.util.Log +import java.io.IOException +import java.util.* + + +@SuppressLint("MissingPermission") +class Garmin( + val context: MainActivity, + val device: BluetoothDevice, + val adapter: BluetoothAdapter +) { + + private lateinit var thread: ConnectThread + + fun start() { + thread = ConnectThread() + thread.start() + } + + fun close() { + thread.close() + } + + private inner class ConnectThread : Thread() { + + private val socket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) { + context.checkBt() + device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")) + } + + override fun run() { + // Cancel discovery because it otherwise slows down the connection. + context.checkBt() + adapter.cancelDiscovery() + socket?.connect() + sleep(3000) + readAll() + send(intArrayOf(1, 1, 0, 16)) + send(intArrayOf(3, 0, 1, 10, 0, 10, 3)) + send(intArrayOf(3, 0, 0, 9, 0, 9, 3)) + send(intArrayOf(0x04, 0x01)) + } + + // Closes the client socket and causes the thread to finish. + fun close() { + try { + socket?.close() + } catch (e: IOException) { + Log.e(TAG, "Could not close the client socket", e) + } + } + + fun readAll() { + val buffer = ByteArray(64) + val istr = socket!!.inputStream + istr!!.let { + if (it.available() > 0) { + it.read(buffer) + } + } + } + + fun send(hex: IntArray) { + sendRaw(prepareData(hex)) + } + + private fun sendRaw(buff: IntArray) { + buff.forEach { socket!!.outputStream.write(it) } + socket!!.outputStream.flush() + sleep(2000) + readAll() + } + + } + + companion object { + fun prepareData(input: IntArray): IntArray { + val n = input.size + var crc = (0xeb + n + n).toUInt() + val chars = ArrayList() + chars.add(0x10) + chars.add(0x7b) + chars.add((n + 0x06)) + if (n == 0xa) + chars.add(0x10) + chars.add(n) + chars.add(0x00) + chars.add(0x00) + chars.add(0x00) + chars.add(0x55) + chars.add(0x15) + for (char in input) { + crc = (crc + char.toUInt()) + chars.add(char) + if (char == 0x10) + chars.add(0x10) + } + chars.add((-(crc.toInt()) and 0xff)) + chars.add(0x10) + chars.add(0x03) + return chars.toIntArray() + } + + private const val TAG = "GARMIN" + } +} diff --git a/app/src/main/java/eu/ztsh/garmin/MainActivity.kt b/app/src/main/java/eu/ztsh/garmin/MainActivity.kt index 67b9340..01b49a8 100644 --- a/app/src/main/java/eu/ztsh/garmin/MainActivity.kt +++ b/app/src/main/java/eu/ztsh/garmin/MainActivity.kt @@ -1,11 +1,125 @@ package eu.ztsh.garmin -import androidx.appcompat.app.AppCompatActivity +import android.Manifest +import android.annotation.SuppressLint +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothManager +import android.bluetooth.BluetoothSocket +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle +import android.util.Log +import androidx.activity.result.ActivityResultCallback +import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import java.io.IOException +import java.util.* +@SuppressLint("MissingPermission") class MainActivity : AppCompatActivity() { + + lateinit var garmin: Garmin + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + bluetoothInit() } -} \ No newline at end of file + override fun onPause() { + super.onPause() +// bluetoothSerial.onPause() + } + + override fun onResume() { + super.onResume() +// bluetoothSerial.onResume() + } + + private fun bluetoothInit() { + val bluetoothManager: BluetoothManager = getSystemService(BluetoothManager::class.java) + val bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter + ?: // Device doesn't support Bluetooth + throw Exception() + if (!bluetoothAdapter.isEnabled) { + // TODO: Start intent + val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) + registerForActivityResult(StartActivityForResult(), ActivityResultCallback { }) + } + checkBt() + + val pairedDevices: Set? = bluetoothAdapter.bondedDevices + val context = this + pairedDevices?.firstOrNull { device -> + Log.d(TAG, device.name) + device.name.equals("GARMIN HUD") + }?.apply { + garmin = Garmin(context, this, bluetoothAdapter) + garmin.start() + } + + } + + fun checkBt(): Boolean { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) { + checkBt(Manifest.permission.BLUETOOTH_SCAN) + checkBt(Manifest.permission.BLUETOOTH_CONNECT) + } else { + checkBt(Manifest.permission.BLUETOOTH) + checkBt(Manifest.permission.BLUETOOTH_ADMIN) + } + return true + } + + private fun checkBt(permission: String): Boolean { + if (ActivityCompat.checkSelfPermission( + this, + permission + ) != PackageManager.PERMISSION_GRANTED + ) { + ActivityCompat.requestPermissions(this, arrayOf(permission), 1) + } + return true + } + + private inner class ConnectThread(val device: BluetoothDevice, val adapter: BluetoothAdapter) : Thread() { + + private val mmSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) { + checkBt() +// device.createInsecureRfcommSocketToServiceRecord(UUID.fromString("7d00d7f5-921b-450c-8eda-26e1d4a15c61")) + device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")) + } + + override fun run() { + // Cancel discovery because it otherwise slows down the connection. + checkBt() + adapter.cancelDiscovery() + + mmSocket?.let { socket -> + // Connect to the remote device through the socket. This call blocks + // until it succeeds or throws an exception. + socket.connect() + + // The connection attempt succeeded. Perform work associated with + // the connection in a separate thread. +// manageMyConnectedSocket(socket) + } + } + + // Closes the client socket and causes the thread to finish. + fun cancel() { + try { + mmSocket?.close() + } catch (e: IOException) { + Log.e(Companion.TAG, "Could not close the client socket", e) + } + } + } + + companion object { + private const val TAG = "bt" + } + +} diff --git a/app/src/main/java/eu/ztsh/garmin/bt/BluetoothSerial.kt b/app/src/main/java/eu/ztsh/garmin/bt/BluetoothSerial.kt new file mode 100644 index 0000000..5167e61 --- /dev/null +++ b/app/src/main/java/eu/ztsh/garmin/bt/BluetoothSerial.kt @@ -0,0 +1,310 @@ +package eu.ztsh.garmin.bt + +import android.annotation.SuppressLint +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothDevice +import android.bluetooth.BluetoothSocket +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.AsyncTask +import android.util.Log +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import eu.ztsh.garmin.MainActivity +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.util.* + +class BluetoothSerial(var context: MainActivity, var messageHandler: MessageHandler, devicePrefix: String) { + var connected = false + var bluetoothDevice: BluetoothDevice? = null + var serialSocket: BluetoothSocket? = null + var serialInputStream: InputStream? = null + var serialOutputStream: OutputStream? = null + var serialReader: SerialReader? = null + var connectionTask: AsyncTask? = null + var devicePrefix: String + + /** + * Listens for discount message from bluetooth system and restablishing a connection + */ + private val bluetoothReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val action = intent.action + val eventDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) + if (BluetoothDevice.ACTION_ACL_DISCONNECTED == action) { + if (bluetoothDevice != null && bluetoothDevice == eventDevice) { + Log.i(BMX_BLUETOOTH, "Received bluetooth disconnect notice") + + //clean up any streams + close() + + //reestablish connect + connect() + LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(BLUETOOTH_DISCONNECTED)) + } + } + } + } + + init { + this.devicePrefix = devicePrefix.uppercase(Locale.getDefault()) + } + + fun onPause() { + context.unregisterReceiver(bluetoothReceiver) + } + + fun onResume() { + //listen for bluetooth disconnect + val disconnectIntent = IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED) + context.registerReceiver(bluetoothReceiver, disconnectIntent) + + //reestablishes a connection is one doesn't exist + if (!connected) { + connect() + } else { + val intent = Intent(BLUETOOTH_CONNECTED) + LocalBroadcastManager.getInstance(context).sendBroadcast(intent) + } + } + + /** + * Initializes the bluetooth serial connections, uses the LocalBroadcastManager when + * connection is established + */ + @SuppressLint("MissingPermission") + fun connect() { + if (connected) { + Log.e(BMX_BLUETOOTH, "Connection request while already connected") + return + } + if (connectionTask != null && connectionTask!!.status == AsyncTask.Status.RUNNING) { + Log.e(BMX_BLUETOOTH, "Connection request while attempting connection") + return + } + val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter() + if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) { + return + } + context.checkBt() + val pairedDevices: List = ArrayList(bluetoothAdapter.getBondedDevices()) + if (pairedDevices.isNotEmpty()) { + bluetoothAdapter.cancelDiscovery() + /** + * AsyncTask to handle the establishing of a bluetooth connection + */ +// connectionTask = object : AsyncTask() { +// var MAX_ATTEMPTS = 30 +// var attemptCounter = 0 +// protected override fun doInBackground(vararg params: Void): BluetoothDevice? { +// while (!isCancelled) { //need to kill without calling onCancel +// for (device in pairedDevices) { +// if (device.getName().uppercase(Locale.getDefault()).startsWith(devicePrefix)) { +// Log.i( +// BMX_BLUETOOTH, +// attemptCounter.toString() + ": Attempting connection to " + device.getName() +// ) +// try { +// serialSocket = try { +// // Standard SerialPortService ID +// val uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") +// device.createRfcommSocketToServiceRecord(uuid) +// } catch (ce: Exception) { +// connectViaReflection(device) +// } +// +// //setup the connect streams +// serialSocket!!.connect() +// serialInputStream = serialSocket!!.inputStream +// serialOutputStream = serialSocket!!.outputStream +// connected = true +// Log.i(BMX_BLUETOOTH, "Connected to " + device.getName()) +// return device +// } catch (e: Exception) { +// serialSocket = null +// serialInputStream = null +// serialOutputStream = null +// Log.i(BMX_BLUETOOTH, e.message!!) +// } +// } +// } +// try { +// attemptCounter++ +// if (attemptCounter > MAX_ATTEMPTS) cancel(false) else Thread.sleep(1000) +// } catch (e: InterruptedException) { +// break +// } +// } +// Log.i(BMX_BLUETOOTH, "Stopping connection attempts") +// val intent = Intent(BLUETOOTH_FAILED) +// LocalBroadcastManager.getInstance(context).sendBroadcast(intent) +// return null +// } +// +// override fun onPostExecute(result: BluetoothDevice?) { +// super.onPostExecute(result) +// bluetoothDevice = result +// +// //start thread responsible for reading from inputstream +// serialReader = SerialReader() +// serialReader!!.start() +// +// //send connection message +// val intent = Intent(BLUETOOTH_CONNECTED) +// LocalBroadcastManager.getInstance(context).sendBroadcast(intent) +// } +// } +// connectionTask.execute() + } + } + + // see: http://stackoverflow.com/questions/3397071/service-discovery-failed-exception-using-bluetooth-on-android + @Throws(Exception::class) + private fun connectViaReflection(device: BluetoothDevice): BluetoothSocket { + val m = device.javaClass.getMethod( + "createRfcommSocket", *arrayOf?>( + Int::class.javaPrimitiveType + ) + ) + return m.invoke(device, 1) as BluetoothSocket + } + + @Throws(IOException::class) + fun available(): Int { + if (connected) return serialInputStream!!.available() + throw RuntimeException("Connection lost, reconnecting now.") + } + + @Throws(IOException::class) + fun read(): Int { + if (connected) return serialInputStream!!.read() + throw RuntimeException("Connection lost, reconnecting now.") + } + + @Throws(IOException::class) + fun read(buffer: ByteArray?): Int { + if (connected) return serialInputStream!!.read(buffer) + throw RuntimeException("Connection lost, reconnecting now.") + } + + @Throws(IOException::class) + fun read(buffer: ByteArray?, byteOffset: Int, byteCount: Int): Int { + if (connected) return serialInputStream!!.read(buffer, byteOffset, byteCount) + throw RuntimeException("Connection lost, reconnecting now.") + } + + @Throws(IOException::class) + fun write(buffer: ByteArray?) { + if (connected) serialOutputStream!!.write(buffer) + throw RuntimeException("Connection lost, reconnecting now.") + } + + @Throws(IOException::class) + fun write(oneByte: Int) { + if (connected) serialOutputStream!!.write(oneByte) + throw RuntimeException("Connection lost, reconnecting now.") + } + + @Throws(IOException::class) + fun write(buffer: ByteArray?, offset: Int, count: Int) { + serialOutputStream!!.write(buffer, offset, count) + throw RuntimeException("Connection lost, reconnecting now.") + } + + inner class SerialReader : Thread() { + var buffer = ByteArray(Companion.MAX_BYTES) + var bufferSize = 0 + override fun run() { + Log.i("serialReader", "Starting serial loop") + while (!isInterrupted) { + try { + + /* + * check for some bytes, or still bytes still left in + * buffer + */ + if (available() > 0) { + val newBytes = read(buffer, bufferSize, Companion.MAX_BYTES - bufferSize) + if (newBytes > 0) bufferSize += newBytes + Log.d(BMX_BLUETOOTH, "read $newBytes") + } + if (bufferSize > 0) { + val read = messageHandler.read(bufferSize, buffer) + + // shift unread data to start of buffer + if (read > 0) { + var index = 0 + for (i in read until bufferSize) { + buffer[index++] = buffer[i] + } + bufferSize = index + } + } else { + try { + sleep(10) + } catch (ie: InterruptedException) { + break + } + } + } catch (e: Exception) { + Log.e(BMX_BLUETOOTH, "Error reading serial data", e) + } + } + Log.i(BMX_BLUETOOTH, "Shutting serial loop") + } + +// companion object { +// } + } + + /** + * Reads from the serial buffer, processing any available messages. Must return the number of bytes + * consumer from the buffer + * + * @author jpetrocik + */ + fun interface MessageHandler { + fun read(bufferSize: Int, buffer: ByteArray?): Int + } + + fun close() { + connected = false + if (connectionTask != null) { + connectionTask!!.cancel(false) + } + if (serialReader != null) { + serialReader!!.interrupt() + try { + serialReader!!.join(1000) + } catch (ie: InterruptedException) { + } + } + try { + serialInputStream!!.close() + } catch (e: Exception) { + Log.e(BMX_BLUETOOTH, "Failed releasing inputstream connection") + } + try { + serialOutputStream!!.close() + } catch (e: Exception) { + Log.e(BMX_BLUETOOTH, "Failed releasing outputstream connection") + } + try { + serialSocket!!.close() + } catch (e: Exception) { + Log.e(BMX_BLUETOOTH, "Failed closing socket") + } + Log.i(BMX_BLUETOOTH, "Released bluetooth connections") + } + + companion object { + private const val BMX_BLUETOOTH = "BMXBluetooth" + var BLUETOOTH_CONNECTED = "bluetooth-connection-started" + var BLUETOOTH_DISCONNECTED = "bluetooth-connection-lost" + var BLUETOOTH_FAILED = "bluetooth-connection-failed" + private const val MAX_BYTES = 125 + } +} diff --git a/app/src/test/java/eu/ztsh/garmin/ExampleUnitTest.kt b/app/src/test/java/eu/ztsh/garmin/ExampleUnitTest.kt index 521c43d..3b7b5cb 100644 --- a/app/src/test/java/eu/ztsh/garmin/ExampleUnitTest.kt +++ b/app/src/test/java/eu/ztsh/garmin/ExampleUnitTest.kt @@ -1,8 +1,8 @@ package eu.ztsh.garmin -import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test -import org.junit.Assert.* /** * Example local unit test, which will execute on the development machine (host). diff --git a/app/src/test/java/eu/ztsh/garmin/GarminTest.kt b/app/src/test/java/eu/ztsh/garmin/GarminTest.kt new file mode 100644 index 0000000..beaa6e0 --- /dev/null +++ b/app/src/test/java/eu/ztsh/garmin/GarminTest.kt @@ -0,0 +1,22 @@ +package eu.ztsh.garmin + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +class GarminTest { + + @Test + fun arayCreationTest() { + arrayTest(intArrayOf(0x04, 0x01), intArrayOf(16, 123, 8, 2, 0, 0, 0, 85, 21, 4, 1, 12, 16, 3)) + arrayTest( + intArrayOf(3, 0, 0, 9, 0, 9, 3), + intArrayOf(16, 123, 13, 7, 0, 0, 0, 85, 21, 3, 0, 0, 9, 0, 9, 3, 0xef, 16, 3) + ) + } + + private fun arrayTest(input: IntArray, expected: IntArray) { + val output = Garmin.prepareData(input) + assertArrayEquals(expected, output) + } + +} diff --git a/build.gradle b/build.gradle index 5df35a3..45e2fa6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,11 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + dependencies { + classpath("de.mannodermaus.gradle.plugins:android-junit5:1.8.2.1") + } +} plugins { - id 'com.android.application' version '7.4.1' apply true + id 'com.android.application' version '7.4.1' apply false id 'com.android.library' version '7.4.1' apply false id 'org.jetbrains.kotlin.android' version '1.8.21' apply false } diff --git a/gradle.properties b/gradle.properties index 2cbd6d1..a54461c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,23 +1,19 @@ -# Project-wide Gradle settings. -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. -# For more details on how to configure your build environment visit +## For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html +# # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# Default value: -Xmx1024m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official -# Enables namespacing of each library's R class so that its R class includes only the -# resources declared in the library itself and none from the library's dependencies, -# thereby reducing the size of the R class for that library +#Thu Jun 22 21:51:56 CEST 2023 +android.enableJetifier=true android.nonTransitiveRClass=true +android.useAndroidX=true +kotlin.code.style=official +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding\=UTF-8 +org.gradle.unsafe.configuration-cache=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index daf36aa..89142c4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Jun 22 21:00:17 CEST 2023 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +#Thu Jun 22 21:00:17 CEST 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists