diff --git a/.gitignore b/.gitignore
index 124379e..618ac91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
/local.properties
/.gradle/
+/.kotlin/
+build/
/.idea/
/app/*.json
/wear/*.json
+/.codebase-memory/
diff --git a/CountDownDialog/.gitignore b/CountDownDialog/.gitignore
deleted file mode 100644
index 42afabf..0000000
--- a/CountDownDialog/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
\ No newline at end of file
diff --git a/CountDownDialog/build.gradle b/CountDownDialog/build.gradle
deleted file mode 100644
index 0250bd2..0000000
--- a/CountDownDialog/build.gradle
+++ /dev/null
@@ -1,50 +0,0 @@
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-
-android {
- compileSdk 34
-
- defaultConfig {
- minSdkVersion 19
- targetSdkVersion 34
- multiDexEnabled true
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles "consumer-rules.pro"
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- nfrelease{
- initWith release
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- }
- kotlinOptions {
- jvmTarget = JavaVersion.VERSION_17
- }
- namespace 'com.motionapps.countdowndialog'
-}
-
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation "androidx.multidex:multidex:2.0.1"
- implementation 'androidx.core:core-ktx:1.12.0'
- implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- implementation 'com.google.android.material:material:1.11.0'
- implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
- implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
- implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
- implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
- implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.5'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
-
-}
\ No newline at end of file
diff --git a/CountDownDialog/consumer-rules.pro b/CountDownDialog/consumer-rules.pro
deleted file mode 100644
index e69de29..0000000
diff --git a/CountDownDialog/proguard-rules.pro b/CountDownDialog/proguard-rules.pro
deleted file mode 100644
index 481bb43..0000000
--- a/CountDownDialog/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/CountDownDialog/src/androidTest/java/com/motionapps/countdowndialog/ExampleInstrumentedTest.kt b/CountDownDialog/src/androidTest/java/com/motionapps/countdowndialog/ExampleInstrumentedTest.kt
deleted file mode 100644
index d53581a..0000000
--- a/CountDownDialog/src/androidTest/java/com/motionapps/countdowndialog/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.motionapps.countdowndialog
-
-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("com.motionapps.countdowndialog.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/CountDownDialog/src/main/AndroidManifest.xml b/CountDownDialog/src/main/AndroidManifest.xml
deleted file mode 100644
index 5e7166c..0000000
--- a/CountDownDialog/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownDialog.kt b/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownDialog.kt
deleted file mode 100644
index f4eea81..0000000
--- a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownDialog.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.motionapps.countdowndialog
-
-import android.app.Dialog
-import android.content.Context
-import android.os.Bundle
-import android.view.Window
-
-/**
- * Dialog composes of textView, where the seconds left are shown
- * CountDown can be canceled by cancel button in the dialog
- * @param context
- */
-class CountDownDialog(context: Context) : Dialog(context) {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- requestWindowFeature(Window.FEATURE_NO_TITLE)
- window?.setBackgroundDrawableResource(android.R.color.transparent)
- setContentView(R.layout.countdown_timer)
- setCancelable(false)
- setCanceledOnTouchOutside(false)
- }
-}
diff --git a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownInterface.kt b/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownInterface.kt
deleted file mode 100644
index 2974cf5..0000000
--- a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownInterface.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.motionapps.countdowndialog
-
-/**
- * interface for the other components to implement
- * refresh interval is 100 ms, but only whole seconds are passed
- */
-interface CountDownInterface {
- fun onTick(seconds: String)
- fun onCountDownEnd()
-}
\ No newline at end of file
diff --git a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownMain.kt b/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownMain.kt
deleted file mode 100644
index 31da3c8..0000000
--- a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownMain.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.motionapps.countdowndialog
-
-import android.app.Dialog
-import android.content.Context
-import android.media.MediaPlayer
-import android.os.CountDownTimer
-
-/**
- * Uses native CountDownTimer of the Android
- * Refresh rate is 100 ms, but whole seconds are formatted as String
- */
-class CountDownMain {
-
-
- private var countDownInterface: CountDownInterface? = null
-
- // tones can be added
- var mediaPlayerBeep: MediaPlayer? = null
- var mediaPlayerStart: MediaPlayer? = null
-
- private var timer: Timer? = null
- private var playedFirst = false
- private var playedSecond = false
- var running: Boolean = false
- var playing: Boolean = false
-
- /**
- * Start of CountDown - dialog is not returned, as this component can be used for internal
- * functionality too
- * To use dialog, create one by method and update it through interface updates
- *
- * @param countDownInterface
- * @param interval - in seconds
- */
- fun startCountDown(countDownInterface: CountDownInterface, interval: Int){
- running = true
- this.countDownInterface = countDownInterface
- timer = Timer(interval.toLong(), 100L)
- timer?.start()
- }
-
-
- private inner class Timer constructor(interval: Long, tick: Long): CountDownTimer(interval * 1000L, tick) {
-
-
- override fun onFinish() {
-
- running = false
-
- mediaPlayerStart?.start()
- playing = true
-
- countDownInterface?.onCountDownEnd()
- mediaPlayerStart?.setOnCompletionListener {
- playing = false
- onDestroy()
- }
- }
-
- override fun onTick(millis: Long) {
- countDownInterface?.onTick("%d s".format((millis / 1000).toInt()))
- when {
- millis <= 2000 && !playedFirst -> { // peep soudn to create on 2 and 1 second
- mediaPlayerBeep?.start()
- playedFirst = true
- }
- millis <= 1000 && !playedSecond -> {
- mediaPlayerBeep?.start()
- playedSecond = true
- }
- }
- }
- }
-
- fun cancel(){
- timer?.cancel()
- playedFirst = false
- playedSecond = false
- running = false
- }
-
-
- fun onDestroy(){
- if(!playing){
- cancel()
- }
- }
-
- fun getDialog(context: Context): Dialog{
- return CountDownDialog(context)
- }
-
-}
\ No newline at end of file
diff --git a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownStates.kt b/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownStates.kt
deleted file mode 100644
index 5805d12..0000000
--- a/CountDownDialog/src/main/java/com/motionapps/countdowndialog/CountDownStates.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.motionapps.countdowndialog
-
-/**
- * CountDown states, which can be used for own use
- *
- */
-sealed class CountDownStates {
-
- class OnTick(val tick: String): CountDownStates()
- object OnCancel: CountDownStates()
- object OnNothing: CountDownStates()
- object OnFinish: CountDownStates()
-
-}
\ No newline at end of file
diff --git a/CountDownDialog/src/main/res/drawable/rounded_button.xml b/CountDownDialog/src/main/res/drawable/rounded_button.xml
deleted file mode 100644
index 61fb31a..0000000
--- a/CountDownDialog/src/main/res/drawable/rounded_button.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CountDownDialog/src/main/res/drawable/rounded_white.xml b/CountDownDialog/src/main/res/drawable/rounded_white.xml
deleted file mode 100644
index 4d1887b..0000000
--- a/CountDownDialog/src/main/res/drawable/rounded_white.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/CountDownDialog/src/main/res/layout/countdown_timer.xml b/CountDownDialog/src/main/res/layout/countdown_timer.xml
deleted file mode 100644
index e58312c..0000000
--- a/CountDownDialog/src/main/res/layout/countdown_timer.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CountDownDialog/src/main/res/values/colors.xml b/CountDownDialog/src/main/res/values/colors.xml
deleted file mode 100644
index 8179bc8..0000000
--- a/CountDownDialog/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- #000000
- #FFFFFF
-
\ No newline at end of file
diff --git a/CountDownDialog/src/main/res/values/strings.xml b/CountDownDialog/src/main/res/values/strings.xml
deleted file mode 100644
index d5a878f..0000000
--- a/CountDownDialog/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- Cancel
-
\ No newline at end of file
diff --git a/CountDownDialog/src/test/java/com/motionapps/countdowndialog/ExampleUnitTest.kt b/CountDownDialog/src/test/java/com/motionapps/countdowndialog/ExampleUnitTest.kt
deleted file mode 100644
index d28d04a..0000000
--- a/CountDownDialog/src/test/java/com/motionapps/countdowndialog/ExampleUnitTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.motionapps.countdowndialog
-
-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/README.md b/README.md
index dc5a2de..9629b45 100644
--- a/README.md
+++ b/README.md
@@ -1,88 +1,125 @@
-# SensorBox - record all your sensors to csv files
-
-This repository is now archived and will no longer be actively maintained.
-
-
-
-
-
-
-
-
-
-The SensorBox provides easy way to access sensors in Android phone and Wear Os. You can customize measurements in many ways, which is suitable for development of other apps. The outputs of the app are raw outputs of the system.
-
-[](https://android-arsenal.com/api?level=24)
-[](https://opensource.org/licenses/Apache-2.0)
-
-## Features:
-
-Whole functionality is hidden under SensorServices library, where one foreground service operates with sensors, GPS and other APIs.
-
-* stores **sensor outputs** into the csv: *timestamp, values, accuracy*
-* values from the sensors are in raw format - **no resampling**
-* pick native sensor speed limits
-* compatible with **GPS**
-* can use **Activity recognition API from Android** and **Significant motion sensor**
-* write custom annotation during measurement
-* all extra information are stored in **JSON**
-* check sensor attributes and preview of the outputs
-* measurement can be customized :
- * write own key words to measurement
- * set up timed alarms
- * set up countdown to start measurement
- * stop on low battery measurement
- * lock CPU, add app to whitelist
-* compatible with **Wear Os** with similar features
-
-## Organization of code and the libraries:
-
-### Code
-* whole code is in **Kotlin** (Flipper - third party - code is in Java)
-* the phone app follows **MVI architecture** - activity/fragment -> ViewModel -> repository
- * There are 2 activities created with this architecture :
- * **MainActivity** - created with other fragments like HomeFragment, AdvancedFragment, SettingsFragment, ... - these **fragments share one ViewModel** defined by MainActivity. Meanwhile for the navigation is used androidx fragment navigation library.
- * **MeasurementActivity** - alone activity to create annotations / stop the measurement if it is proceeding - **has its own ViewModel**
-* In the phone application is used **Hilt - dependency injection library**
-* **The phone app and the Wear Os app use the same SensorService Library** which covers all the requirements from the apps. The library provides intents builders for both of them.
-* **WearOsLib** provides easy and comprehensive code of how to find other device and send messages, send file between them.
-
-
-### Libraries:
-
-* **app / wear** - implementation for the phone / wearable respectively
-* **CountDownDialog** - library for creation of the countdowns, with interaface to interact and custom Dialog
-* **Flipper** - [Storage access framework](https://github.com/baldapps/Flipper) created by [baldapps](https://github.com/baldapps)
-* **Sensorservices** - main background service, which registers all the sensors and other providers of the data
-* **WearOsLib** - general library for communication of the phone and wearable and vice versa
-
-## How to build the project:
-
-* clone / download the project to your machine
-* to activate google services follow steps at **[Firebase](https://console.firebase.google.com/u/0/).** Create project and get the `google-services.json`
- * make sure, that the package id in app/wear build gradle is the same as in firebase console
-* `google-services.json` copy to the app folder and wear folder too
-* to activate Google maps, follow the steps here to create API key **[Google documentation](https://developers.google.com/maps/documentation/android-sdk/get-api-key#console)**
-* adding line to `local.properties`: **MAPS_API_KEY=YOUR_API_KEY** is enough
-
-
-## Third parties:
-
-Thanks goes to:
-
-* [GraphView](https://github.com/jjoe64/GraphView) - chart library
-[](https://opensource.org/licenses/Apache-2.0)
-* [Flipper](https://github.com/baldapps/Flipper) - storage access framework
-[](https://opensource.org/licenses/MIT)
-* [AppIntro](https://github.com/AppIntro/AppIntro) - introduction to the app for the first launch
-[](https://opensource.org/licenses/Apache-2.0)
-* [Material dialogs](https://github.com/afollestad/material-dialogs) - dialogs with material design style
-[](https://opensource.org/licenses/Apache-2.0)
-* [Number picker](https://github.com/ShawnLin013/NumberPicker) - create custom number pickers
-[](https://opensource.org/licenses/MIT)
-* [Android about page](https://github.com/medyo/android-about-page) - easy way to create about page
-[](https://opensource.org/licenses/MIT)
-* [Licenses dialog](https://github.com/PSDev/LicensesDialog) - dialog to aggreate all licences - check out for the full licenses
-[](https://opensource.org/licenses/Apache-2.0)
-* [Toasty](https://github.com/GrenderG/Toasty) - The usual Toast, but with steroids 💪
-[](https://www.gnu.org/licenses/gpl-3.0)
+# SensorBox
+
+SensorBox records raw Android and Wear OS sensor samples to local CSV files. The phone app uses Android's system folder picker; recordings never require cloud storage or an account.
+
+This is the hard-cut Android 17 generation of the project. It does not retain the former Fragment/XML UI, `SharedPreferences`, Firebase, Maps, or compatibility migrations for old settings.
+
+## Screenshots
+
+| Sensor selection | Measurement setup |
+|:---:|:---:|
+|
|
|
+
+| Wear dashboard | Wear live-sensor picker |
+|:---:|:---:|
+|
|
|
+
+### First-run introduction
+
+| Welcome | Local data | Privacy and terms |
+|:---:|:---:|:---:|
+|
|
|
|
+
+| Android lifecycle | Battery optimization | Recording folder |
+|:---:|:---:|:---:|
+|
|
|
|
+
+The introduction uses the original repository artwork. Privacy Policy, Terms of Use, battery optimization, and folder selection are live native actions. Folder selection remains mandatory before setup can finish.
+
+## Current feature set
+
+- Record available phone or watch sensors at Android sampling periods.
+- Record foreground GPS samples alongside sensor data.
+- Run measurement work in an explicit foreground service with health/location service types.
+- Stop safely from the app, watch, notification, low-battery policy, or a paired-device command.
+- Preview a live watch sensor with a Compose-native chart.
+- Stream watch recordings to the phone with the Wear OS Channel API.
+- Store phone recordings in a user-selected Storage Access Framework folder.
+- Follow system/dynamic color with light, dark, and custom fallback palettes.
+
+## Architecture
+
+The UI modules use unidirectional MVI:
+
+`Composable → Intent → ViewModel → use case → repository/service → State + Effect`
+
+UI launchers execute one-shot effects, while decisions and state transitions remain in workflow-owned ViewModels, reducers, and focused use cases. The phone shell owns navigation only. Hilt provides production dependencies and interfaces keep platform boundaries replaceable in tests.
+
+Modules:
+
+- `app`: phone Compose UI, workflow-owned MVI, paired-recording policy, permissions, and received watch files.
+- `wear`: Wear Compose Material 3 UI, MVI, live charts, recording, and phone launch flow.
+- `core-common`: platform-neutral `AppResult`, stable application errors, and diagnostics contracts.
+- `recording-core`: pure Kotlin recording state machine, source roles, scheduling, and cleanup policy.
+- `core`: Android DataStore preferences, document storage, local rotating diagnostics, and reusable test fixtures.
+- `sensorservices`: Android recording adapters, foreground host, and linear sensor/GPS writers. It has no Wear dependency.
+- `WearOsLib`: coroutine-based connectivity, strict protocol v2 command encoding, and Channel file transport. App policy stays in `app` and `wear`.
+
+Paired phone/watch recording is all-or-nothing: both sides prepare before either commits, commands are session-correlated and idempotent, timeouts use bounded retries, and rejection or timeout compensates both sides.
+
+## Platform and toolchain
+
+- Android Gradle Plugin 9.3.1 and Gradle 9.7
+- Android compile/target SDK 37 (Android 17)
+- Java 17 and Kotlin 2.4.10
+- Jetpack Compose Material 3 and Wear Compose Material 3
+- Hilt 2.60.1
+- DataStore Preferences 1.2.1
+- Detekt 2 with formatting rules and no baselines
+
+Every Kotlin function is checked at a maximum of 40 lines. Compose functions therefore also stay below the requested 60-line ceiling.
+
+## Build and quality checks
+
+Install JDK 17 and Android SDK 37, then run:
+
+```shell
+./gradlew :app:assembleDebug :wear:assembleDebug
+./gradlew testDebugUnitTest detekt
+./gradlew :app:lintDebug :wear:lintDebug
+```
+
+Instrumentation test sources can be compiled without a device:
+
+```shell
+./gradlew :app:compileDebugAndroidTestKotlin :wear:compileDebugAndroidTestKotlin
+```
+
+Tests use Given/When/Then naming, reusable state/repository fixtures, coroutine test contexts, and Compose robots for end-to-end UI interactions.
+
+## Emulator integration tests
+
+The phone sensor test starts the real foreground measurement service, injects three accelerometer values through the emulator console, and verifies the generated CSV:
+
+```shell
+ANDROID_HOME="$HOME/Library/Android/sdk" \
+PHONE_SERIAL=emulator-5554 \
+tools/emulator/run_phone_sensor_test.sh
+```
+
+The Wear sync test sends a fixture CSV through the real Wear OS Channel API and verifies its exact bytes on the phone. Use an Android 17 Google Play phone AVD and a Wear OS 7 AVD. Pair them once with Android Studio's Pairing Assistant and complete the Wear companion flow before running:
+
+```shell
+ANDROID_HOME="$HOME/Library/Android/sdk" \
+PHONE_SERIAL=emulator-5554 \
+WEAR_SERIAL=emulator-5556 \
+tools/emulator/run_wear_sync_test.sh
+```
+
+The runner creates Android Studio's ADB forward/reverse bridge and fails immediately with pairing guidance when the watch reports no peer. Received files use app-internal storage only in debuggable builds; release builds continue to require the user-selected Storage Access Framework directory.
+
+No Firebase project, Maps key, secrets file, or external storage permission is required.
+
+## Dependencies
+
+The former Flipper, AppIntro, Material Dialogs, NumberPicker, Android About Page, LicensesDialog, Toasty, GraphView, and custom countdown modules have been removed. Their replacements are native APIs or small project-owned Compose components.
+
+[Vico](https://github.com/patrykandpatrick/vico) is retained as the sole feature-level third-party UI library because it provides a maintained, Compose-native chart model and renderer suitable for the live Wear OS plot. AndroidX, Google Play services for Wear/location, Kotlin coroutines, Hilt, and Detekt remain infrastructure dependencies.
+
+## Privacy
+
+Measurements are initiated by the user, represented by an ongoing foreground-service notification, and written locally. SensorBox does not upload measurement data or include analytics/crash-reporting SDKs.
+
+## License
+
+SensorBox is licensed under the Apache License 2.0. See [LICENSE](LICENSE).
diff --git a/WearOsLib/build.gradle b/WearOsLib/build.gradle
deleted file mode 100644
index 31d87e6..0000000
--- a/WearOsLib/build.gradle
+++ /dev/null
@@ -1,52 +0,0 @@
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-
-android {
- compileSdk 34
-
- defaultConfig {
- minSdkVersion 24
- targetSdkVersion 34
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles "consumer-rules.pro"
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- nfrelease{
- initWith debug
- }
- }
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- }
- kotlinOptions {
- jvmTarget = JavaVersion.VERSION_17
- }
- namespace 'com.motionapps.wearoslib'
-}
-
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation project(path: ':flipper')
-
- implementation 'androidx.preference:preference-ktx:1.2.1'
- implementation 'androidx.core:core-ktx:1.10.1'
- implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.5'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
-
- implementation 'com.google.android.gms:play-services-wearable:18.1.0'
- implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
-
- implementation 'com.github.GrenderG:Toasty:1.5.2'
-}
\ No newline at end of file
diff --git a/WearOsLib/build.gradle.kts b/WearOsLib/build.gradle.kts
new file mode 100644
index 0000000..4100136
--- /dev/null
+++ b/WearOsLib/build.gradle.kts
@@ -0,0 +1,58 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.detekt)
+ alias(libs.plugins.hilt)
+ alias(libs.plugins.ksp)
+}
+
+android {
+ namespace = "com.motionapps.wearoslib"
+ compileSdk = 37
+
+ defaultConfig {
+ minSdk = 24
+ consumerProguardFiles("consumer-rules.pro")
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro",
+ )
+ }
+ create("nfrelease") {
+ initWith(getByName("release"))
+ matchingFallbacks += "release"
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ testFixtures {
+ enable = true
+ }
+}
+
+dependencies {
+ implementation(project(":core-common"))
+
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.play.services.wearable)
+ implementation(libs.coroutines.core)
+ implementation(libs.coroutines.play.services)
+ implementation(libs.hilt.android)
+ ksp(libs.hilt.compiler)
+ testImplementation(libs.junit)
+ testFixturesImplementation(project(":core-common"))
+ testFixturesImplementation(libs.coroutines.core)
+}
+
+hilt {
+ enableAggregatingTask = true
+}
diff --git a/WearOsLib/font/roboto_family.xml b/WearOsLib/font/roboto_family.xml
deleted file mode 100644
index 9e2ad54..0000000
--- a/WearOsLib/font/roboto_family.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/WearOsLib/font/roboto_regular.ttf b/WearOsLib/font/roboto_regular.ttf
deleted file mode 100644
index 2c97eea..0000000
Binary files a/WearOsLib/font/roboto_regular.ttf and /dev/null differ
diff --git a/WearOsLib/src/androidTest/java/com/motionapps/wearoslib/ExampleInstrumentedTest.kt b/WearOsLib/src/androidTest/java/com/motionapps/wearoslib/ExampleInstrumentedTest.kt
deleted file mode 100644
index 26ee3a2..0000000
--- a/WearOsLib/src/androidTest/java/com/motionapps/wearoslib/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.motionapps.wearoslib
-
-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("com.motionapps.wearoslib.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/WearOsLib/src/main/AndroidManifest.xml b/WearOsLib/src/main/AndroidManifest.xml
index e170676..cc947c5 100644
--- a/WearOsLib/src/main/AndroidManifest.xml
+++ b/WearOsLib/src/main/AndroidManifest.xml
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsConstants.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsConstants.kt
index e4c0abf..283f93a 100644
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsConstants.kt
+++ b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsConstants.kt
@@ -1,45 +1,8 @@
package com.motionapps.wearoslib
-/**
- * Constants, which are used by both sides at phone and
- */
object WearOsConstants {
-
- // these paths needs to be the same in manifest
- // also both of them needs XML file with these capabilities
const val PHONE_APP_CAPABILITY = "phone_app"
- const val PHONE_MESSAGE_PATH = "/com.motionapps.sensorbox.Activity" // in phone app
-
+ const val PHONE_MESSAGE_PATH = "/sensorbox/v2/phone"
const val WEAR_APP_CAPABILITY = "wear_app"
- const val WEAR_MESSAGE_PATH = "/com.motionapps.sensorbox.Sensors" // in wear app
-
- // basic messages to send
- const val WEAR_STATUS = "SEND_STATUS"
- const val WEAR_STATUS_EXTRA = "SEND_STATUS_EXTRA"
- const val WEAR_KILL_APP = "KILL_WEAR_APP"
- const val WEAR_SEND_PATHS = "WEAR_SEND_PATHS"
- const val WEAR_SEND_PATHS_EXTRA = "WEAR_SEND_PATHS_EXTRA"
- const val WEAR_SEND_FILE = "WEAR_SEND_FILE"
- const val WEAR_HEART_RATE_PERMISSION_REQUIRED = "HEART_RATE_PERMISSION"
- const val WEAR_HEART_RATE_PERMISSION_REQUIRED_BOOLEAN = "HEART_RATE_PERMISSION_BOOLEAN"
-
- const val START_MAIN_ACTIVITY = "START_MAIN_ACTIVITY"
- const val START_MEASUREMENT = "START_MEASUREMENT"
- const val STOP_SYNC = "STOP_SYNC"
- const val NUMBER_OF_FILES = "NUMBER_OF_FILES"
- const val DELETE_ALL_MEASUREMENTS = "DELETE_ALL_MEASUREMENTS"
- const val DELETE_FOLDER = "DELETE_FOLDER"
-
- // Realtime broadcasting of samples to chart
- const val WEAR_START_SENSOR_REAL_TIME = "START_WEAR_SENSOR_REAL_TIME"
- const val WEAR_END_SENSOR_REAL_TIME = "END_WEAR_SENSOR_REAL_TIME"
- const val WEAR_SEND_SENSOR_INFO = "SEND_WEAR_SENSOR_INFO"
- const val WEAR_SEND_SENSOR_INFO_EXTRA = "SEND_WEAR_SENSOR_INFO_EXTRA"
-
- // to send sample from sensor
- const val SAMPLE_PATH = "/com.motionapps.sensorbox."
- const val SAMPLE_PATH_VALUE = "/com.motionapps.sensorbox.sample."
- const val SAMPLE_PATH_TIME = "/com.motionapps.sensorbox.sample.time"
- const val FILE_TO_TRANSFER_PATH = "/com.motionapps.sensorbox.file_to_transfer"
-
-}
\ No newline at end of file
+ const val WEAR_MESSAGE_PATH = "/sensorbox/v2/wear"
+}
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsHandler.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsHandler.kt
deleted file mode 100644
index 7546a62..0000000
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsHandler.kt
+++ /dev/null
@@ -1,247 +0,0 @@
-package com.motionapps.wearoslib
-
-import android.content.Context
-import android.util.Log
-import com.google.android.gms.tasks.Tasks
-import com.google.android.gms.wearable.CapabilityClient
-import com.google.android.gms.wearable.CapabilityClient.OnCapabilityChangedListener
-import com.google.android.gms.wearable.CapabilityInfo
-import com.google.android.gms.wearable.Node
-import com.google.android.gms.wearable.Wearable
-import es.dmoral.toasty.Toasty
-import kotlinx.coroutines.*
-import java.lang.Exception
-import java.util.concurrent.ExecutionException
-
-/**
- * Background to search for the Wear Os and send messages
- *
- */
-class WearOsHandler {
-
- var nodeId: String? = null
- private var capability: String? = null
- private var msg: String = ""
- private var wearOsListener: WearOsListener? = null
-
- /**
- * Tries to find Node by which, the messages can be sent
- *
- * @param context
- * @param wearOsListener - object to which the response will be sent
- * @param capability - Wearable or phone capability from XML
- */
- suspend fun searchForWearOs(
- context: Context,
- wearOsListener: WearOsListener,
- capability: String
- ): String? {
- val client = Wearable.getCapabilityClient(context)
- this.wearOsListener = wearOsListener
- this.capability = capability
- try {
- val result = runCatching {
- val foundId: String? = searchForNode(client)
- setupListener(client)
- return@runCatching foundId
- }
- if(result.isFailure){
- result.exceptionOrNull()?.printStackTrace()
- wearOsListener.onWearOsStates(WearOsStates.PresenceResult(false))
- }else{
- return result.getOrNull()
- }
- } catch (e: ExecutionException) {
- e.printStackTrace()
- wearOsListener.onWearOsStates(WearOsStates.PresenceResult(false))
- } catch (e: InterruptedException) {
- e.printStackTrace()
- wearOsListener.onWearOsStates(WearOsStates.PresenceResult(false))
- }
- return null
- }
-
- /**
- * Uses RunBlocking to send message - avoid to put it into UI thread of the activity
- *
- * @param context
- * @param capability - Wearable or phone capability from XML
- * @param path - path to use to send message
- * @param msg - string of the message
- * @return
- */
- fun sendMessageInstant(
- context: Context,
- capability: String,
- path: String,
- msg: String
- ): Boolean {
- val client = Wearable.getCapabilityClient(context)
- this.capability = capability
- this.msg = msg
- return runBlocking {
- try {
- val nodeId = searchForNode(client)
- if (nodeId != null) {
- sendMsg(context, path, msg)
- }
- return@runBlocking nodeId != null
- } catch (e: ExecutionException) {
- e.printStackTrace()
- } catch (e: InterruptedException) {
- e.printStackTrace()
- }
- return@runBlocking false
- }
- }
-
- /**
- * Uses RunBlocking to get nodeId
- *
- * @param context
- * @return
- */
- fun getNodeId(
- context: Context
- ): String? {
- val client = Wearable.getCapabilityClient(context)
- return runBlocking {
- try {
- return@runBlocking searchForNode(client)
- } catch (e: Exception) {
- return@runBlocking null
- }
- }
- }
-
-
-
- /**
- * Searches for the node in asynchronous call - need to wait for the result
- *
- * @param client
- * @return
- */
- @Throws(ExecutionException::class, InterruptedException::class)
- private suspend fun searchForNode(client: CapabilityClient): String? {
- return withContext(Dispatchers.IO) {
- val j = async { getCapabilities(client) } // searching for wear nodes
- j.await()?.let {
- // update nodeId
- return@withContext updateCapability(it)
- } ?: run {
- // no node
- wearOsListener?.onWearOsStates(WearOsStates.PresenceResult(false))
- return@withContext null
- }
- }
-
-
- }
-
- /**
- * @param client
- * @return list of nodes
- */
- private fun getCapabilities(client: CapabilityClient): CapabilityInfo? {
- return try {
- Tasks.await(client.getCapability(capability!!, CapabilityClient.FILTER_REACHABLE))
- } catch (e: Exception) {
- e.printStackTrace()
- null
- }
-
- }
-
- /**
- * Listens to changes of nodes -> sends them by callback
- *
- * @param client
- */
- private fun setupListener(client: CapabilityClient) {
- val capabilityListener = OnCapabilityChangedListener { capabilityInfo: CapabilityInfo ->
- CoroutineScope(Dispatchers.Main).launch {
- updateCapability(capabilityInfo)
- wearOsListener?.onWearOsStates(WearOsStates.PresenceResult(isNode))
- }
- }
- client.addListener(
- capabilityListener,
- capability!!
- )
- }
-
- /**
- * search for viable node to send info to connect
- * @param capabilityInfo - output of the WearableClient
- */
- private suspend fun updateCapability(capabilityInfo: CapabilityInfo): String? {
- val connectedNodes = capabilityInfo.nodes
- nodeId = pickBestNodeId(connectedNodes)
- if (nodeId == "") {
- wearOsListener?.onWearOsStates(WearOsStates.PresenceResult(false))
- } else { // broadcasting to first node which is available
- wearOsListener?.onWearOsStates(WearOsStates.PresenceResult(true))
- }
- return nodeId
- }
-
- /**
- * Find a nearby node or pick one arbitrarily
- *
- * @param nodes - list of available nodes
- * @return
- */
- private fun pickBestNodeId(nodes: Set): String {
- var bestNodeId = ""
-
- for (node in nodes) {
- if (node.isNearby) {
- return node.id
- }
- bestNodeId = node.id
- }
- return bestNodeId
- }
-
- val isNode: Boolean
- get() = nodeId != null && nodeId != ""
-
- /**
- * Sends message via nodeId to Wearable device
- *
- * @param context
- * @param path - to use for device
- * @param msg - to send
- * @param silent - true - if the error occurs, the Toast is raised to user
- */
- fun sendMsg(context: Context, path: String, msg: String, silent: Boolean = false) {
- nodeId?.let { nodeString ->
- val sendTask =
- Wearable.getMessageClient(context).sendMessage(nodeString, path, msg.toByteArray())
- sendTask.addOnSuccessListener {
- Log.i(TAG, "sendMsg: Successful $msg")
- }
- sendTask.addOnFailureListener {
- if (silent) {
- Toasty.error(
- context,
- R.string.sync_failed_restart,
- Toasty.LENGTH_SHORT,
- true
- ).show()
- }
- it.printStackTrace()
- }
- }
-
- }
-
- fun onDestroy(){
- wearOsListener = null
- }
-
- companion object {
- private const val TAG = "WEAR"
- }
-}
\ No newline at end of file
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsListener.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsListener.kt
deleted file mode 100644
index cd611c2..0000000
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsListener.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.motionapps.wearoslib
-
-interface WearOsListener {
-
- suspend fun onWearOsStates(wearOsStates: WearOsStates)
-
-}
\ No newline at end of file
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsNotify.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsNotify.kt
deleted file mode 100644
index 38157d1..0000000
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsNotify.kt
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.motionapps.wearoslib
-
-import android.annotation.SuppressLint
-import android.app.Notification
-import android.app.NotificationChannel
-import android.app.NotificationManager
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.os.Build
-import androidx.core.app.NotificationCompat
-import androidx.core.content.ContextCompat
-import com.motionapps.wearoslib.WearOsConstants.STOP_SYNC
-
-/**
- * Functions to create and update notifications connected with Wear Os device
- */
-object WearOsNotify {
-
- private const val CHANNEL_ID = "sensorBoxId"
- private const val CHANNEL_NAME = "SensorBoxChannel"
-
- /**
- * notification for the synchronization between phone and wearable
- * creates channel and notification -
- *
- * @param context
- * @param count - number of files to move
- * @param progress - actual number of files
- * @param importance - importance
- * @return - built notification
- */
- @SuppressLint("UnspecifiedImmutableFlag")
- fun createProgressNotification(
- context: Context,
- count: Int,
- progress: Int,
- importance: Int
- ): Notification {
- createChannel(context)
- val builder = NotificationCompat.Builder(
- context,
- CHANNEL_ID
- )
- // it is ongoing notification for service
- builder.setAutoCancel(false)
- builder.setOngoing(true)
- builder.setOnlyAlertOnce(true)
- builder.setProgress(count, progress, false)
- builder.setContentTitle(context.getString(R.string.wear_os_sync_data))
-
- // importance
- builder.priority = importance
- builder.setCategory(Notification.CATEGORY_SERVICE)
-
- // button to stop sync
- builder.setSmallIcon(R.drawable.ic_graph)
- builder.color = ContextCompat.getColor(context, R.color.black_color)
- val stopIntent = Intent(STOP_SYNC)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- builder.addAction(
- R.drawable.ic_baseline_stop,
- context.getString(R.string.text_stop),
- PendingIntent.getBroadcast(
- context,
- 25, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- )
- }else{
- builder.addAction(
- R.drawable.ic_baseline_stop,
- context.getString(R.string.text_stop),
- PendingIntent.getBroadcast(
- context,
- 25, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT
- )
- )
- }
- return builder.build()
- }
-
- /**
- * updates notification by id
- *
- * @param context
- * @param id - id of the notification
- * @param notification - built notification
- */
- fun updateNotification(context: Context, id: Int, notification: Notification) {
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- notificationManager.notify(id, notification)
- }
-
- /**
- * cancels notification by id
- *
- * @param context
- * @param id - of the notification
- */
- fun cancelNotification(context: Context, id: Int) {
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- notificationManager.cancel(id)
- }
-
- /**
- * creates notification channel for the Oreo and higher of the Android
- *
- * @param context
- */
- private fun createChannel(context: Context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- val notificationChannel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)
- val notificationManager = context.getSystemService(NotificationManager::class.java)
- notificationManager?.createNotificationChannel(notificationChannel)
- }
- }
-
-}
\ No newline at end of file
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsStates.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsStates.kt
deleted file mode 100644
index 0a75a26..0000000
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsStates.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.motionapps.wearoslib
-
-sealed class WearOsStates {
- class PresenceResult(val present: Boolean): WearOsStates() // if the Wear Os is present
- // Memory status
- class Status(val running: Boolean, val measurementsToSync: Int, val sizeOfData: Double, val totalNumberOfFiles: Int ): WearOsStates()
- // to turn off Wear Os
- object Offline: WearOsStates()
- // waiting for the result
- object AwaitResult: WearOsStates()
-}
\ No newline at end of file
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsStorageHandler.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsStorageHandler.kt
deleted file mode 100644
index 4668141..0000000
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsStorageHandler.kt
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.motionapps.wearoslib
-
-import android.content.Context
-import android.util.Log
-import com.balda.flipper.DocumentFileCompat
-import com.balda.flipper.StorageManagerCompat
-import java.io.*
-import java.nio.charset.StandardCharsets
-
-/**
- * Functions to store files
- */
-object WearOsStorageHandler {
-
- private const val TAG = "WearOsHandler"
-
- /**
- * InputStream is stored into specific folder
- *
- * @param context
- * @param inputStream - to store
- * @param mainFolderName - SensorBox in our case
- * @param folderName - folder of the measurement
- * @param fileName - name of the file, where the data will be stored
- */
- fun storeInputStream(
- context: Context,
- inputStream: InputStream,
- mainFolderName: String,
- folderName: String,
- fileName: String
- ) {
-
- // checks main folder
- if (!createFolderMeasurement(context, mainFolderName, folderName)) {
- Log.i(TAG, "$folderName exists")
- } else {
- Log.i(TAG, "$folderName was created")
- }
-
- val mime =
- when {
- ".txt" in folderName -> {
- "txt"
- }
- ".json" in folderName -> {
- "json"
- }
- else -> {
- "csv"
- }
- }
-
- // creates file
- createFileInFolder(
- context,
- mainFolderName,
- folderName,
- mime,
- "WEAR_$fileName"
- )?.let { outputStream ->
-
- // rewrites inputStream into OutputStream
- val bufferSize = 1024
- val buffer = CharArray(bufferSize)
- val reader: Reader = InputStreamReader(inputStream, StandardCharsets.UTF_8)
- while (reader.read(buffer) >= 0) {
- outputStream.write(buffer.concatToString().toByteArray())
- }
-
- outputStream.flush()
- outputStream.close()
- }
-
- inputStream.close()
- }
-
- /**
- * Creates measurement folder in main folder
- *
- * @param context
- * @param mainFolderName - SensorBox
- * @param folderName
- * @return - boolean if it was created
- */
- private fun createFolderMeasurement(
- context: Context,
- mainFolderName: String,
- folderName: String
- ): Boolean {
- val manager = StorageManagerCompat(context)
- val root = manager.getRoot(StorageManagerCompat.DEF_MAIN_ROOT) ?: return false // root access
- val f = root.toRootDirectory(context) ?: return false
- val subFolder = DocumentFileCompat.peekSubFolder(f, mainFolderName) ?: return false // find main folder
-
- if (DocumentFileCompat.peekSubFolder(
- subFolder,
- folderName
- ) == null
- ) { // create our measurement folder, if it does not exists
- subFolder.createDirectory(folderName)
- return true
- }
- return false
- }
-
- /**
- * Creates file into which the data will be stored
- * It also deletes file, if it exists
- * @param context
- * @param folderMain - SensorBox
- * @param folderName - ENDLESS_...
- * @param mimeOfNewFile - json, csv, txt, ...
- * @param nameOfNewFile - ACG.csv, ...
- * @return OutputStream, which can be used to store data
- */
- @Throws(IOException::class)
- private fun createFileInFolder(
- context: Context,
- folderMain: String,
- folderName: String,
- mimeOfNewFile: String,
- nameOfNewFile: String
- ): OutputStream? {
-
- val manager = StorageManagerCompat(context)
- val root = manager.getRoot(StorageManagerCompat.DEF_MAIN_ROOT) ?: return null // root access
- val f = root.toRootDirectory(context) ?: return null
- var subFolder = DocumentFileCompat.peekSubFolder(f, folderMain) // SensorBox folder
- if(subFolder == null || !subFolder.exists()){
- subFolder = f.createDirectory("SensorBox") ?: return null
- }
- var recordFolder = DocumentFileCompat.peekSubFolder(subFolder, folderName)// measurementFolder
- if(recordFolder == null || !recordFolder.exists()){
- recordFolder = f.createDirectory(folderName) ?: return null
- }
- recordFolder.findFile(nameOfNewFile)?.delete() // deletes previous stored data
- recordFolder.createFile(mimeOfNewFile, nameOfNewFile)?.let {
- return context.contentResolver.openOutputStream(it.uri) // creates new file
- }
-
- return null
- }
-}
\ No newline at end of file
diff --git a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsSyncDialog.kt b/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsSyncDialog.kt
deleted file mode 100644
index ff334f9..0000000
--- a/WearOsLib/src/main/java/com/motionapps/wearoslib/WearOsSyncDialog.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.motionapps.wearoslib
-
-import android.app.Dialog
-import android.content.Context
-import android.content.Intent
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
-import android.os.Bundle
-import android.view.ViewGroup
-import android.view.Window
-import android.widget.Button
-import android.widget.TextView
-import androidx.core.content.ContextCompat
-import com.motionapps.wearoslib.WearOsConstants.NUMBER_OF_FILES
-
-/**
- * Dialog to show basic info about data stored at Wear Os
- * Number of measurements, size of them
- *
- * @param context
- */
-class WearOsSyncDialog(context: Context): Dialog(context) {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- requestWindowFeature(Window.FEATURE_NO_TITLE)
- window?.setBackgroundDrawableResource(android.R.color.transparent)
- setContentView(R.layout.wearos_sync_dialog)
- }
-
-
- override fun onStart() {
- super.onStart()
- // to resize dialog to match parent in width
- window!!.setLayout(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
- }
-
- /**
- * After click on button, the SyncService will be started to transfer all the data
- *
- * @param status - data about storage
- */
- fun showStatus(status: WearOsStates.Status){
- show()
- findViewById(R.id.wear_os_sync_measurement_count)?.apply {
- text = status.measurementsToSync.toString()
- }
-
- findViewById(R.id.wear_os_sync_size_mb)?.apply{
- text = "%.3f MB".format(status.sizeOfData)
- }
-
- findViewById