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