diff --git a/README.md b/README.md
index b795587..6ff3fe9 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ After setting up the Gradle dependency, you will be able to access two main clas
First, you need to **find a Myo** with a bluetooth scan.
-** ⚠️ Please note that you need to request the user the ACCESS_COARSE_LOCATION permission. If not, the scan will be empty ⚠️ **
+** ⚠️ Please note that you need to request the user the ACCESS_FINE_LOCATION permission. If not, the scan will be empty ⚠️ **
To start a bluetooth scan, you can use the `startScan()` method:
@@ -109,10 +109,10 @@ myMyo.statusObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
when (it) {
- MyoStatus.CONNECTED -> { ... }
- MyoStatus.CONNECTING -> { ... }
- MyoStatus.READY -> { ... }
- else -> { ... } // DISCONNECTED
+ MyoStatus.CONNECTED -> { /* ... */ }
+ MyoStatus.CONNECTING -> { /* ... */ }
+ MyoStatus.READY -> { /* ... */ }
+ else -> { /* ... */ } // DISCONNECTED
}
}
```
@@ -188,7 +188,7 @@ myMyo.keepAlive = false
You can find the test app (Myo Emg Visualizer) inside the `app` module.
-
+
This app allows you to:
@@ -210,24 +210,28 @@ Some technical features are:
**Searching for a Myo**
-
+
**Starting the Streaming**
-
+
**Exporting to CSV**
-
+
## Building/Testing ⚙️
-### CircleCI [![CircleCI](https://circleci.com/gh/cortinico/myonnaise.svg?style=svg)](https://circleci.com/gh/cortinico/myonnaise)
+### CircleCI
+
+[![CircleCI](https://circleci.com/gh/cortinico/myonnaise.svg?style=svg)](https://circleci.com/gh/cortinico/myonnaise)
This projects is built with [**Circle CI 2.0**](https://circleci.com/gh/cortinico/myonnaise/). The CI environment takes care of building the library .AAR, the example app and to run the **JUnit** tests. Test and lint reports are exposes in the **artifacts** section at the end of every build.
-### Codecov [![codecov](https://codecov.io/gh/cortinico/myonnaise/branch/master/graph/badge.svg)](https://codecov.io/gh/cortinico/myonnaise)
+### Codecov
+
+[![codecov](https://codecov.io/gh/cortinico/myonnaise/branch/master/graph/badge.svg)](https://codecov.io/gh/cortinico/myonnaise)
Circle CI is responsible of uploading Jacoco reports to [Codecov](https://codecov.io/gh/cortinico/myonnaise). When opening a Pull Request, Codecov will post a report of the diff of the test coverage.
@@ -235,19 +239,12 @@ Please **don't ignore it**! PR with new features and **without** are likely to b
### Building locally
-Before building, make sure you have the following **updated components** from the Android SDK:
-
-* tools
-* platform-tools
-* build-tools-28.0.1
-* android-28
-
Then just clone the repo locally and build the .AAR with the following command:
```bash
git clone git@github.com:cortinico/myonnaise.git
cd myonnaise/
-./gradlew app:assemble
+./gradlew build
```
The assembled .AAR (library) will be inside the **myonnaise/build/outputs/aar** folder.
The assembled .APK (application) will be inside the **app/build/outputs/apk/debug** folder.
@@ -273,4 +270,4 @@ Make sure your tests are all green ✅ locally before submitting PRs.
## License 📄
-This project is licensed under the MIT License - see the [License](License) file for details
+This project is licensed under the MIT License - see the [License](LICENSE) file for details
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0ee0fa1..400b31f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,25 +3,22 @@
xmlns:tools="http://schemas.android.com/tools">
-
-
+ tools:ignore="GoogleAppIndexingWarning">
+ android:name="it.ncorti.emgvisualizer.ui.IntroActivity"
+ android:exported="true">
, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- when (requestCode) {
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ when (requestCode) {
REQUEST_LOCATION_CODE -> {
- if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {
startMainActivity()
} else {
Toast.makeText(
diff --git a/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceContract.kt b/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceContract.kt
index f65b2a9..01bc256 100644
--- a/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceContract.kt
+++ b/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceContract.kt
@@ -9,10 +9,6 @@ interface ControlDeviceContract {
fun showDeviceInformation(name: String?, address: String)
- fun showConnectionProgress()
-
- fun hideConnectionProgress()
-
fun showConnected()
fun showDisconnected()
diff --git a/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceFragment.kt b/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceFragment.kt
index 1b292b2..9086ca2 100644
--- a/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceFragment.kt
+++ b/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDeviceFragment.kt
@@ -62,14 +62,6 @@ class ControlDeviceFragment : BaseFragment(), C
binding.deviceAddress.text = address
}
- override fun showConnectionProgress() {
- binding.progressConnect.animate().alpha(1.0f)
- }
-
- override fun hideConnectionProgress() {
- binding.progressConnect.animate().alpha(0.0f)
- }
-
override fun showConnecting() {
binding.deviceStatus.text = getString(R.string.connecting)
}
diff --git a/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenter.kt b/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenter.kt
index 22db2ad..1e9e312 100644
--- a/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenter.kt
+++ b/app/src/main/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenter.kt
@@ -2,6 +2,7 @@
package it.ncorti.emgvisualizer.ui.control
+import android.annotation.SuppressLint
import com.ncorti.myonnaise.CommandList
import com.ncorti.myonnaise.MYO_MAX_FREQUENCY
import com.ncorti.myonnaise.MyoControlStatus
@@ -12,6 +13,7 @@ import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import it.ncorti.emgvisualizer.dagger.DeviceManager
+@SuppressLint("MissingPermission")
class ControlDevicePresenter(
override val view: ControlDeviceContract.View,
private val myonnaise: Myonnaise,
@@ -46,18 +48,15 @@ class ControlDevicePresenter(
.subscribe {
when (it) {
MyoStatus.CONNECTED -> {
- view.hideConnectionProgress()
view.showConnected()
}
MyoStatus.CONNECTING -> {
- view.showConnectionProgress()
view.showConnecting()
}
MyoStatus.READY -> {
view.enableControlPanel()
}
else -> {
- view.hideConnectionProgress()
view.showDisconnected()
view.disableControlPanel()
}
diff --git a/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportFragment.kt b/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportFragment.kt
index b168e44..f2cd9be 100644
--- a/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportFragment.kt
+++ b/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportFragment.kt
@@ -1,20 +1,16 @@
package it.ncorti.emgvisualizer.ui.export
-import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
import android.content.ContentValues
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.net.Uri
-import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
-import androidx.core.content.ContextCompat
import dagger.android.support.AndroidSupportInjection
import it.ncorti.emgvisualizer.BaseFragment
import it.ncorti.emgvisualizer.R
@@ -46,9 +42,7 @@ class ExportFragment : BaseFragment(), ExportContract.
}
override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = LayoutExportBinding.inflate(inflater, container, false)
setHasOptionsMenu(true)
@@ -74,9 +68,7 @@ class ExportFragment : BaseFragment(), ExportContract.
override fun showNotStreamingErrorMessage() {
Toast.makeText(
- activity,
- "You can't collect points if Myo is not streaming!",
- Toast.LENGTH_SHORT
+ activity, "You can't collect points if Myo is not streaming!", Toast.LENGTH_SHORT
).show()
}
@@ -124,53 +116,34 @@ class ExportFragment : BaseFragment(), ExportContract.
override fun saveCsvFile(content: String) {
val fileName = getCsvFilename()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- // Use scoped storage for API level 29 and above
- val contentResolver = context?.contentResolver
- val contentValues = ContentValues().apply {
- put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName)
- put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "text/plain")
- put(
- android.provider.MediaStore.MediaColumns.RELATIVE_PATH,
- Environment.DIRECTORY_DOCUMENTS
- )
- }
- val uri: Uri? = contentResolver?.insert(
- android.provider.MediaStore.Files.getContentUri("external"),
- contentValues
+ // Use scoped storage for API level 29 and above
+ val contentResolver = context?.contentResolver
+ val contentValues = ContentValues().apply {
+ put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName)
+ put(android.provider.MediaStore.MediaColumns.MIME_TYPE, "text/plain")
+ put(
+ android.provider.MediaStore.MediaColumns.RELATIVE_PATH,
+ Environment.DIRECTORY_DOCUMENTS
)
- if (uri != null) {
- contentResolver.openOutputStream(uri)?.use { outputStream ->
- outputStream.write(content.toByteArray())
- }
- } else {
- // Handle failure to create the file
- error("Failed to create file for scoped storage")
+ }
+ val uri: Uri? = contentResolver?.insert(
+ android.provider.MediaStore.Files.getContentUri("external"), contentValues
+ )
+ if (uri != null) {
+ contentResolver.openOutputStream(uri)?.use { outputStream ->
+ outputStream.write(content.toByteArray())
}
+ val userReadablePath = "${Environment.DIRECTORY_DOCUMENTS}/$fileName"
+ Toast.makeText(activity, "Export saved to: $userReadablePath", Toast.LENGTH_LONG).show()
} else {
- context?.apply {
- val hasPermission = (
- ContextCompat.checkSelfPermission(
- this,
- WRITE_EXTERNAL_STORAGE
- ) == PERMISSION_GRANTED
- )
- if (hasPermission) {
- writeToFile(fileName, content)
- } else {
- fileContentToSave = content
- requestPermissions(
- arrayOf(WRITE_EXTERNAL_STORAGE),
- REQUEST_WRITE_EXTERNAL_CODE
- )
- }
- }
+ // Handle failure to create the file
+ Toast.makeText(activity, "ERROR: Impossible to save export to file", Toast.LENGTH_LONG)
+ .show()
}
}
private fun writeToFile(fileName: String, content: String) {
- val storageDir =
- File("${Environment.getExternalStorageDirectory().absolutePath}/myo_emg")
+ val storageDir = File("${Environment.getExternalStorageDirectory().absolutePath}/myo_emg")
storageDir.mkdir()
val outfile = File(storageDir, fileName)
val fileOutputStream = FileOutputStream(outfile)
@@ -181,17 +154,16 @@ class ExportFragment : BaseFragment(), ExportContract.
@Deprecated("Deprecated in Java")
override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
+ requestCode: Int, permissions: Array, grantResults: IntArray
) {
when (requestCode) {
REQUEST_WRITE_EXTERNAL_CODE -> {
- if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED) {
fileContentToSave?.apply { writeToFile(getCsvFilename(), this) }
} else {
Toast.makeText(
- activity, getString(R.string.write_permission_denied_message),
+ activity,
+ getString(R.string.write_permission_denied_message),
Toast.LENGTH_SHORT
).show()
}
diff --git a/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportPresenter.kt b/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportPresenter.kt
index 62a16bf..f1e519d 100644
--- a/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportPresenter.kt
+++ b/app/src/main/java/it/ncorti/emgvisualizer/ui/export/ExportPresenter.kt
@@ -82,8 +82,8 @@ class ExportPresenter(
@VisibleForTesting
internal fun createCsv(buffer: ArrayList): String {
val stringBuilder = StringBuilder()
- buffer.forEach {
- it.forEach {
+ buffer.forEach { floatArray ->
+ floatArray.forEach {
stringBuilder.append(it)
stringBuilder.append(";")
}
diff --git a/app/src/main/java/it/ncorti/emgvisualizer/ui/scan/ScanDevicePresenter.kt b/app/src/main/java/it/ncorti/emgvisualizer/ui/scan/ScanDevicePresenter.kt
index 9f34f30..cae9650 100644
--- a/app/src/main/java/it/ncorti/emgvisualizer/ui/scan/ScanDevicePresenter.kt
+++ b/app/src/main/java/it/ncorti/emgvisualizer/ui/scan/ScanDevicePresenter.kt
@@ -1,6 +1,8 @@
package it.ncorti.emgvisualizer.ui.scan
+import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
+import android.util.Log
import com.ncorti.myonnaise.Myonnaise
import io.reactivex.Flowable
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -12,6 +14,7 @@ import java.util.concurrent.TimeUnit
const val SCAN_INTERVAL_SECONDS = 10L
+@SuppressLint("MissingPermission")
class ScanDevicePresenter(
override val view: ScanDeviceContract.View,
private val myonnaise: Myonnaise,
@@ -64,12 +67,13 @@ class ScanDevicePresenter(
deviceManager.scannedDeviceList.add(it)
}
},
- {
+ { error ->
view.hideScanLoading()
view.showScanError()
if (deviceManager.scannedDeviceList.isEmpty()) {
view.showEmptyListMessage()
}
+ Log.e("NCOR", "Error", error)
},
{
view.hideScanLoading()
diff --git a/app/src/main/res/layout/item_device.xml b/app/src/main/res/layout/item_device.xml
index daa5230..a342eb1 100644
--- a/app/src/main/res/layout/item_device.xml
+++ b/app/src/main/res/layout/item_device.xml
@@ -50,8 +50,8 @@
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="@string/select"
- app:layout_constraintBottom_toTopOf="@+id/image_device"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/image_device" />
+ app:layout_constraintTop_toTopOf="parent" />
diff --git a/app/src/main/res/layout/layout_control_device.xml b/app/src/main/res/layout/layout_control_device.xml
index 5cf35f8..2b92b02 100644
--- a/app/src/main/res/layout/layout_control_device.xml
+++ b/app/src/main/res/layout/layout_control_device.xml
@@ -1,239 +1,235 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ android:layout_height="wrap_content">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index c9cbcfd..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index 406a534..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 08d2d01..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index d6675aa..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index d7870a7..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 47873c1..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index a8a1b40..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index e6ea677..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 893274f..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index 5bede0a..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap/ic_launcher.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to app/src/main/res/mipmap/ic_launcher.xml
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap/ic_launcher_round.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to app/src/main/res/mipmap/ic_launcher_round.xml
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index c51e8ce..66d0a25 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -6,6 +6,7 @@
12dp
16dp
40dp
+ 48dp
72dp
@dimen/quadruple_grid_size
diff --git a/app/src/test/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenterTest.kt b/app/src/test/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenterTest.kt
index d6d05f4..6672720 100644
--- a/app/src/test/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenterTest.kt
+++ b/app/src/test/java/it/ncorti/emgvisualizer/ui/control/ControlDevicePresenterTest.kt
@@ -37,8 +37,8 @@ class ControlDevicePresenterTest {
mockedView = mock {}
mockedMyo = mock {
- on(this.mock.statusObservable()) doReturn Observable.empty()
- on(this.mock.controlObservable()) doReturn Observable.empty()
+ on(this.mock.statusObservable()) doReturn Observable.empty()
+ on(this.mock.controlObservable()) doReturn Observable.empty()
}
mockedMyonnaise = mock {}
mockedBluetoothDevice = mock {
@@ -77,7 +77,6 @@ class ControlDevicePresenterTest {
testPresenter.start()
verify(mockedView).showConnecting()
- verify(mockedView).showConnectionProgress()
}
@Test
@@ -86,7 +85,6 @@ class ControlDevicePresenterTest {
testPresenter.start()
- verify(mockedView, atLeast(1)).hideConnectionProgress()
verify(mockedView).showConnected()
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index aad90db..87ddf17 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,12 +1,12 @@
[versions]
-min_sdk_version = "21"
-target_sdk_version = "34"
-compile_sdk_version = "34"
+min_sdk_version = "31"
+target_sdk_version = "35"
+compile_sdk_version = "35"
agp = "8.7.2"
androidx_recyclerview = "1.3.2"
appcompat = "1.7.0"
-appintro = "5.1.0"
+appintro = "6.3.1"
constraintlayout = "2.2.0"
dagger = "2.16"
detekt = "1.23.7"
diff --git a/kotlin-static-analysis.gradle b/kotlin-static-analysis.gradle
index cb50e59..0de1a8b 100644
--- a/kotlin-static-analysis.gradle
+++ b/kotlin-static-analysis.gradle
@@ -20,5 +20,5 @@ ktlint {
detekt {
toolVersion = "1.23.7"
- config = files("../config/detekt/detekt.yml")
+ config.setFrom("../config/detekt/detekt.yml")
}
\ No newline at end of file
diff --git a/myonnaise/src/main/AndroidManifest.xml b/myonnaise/src/main/AndroidManifest.xml
index 3c36f86..09dbedf 100644
--- a/myonnaise/src/main/AndroidManifest.xml
+++ b/myonnaise/src/main/AndroidManifest.xml
@@ -1,9 +1,14 @@
-
+
-
-
-
-
+
+
+
+
+
diff --git a/myonnaise/src/main/java/com/ncorti/myonnaise/CommandList.kt b/myonnaise/src/main/java/com/ncorti/myonnaise/CommandList.kt
index 0bf9db7..3fad7a1 100644
--- a/myonnaise/src/main/java/com/ncorti/myonnaise/CommandList.kt
+++ b/myonnaise/src/main/java/com/ncorti/myonnaise/CommandList.kt
@@ -93,4 +93,4 @@ fun Command.isStartStreamingCommand() =
(this[2] != 0x00.toByte() || this[3] != 0x00.toByte() || this[4] != 0x00.toByte())
/** Extension function to check the [Command] is a stop streaming command */
-fun Command.isStopStreamingCommand() = Arrays.equals(this, CommandList.stopStreaming())
+fun Command.isStopStreamingCommand() = this.contentEquals(CommandList.stopStreaming())
diff --git a/myonnaise/src/main/java/com/ncorti/myonnaise/Myo.kt b/myonnaise/src/main/java/com/ncorti/myonnaise/Myo.kt
index b1cabcd..f6f2d12 100644
--- a/myonnaise/src/main/java/com/ncorti/myonnaise/Myo.kt
+++ b/myonnaise/src/main/java/com/ncorti/myonnaise/Myo.kt
@@ -33,6 +33,7 @@ enum class MyoControlStatus {
*
* @param device The [BluetoothDevice] that is backing this Myo.
*/
+@Suppress("MissingPermission")
class Myo(private val device: BluetoothDevice) : BluetoothGattCallback() {
/** The Device Name of this Myo */
@@ -53,7 +54,7 @@ class Myo(private val device: BluetoothDevice) : BluetoothGattCallback() {
* Keep alive flag. If set to true, the library will send a [CommandList.unSleep] command
* to the device every [KEEP_ALIVE_INTERVAL_MS] ms.
*/
- var keepAlive = true
+ private var keepAlive = true
private var lastKeepAlive = 0L
// Subjects for publishing outside Connection Status, Control Status and the Data (Float Arrays).
@@ -61,7 +62,7 @@ class Myo(private val device: BluetoothDevice) : BluetoothGattCallback() {
BehaviorSubject.createDefault(MyoStatus.DISCONNECTED)
internal val controlStatusSubject: BehaviorSubject =
BehaviorSubject.createDefault(MyoControlStatus.NOT_STREAMING)
- internal val dataProcessor: PublishProcessor = PublishProcessor.create()
+ private val dataProcessor: PublishProcessor = PublishProcessor.create()
internal var gatt: BluetoothGatt? = null
private var byteReader = ByteReader()
@@ -246,7 +247,8 @@ class Myo(private val device: BluetoothDevice) : BluetoothGattCallback() {
gatt.readCharacteristic(readQueue.element())
}
- @SuppressLint("DefaultLocale")
+ @Deprecated("Deprecated in Java")
+ @SuppressLint("DefaultLocale", "MissingPermission")
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
super.onCharacteristicRead(gatt, characteristic, status)
readQueue.remove()
@@ -275,10 +277,12 @@ class Myo(private val device: BluetoothDevice) : BluetoothGattCallback() {
}
}
- if (readQueue.size > 0)
+ if (readQueue.size > 0) {
gatt.readCharacteristic(readQueue.element())
+ }
}
+ @Deprecated("Deprecated in Java")
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
super.onCharacteristicChanged(gatt, characteristic)
diff --git a/myonnaise/src/main/java/com/ncorti/myonnaise/Myonnaise.kt b/myonnaise/src/main/java/com/ncorti/myonnaise/Myonnaise.kt
index 2ab33e6..b02f913 100644
--- a/myonnaise/src/main/java/com/ncorti/myonnaise/Myonnaise.kt
+++ b/myonnaise/src/main/java/com/ncorti/myonnaise/Myonnaise.kt
@@ -19,9 +19,10 @@ import java.util.concurrent.TimeUnit
* Use this class to do a Bluetooth scan and search for a new [Myo].
*
* Please note that in order to perform a Bluetooth Scan, the user needs to provide the
- * [android.permission.ACCESS_COARSE_LOCATION] permission. You must request this permission to
+ * `android.permission.ACCESS_FINE_LOCATION` permission. You must request this permission to
* the user otherwise your scan will be empty.
*/
+@Suppress("MissingPermission")
class Myonnaise(val context: Context) {
private val blManager = context.getSystemService(Activity.BLUETOOTH_SERVICE) as BluetoothManager
diff --git a/myonnaise/src/test/java/com/ncorti/myonnaise/ByteReaderTest.kt b/myonnaise/src/test/java/com/ncorti/myonnaise/ByteReaderTest.kt
index c7fb474..1aed91b 100644
--- a/myonnaise/src/test/java/com/ncorti/myonnaise/ByteReaderTest.kt
+++ b/myonnaise/src/test/java/com/ncorti/myonnaise/ByteReaderTest.kt
@@ -72,7 +72,7 @@ class ByteReaderTest {
val resultArray = testReader.getBytes(8)
assertEquals(8, resultArray.size)
- for (i in 0 until resultArray.size) {
+ for (i in resultArray.indices) {
assertEquals(i.toFloat(), resultArray[i])
}
}
diff --git a/sensorgraphview/src/main/java/com/ncorti/myonnaise/sensorgraphview/SensorGraphView.kt b/sensorgraphview/src/main/java/com/ncorti/myonnaise/sensorgraphview/SensorGraphView.kt
index 79af9b5..c34f45f 100644
--- a/sensorgraphview/src/main/java/com/ncorti/myonnaise/sensorgraphview/SensorGraphView.kt
+++ b/sensorgraphview/src/main/java/com/ncorti/myonnaise/sensorgraphview/SensorGraphView.kt
@@ -7,6 +7,7 @@ import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
+import kotlin.math.min
/** Default point circle size */
private const val CIRCLE_SIZE_DEFAULT = 3
@@ -33,7 +34,7 @@ class SensorGraphView(context: Context, attrs: AttributeSet) : View(context, att
var maxValue = INITIAL_MAX_VALUE
var minValue = INITIAL_MIN_VALUE
- val spread: Float
+ private val spread: Float
get() = maxValue - minValue
private val zeroLine: Float
@@ -52,9 +53,9 @@ class SensorGraphView(context: Context, attrs: AttributeSet) : View(context, att
init {
val colors = context.resources.getIntArray(R.array.graph_colors)
- for (i in 0 until colors.size) {
+ for (element in colors) {
val paint = Paint()
- paint.color = Color.parseColor("#${Integer.toHexString(colors[i])}")
+ paint.color = Color.parseColor("#${Integer.toHexString(element)}")
rectPaints += paint
}
@@ -73,14 +74,14 @@ class SensorGraphView(context: Context, attrs: AttributeSet) : View(context, att
val desiredWidth = suggestedMinimumWidth + paddingLeft + paddingRight
val width = when (MeasureSpec.getMode(widthMeasureSpec)) {
MeasureSpec.EXACTLY -> widthSize
- MeasureSpec.AT_MOST -> Math.min(desiredWidth, widthSize)
+ MeasureSpec.AT_MOST -> min(desiredWidth, widthSize)
MeasureSpec.UNSPECIFIED -> desiredWidth
else -> desiredWidth
}
val desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom
val height = when (MeasureSpec.getMode(heightMeasureSpec)) {
MeasureSpec.EXACTLY -> heightSize
- MeasureSpec.AT_MOST -> Math.min(desiredHeight, heightSize)
+ MeasureSpec.AT_MOST -> min(desiredHeight, heightSize)
MeasureSpec.UNSPECIFIED -> desiredHeight
else -> desiredHeight
}