Add DFU module

This commit is contained in:
Sylwester Zieliński
2022-01-04 15:07:57 +01:00
parent 8545a50995
commit fca84b7f23
18 changed files with 315 additions and 1 deletions

30
profile_dfu/build.gradle Normal file
View File

@@ -0,0 +1,30 @@
apply from: rootProject.file("library.gradle")
apply plugin: 'kotlin-parcelize'
dependencies {
implementation project(":lib_service")
implementation project(":lib_theme")
implementation project(":lib_utils")
implementation libs.chart
implementation libs.nordic.ble.common
implementation libs.nordic.theme
implementation libs.nordic.log
implementation libs.nordic.dfu
implementation libs.bundles.compose
implementation libs.androidx.core
implementation libs.material
implementation libs.lifecycle.activity
implementation libs.lifecycle.service
implementation libs.compose.lifecycle
implementation libs.compose.activity
testImplementation libs.test.junit
androidTestImplementation libs.android.test.junit
androidTestImplementation libs.android.test.espresso
androidTestImplementation libs.android.test.compose.ui
debugImplementation libs.android.test.compose.tooling
}

View File

@@ -0,0 +1,24 @@
package no.nordicsemi.dfu
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("no.nordicsemi.dfu.test", appContext.packageName)
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="no.nordicsemi.dfu">
</manifest>

View File

@@ -0,0 +1,4 @@
package no.nordicsemi.dfu.data
class DFUData {
}

View File

@@ -0,0 +1,15 @@
package no.nordicsemi.dfu.data
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
internal class DFUDataHolder @Inject constructor() {
private val _data = MutableStateFlow(DFUData())
val data: StateFlow<DFUData> = _data
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.dfu.repository
import android.app.Activity
import no.nordicsemi.android.dfu.DfuBaseService
import no.nordicsemi.dfu.view.NotificationActivity
class DFUService : DfuBaseService() {
override fun getNotificationTarget(): Class<out Activity?>? {
/*
* As a target activity the NotificationActivity is returned, not the MainActivity. This is because the notification must create a new task:
*
* intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
*
* when user press it. Using NotificationActivity we can check whether the new activity is a root activity (that means no other activity was open before)
* or that there is other activity already open. In the later case the notificationActivity will just be closed. System will restore the previous activity.
* However if the application has been closed during upload and user click the notification a NotificationActivity will be launched as a root activity.
* It will create and start the main activity and terminate itself.
*
* This method may be used to restore the target activity in case the application was closed or is open. It may also be used to recreate an activity
* history (see NotificationActivity).
*/
return NotificationActivity::class.java
}
override fun isDebug(): Boolean {
// return BuildConfig.DEBUG;
return true
}
}

View File

@@ -0,0 +1,8 @@
package no.nordicsemi.dfu.view
import androidx.compose.runtime.Composable
import no.nordicsemi.dfu.data.DFUData
@Composable
internal fun DFUContentView(state: DFUData, onEvent: (DFUViewEvent) -> Unit) {
}

View File

@@ -0,0 +1,7 @@
package no.nordicsemi.dfu.view
import androidx.compose.runtime.Composable
@Composable
fun DFUErrorView() {
}

View File

@@ -0,0 +1,7 @@
package no.nordicsemi.dfu.view
import androidx.compose.runtime.Composable
@Composable
fun DFUInstallingView() {
}

View File

@@ -0,0 +1,54 @@
package no.nordicsemi.dfu.view
import android.content.Intent
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import no.nordicsemi.android.theme.view.BackIconAppBar
import no.nordicsemi.android.utils.isServiceRunning
import no.nordicsemi.dfu.R
import no.nordicsemi.dfu.data.DFUData
import no.nordicsemi.dfu.repository.DFUService
import no.nordicsemi.dfu.viewmodel.DFUViewModel
@Composable
fun DFUScreen(finishAction: () -> Unit) {
val viewModel: DFUViewModel = hiltViewModel()
val state = viewModel.state.collectAsState().value
val isScreenActive = viewModel.isActive.collectAsState().value
val context = LocalContext.current
LaunchedEffect(isScreenActive) {
if (!isScreenActive) {
finishAction()
}
if (context.isServiceRunning(DFUService::class.java.name)) {
val intent = Intent(context, DFUService::class.java)
context.stopService(intent)
}
}
LaunchedEffect("start-service") {
if (!context.isServiceRunning(DFUService::class.java.name)) {
val intent = Intent(context, DFUService::class.java)
context.startService(intent)
}
}
DFUView(state) { viewModel.onEvent(it) }
}
@Composable
private fun DFUView(state: DFUData, onEvent: (DFUViewEvent) -> Unit) {
Column {
BackIconAppBar(stringResource(id = R.string.dfu_title)) {
onEvent(OnDisconnectButtonClick)
}
DFUContentView(state) { onEvent(it) }
}
}

View File

@@ -0,0 +1,7 @@
package no.nordicsemi.dfu.view
import androidx.compose.runtime.Composable
@Composable
fun DFUSelectFileView() {
}

View File

@@ -0,0 +1,7 @@
package no.nordicsemi.dfu.view
import androidx.compose.runtime.Composable
@Composable
fun DFUSuccessView() {
}

View File

@@ -0,0 +1,5 @@
package no.nordicsemi.dfu.view
internal sealed class DFUViewEvent
internal object OnDisconnectButtonClick : DFUViewEvent()

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2015, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.dfu.view
import android.app.Activity
import android.os.Bundle
class NotificationActivity : Activity() {
protected override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot()) {
// Start the app before finishing
//TODO
// val parentIntent = Intent(this, FeaturesActivity::class.java)
// parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// val startAppIntent = Intent(this, DfuActivity::class.java)
// if (getIntent() != null && getIntent().getExtras() != null) startAppIntent.putExtras(
// getIntent().getExtras()
// )
// startActivities(arrayOf<Intent>(parentIntent, startAppIntent))
}
// Now finish, which will drop the user in to the activity that was at the top
// of the task stack
finish()
}
}

View File

@@ -0,0 +1,19 @@
package no.nordicsemi.dfu.viewmodel
import dagger.hilt.android.lifecycle.HiltViewModel
import no.nordicsemi.android.theme.viewmodel.CloseableViewModel
import no.nordicsemi.dfu.data.DFUDataHolder
import no.nordicsemi.dfu.view.DFUViewEvent
import javax.inject.Inject
@HiltViewModel
internal class DFUViewModel @Inject constructor(
private val dataHolder: DFUDataHolder
) : CloseableViewModel() {
val state = dataHolder.data
fun onEvent(event: DFUViewEvent) {
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="dfu_title">DFU</string>
</resources>

View File

@@ -0,0 +1,17 @@
package no.nordicsemi.dfu
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

View File

@@ -7,7 +7,6 @@ dependencyResolutionManagement {
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
mavenCentral() mavenCentral()
mavenLocal() mavenLocal()
jcenter() // Warning: this repository is going to shut down soon
} }
versionCatalogs { versionCatalogs {
@@ -17,6 +16,7 @@ dependencyResolutionManagement {
alias('nordic-log').to('no.nordicsemi.android:log:2.3.0') alias('nordic-log').to('no.nordicsemi.android:log:2.3.0')
alias('nordic-scanner').to('no.nordicsemi.android.support.v18:scanner:1.5.0') alias('nordic-scanner').to('no.nordicsemi.android.support.v18:scanner:1.5.0')
alias('nordic-ui-scanner').to('no.nordicsemi.android.common:scanner:1.0.0') alias('nordic-ui-scanner').to('no.nordicsemi.android.common:scanner:1.0.0')
alias('nordic-dfu').to('no.nordicsemi.android:dfu:1.12.1-beta01')
alias('localbroadcastmanager').to('androidx.localbroadcastmanager:localbroadcastmanager:1.0.0') alias('localbroadcastmanager').to('androidx.localbroadcastmanager:localbroadcastmanager:1.0.0')
alias('material').to('com.google.android.material:material:1.5.0-beta01') alias('material').to('com.google.android.material:material:1.5.0-beta01')
@@ -95,3 +95,4 @@ if (file('../Android-Common-Libraries').exists()) {
// includeBuild('../Android-Scanner-Compat-Library') // includeBuild('../Android-Scanner-Compat-Library')
//} //}
include ':profile_uart' include ':profile_uart'
include ':profile_dfu'