diff --git a/profile_dfu/build.gradle b/profile_dfu/build.gradle
new file mode 100644
index 00000000..1e223cb2
--- /dev/null
+++ b/profile_dfu/build.gradle
@@ -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
+}
diff --git a/profile_dfu/src/androidTest/java/no/nordicsemi/dfu/ExampleInstrumentedTest.kt b/profile_dfu/src/androidTest/java/no/nordicsemi/dfu/ExampleInstrumentedTest.kt
new file mode 100644
index 00000000..9e50f754
--- /dev/null
+++ b/profile_dfu/src/androidTest/java/no/nordicsemi/dfu/ExampleInstrumentedTest.kt
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/profile_dfu/src/main/AndroidManifest.xml b/profile_dfu/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..47115554
--- /dev/null
+++ b/profile_dfu/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/data/DFUData.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/data/DFUData.kt
new file mode 100644
index 00000000..eb8ba2a3
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/data/DFUData.kt
@@ -0,0 +1,4 @@
+package no.nordicsemi.dfu.data
+
+class DFUData {
+}
\ No newline at end of file
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/data/DFUDataHolder.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/data/DFUDataHolder.kt
new file mode 100644
index 00000000..cbe95f47
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/data/DFUDataHolder.kt
@@ -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 = _data
+
+
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/repository/DFUService.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/repository/DFUService.kt
new file mode 100644
index 00000000..634c8a73
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/repository/DFUService.kt
@@ -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? {
+ /*
+ * 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
+ }
+}
\ No newline at end of file
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUContentView.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUContentView.kt
new file mode 100644
index 00000000..b0d0df2f
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUContentView.kt
@@ -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) {
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUErrorView.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUErrorView.kt
new file mode 100644
index 00000000..911c5167
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUErrorView.kt
@@ -0,0 +1,7 @@
+package no.nordicsemi.dfu.view
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun DFUErrorView() {
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUInstallingView.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUInstallingView.kt
new file mode 100644
index 00000000..c3161e33
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUInstallingView.kt
@@ -0,0 +1,7 @@
+package no.nordicsemi.dfu.view
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun DFUInstallingView() {
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUScreen.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUScreen.kt
new file mode 100644
index 00000000..f657d6c8
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUScreen.kt
@@ -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) }
+ }
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUSelectFileView.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUSelectFileView.kt
new file mode 100644
index 00000000..6992f962
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUSelectFileView.kt
@@ -0,0 +1,7 @@
+package no.nordicsemi.dfu.view
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun DFUSelectFileView() {
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUSuccessView.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUSuccessView.kt
new file mode 100644
index 00000000..d8277efe
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUSuccessView.kt
@@ -0,0 +1,7 @@
+package no.nordicsemi.dfu.view
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun DFUSuccessView() {
+}
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUViewEvent.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUViewEvent.kt
new file mode 100644
index 00000000..56cb09e4
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/DFUViewEvent.kt
@@ -0,0 +1,5 @@
+package no.nordicsemi.dfu.view
+
+internal sealed class DFUViewEvent
+
+internal object OnDisconnectButtonClick : DFUViewEvent()
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/view/NotificationActivity.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/NotificationActivity.kt
new file mode 100644
index 00000000..207d4370
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/view/NotificationActivity.kt
@@ -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(parentIntent, startAppIntent))
+ }
+
+ // Now finish, which will drop the user in to the activity that was at the top
+ // of the task stack
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/profile_dfu/src/main/java/no/nordicsemi/dfu/viewmodel/DFUViewModel.kt b/profile_dfu/src/main/java/no/nordicsemi/dfu/viewmodel/DFUViewModel.kt
new file mode 100644
index 00000000..03491672
--- /dev/null
+++ b/profile_dfu/src/main/java/no/nordicsemi/dfu/viewmodel/DFUViewModel.kt
@@ -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) {
+
+ }
+}
diff --git a/profile_dfu/src/main/res/values/strings.xml b/profile_dfu/src/main/res/values/strings.xml
new file mode 100644
index 00000000..287bafd3
--- /dev/null
+++ b/profile_dfu/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ DFU
+
\ No newline at end of file
diff --git a/profile_dfu/src/test/java/no/nordicsemi/dfu/ExampleUnitTest.kt b/profile_dfu/src/test/java/no/nordicsemi/dfu/ExampleUnitTest.kt
new file mode 100644
index 00000000..d48fc46b
--- /dev/null
+++ b/profile_dfu/src/test/java/no/nordicsemi/dfu/ExampleUnitTest.kt
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index df157373..aff91c5a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -7,7 +7,6 @@ dependencyResolutionManagement {
maven { url 'https://jitpack.io' }
mavenCentral()
mavenLocal()
- jcenter() // Warning: this repository is going to shut down soon
}
versionCatalogs {
@@ -17,6 +16,7 @@ dependencyResolutionManagement {
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-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('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')
//}
include ':profile_uart'
+include ':profile_dfu'