A fork of Simple Time Tracker with WearOS support. (Now integrated upstream)
0

Configure Feed

Select the types of activity you want to include in your feed.

refactoring

razeeman (Mar 2, 2024, 10:57 AM +0300) b2a2dbeb f16c5a95

+198 -169
+19 -15
features/feature_wear/src/main/java/com/example/util/simpletimetracker/feature_wear/WearCommunicationInteractor.kt
··· 6 6 package com.example.util.simpletimetracker.feature_wear 7 7 8 8 import com.example.util.simpletimetracker.domain.extension.orZero 9 + import com.example.util.simpletimetracker.domain.interactor.AddRunningRecordMediator 9 10 import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor 10 11 import com.example.util.simpletimetracker.domain.interactor.RecordTagInteractor 11 12 import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor ··· 28 29 private val recordTagInteractor: RecordTagInteractor, 29 30 private val runningRecordInteractor: RunningRecordInteractor, 30 31 private val removeRunningRecordMediator: RemoveRunningRecordMediator, 32 + private val addRunningRecordMediator: AddRunningRecordMediator, 31 33 private val appColorMapper: AppColorMapper, 32 34 ) : WearCommunicationAPI { 33 35 ··· 56 58 } 57 59 } 58 60 59 - override suspend fun setCurrentActivities(activities: List<CurrentActivity>) { 60 - val currents = queryCurrentActivities() 61 - val unchanged = currents.filter { c -> activities.any { a -> a == c } } 62 - val stopped = currents.filter { c -> unchanged.none { u -> u == c } } 63 - val started = activities.filter { a -> currents.none { c -> a == c } } 64 - stopped.forEach { removeRunningRecordMediator.removeWithRecordAdd(asRunningRecord(it)) } 65 - started.forEach { runningRecordInteractor.add(asRunningRecord(it)) } 66 - } 61 + override suspend fun setCurrentActivities(starting: List<CurrentActivity>) { 62 + val currents = runningRecordInteractor.getAll() 63 + val currentsIds = runningRecordInteractor.getAll().map(RunningRecord::id) 64 + val startingIds = starting.map(CurrentActivity::id) 67 65 68 - private fun asRunningRecord(currentActivity: CurrentActivity): RunningRecord { 69 - return RunningRecord( 70 - id = currentActivity.id, 71 - timeStarted = currentActivity.startedAt, 72 - comment = "", 73 - tagIds = currentActivity.tags.map(Tag::id), 74 - ) 66 + val stopped = currents.filter { it.id !in startingIds } 67 + val started = starting.filter { it.id !in currentsIds } 68 + 69 + stopped.forEach { 70 + removeRunningRecordMediator.removeWithRecordAdd(it) 71 + } 72 + started.forEach { record -> 73 + addRunningRecordMediator.add( 74 + typeId = record.id, 75 + timeStarted = record.startedAt, 76 + tagIds = record.tags.map(Tag::id), 77 + ) 78 + } 75 79 } 76 80 77 81 override suspend fun queryTagsForActivity(activityId: Long): List<Tag> {
+8 -8
features/feature_wear/src/main/java/com/example/util/simpletimetracker/feature_wear/WearRPCServer.kt
··· 39 39 } 40 40 41 41 private suspend fun onQueryTagsForActivity(request: ByteArray): ByteArray? { 42 - val activityId: Long = mapRequest(request) ?: return null 43 - return mapToResponse(api.queryTagsForActivity(activityId)) 42 + val activityId: Long = mapFromBytes(request) ?: return null 43 + return mapToBytes(api.queryTagsForActivity(activityId)) 44 44 } 45 45 46 46 private suspend fun onSetCurrentActivities(request: ByteArray): ByteArray? { 47 - val activities: List<CurrentActivity> = mapRequest(request) ?: return null 47 + val activities: List<CurrentActivity> = mapFromBytes(request) ?: return null 48 48 api.setCurrentActivities(activities) 49 49 return ByteArray(0) 50 50 } ··· 54 54 } 55 55 56 56 private suspend fun onQueryActivities(): ByteArray { 57 - return mapToResponse(api.queryActivities()) 57 + return mapToBytes(api.queryActivities()) 58 58 } 59 59 60 60 private suspend fun onQueryCurrentActivities(): ByteArray { 61 - return mapToResponse(api.queryCurrentActivities()) 61 + return mapToBytes(api.queryCurrentActivities()) 62 62 } 63 63 64 64 private suspend fun onQuerySettings(): ByteArray { 65 - return mapToResponse(api.querySettings()) 65 + return mapToBytes(api.querySettings()) 66 66 } 67 67 68 - private fun <T> mapToResponse(data: T): ByteArray { 68 + private fun <T> mapToBytes(data: T): ByteArray { 69 69 return gson.toJson(data).toByteArray() 70 70 } 71 71 72 - private inline fun <reified T> mapRequest(data: ByteArray): T? { 72 + private inline fun <reified T> mapFromBytes(data: ByteArray): T? { 73 73 return runCatching { 74 74 val collectionType = object : TypeToken<T>() {}.type 75 75 gson.fromJson<T>(String(data), collectionType)
+4 -3
features/feature_wear/src/test/java/com/example/util/simpletimetracker/feature_wear/WearRPCServerTest.kt
··· 7 7 8 8 import com.example.util.simpletimetracker.wearrpc.Activity 9 9 import com.example.util.simpletimetracker.wearrpc.CurrentActivity 10 - import com.example.util.simpletimetracker.wearrpc.Messenger 10 + import com.example.util.simpletimetracker.presentation.data.Messenger 11 11 import com.example.util.simpletimetracker.wearrpc.MockWearCommunicationAPI 12 12 import com.example.util.simpletimetracker.wearrpc.Settings 13 13 import com.example.util.simpletimetracker.wearrpc.Tag 14 - import com.example.util.simpletimetracker.wearrpc.WearRPCClient 14 + import com.example.util.simpletimetracker.presentation.data.WearRPCClient 15 15 import kotlinx.coroutines.test.runTest 16 16 import org.junit.Assert.assertArrayEquals 17 17 import org.junit.Assert.assertEquals ··· 196 196 assertFalse(response.allowMultitasking) 197 197 } 198 198 199 - class MockMessenger(private val rpc: WearRPCServer) : Messenger { 199 + class MockMessenger(private val rpc: WearRPCServer) : 200 + Messenger { 200 201 201 202 override suspend fun send(capability: String, message: ByteArray): ByteArray? { 202 203 return rpc.onRequest(capability, message)
+11
wear/build.gradle.kts
··· 1 + import com.example.util.simpletimetracker.Deps 2 + 1 3 /* 2 4 * This Source Code Form is subject to the terms of the Mozilla Public 3 5 * License, v. 2.0. If a copy of the MPL was not distributed with this ··· 7 9 plugins { 8 10 id("com.android.application") 9 11 id("kotlin-android") 12 + id("kotlin-kapt") 13 + id("dagger.hilt.android.plugin") 10 14 } 11 15 12 16 android { ··· 74 78 // Default Dependencies 75 79 implementation("androidx.core:core-ktx:1.7.0") 76 80 implementation("com.google.android.gms:play-services-wearable:17.1.0") 81 + implementation(Deps.Google.gson) 77 82 implementation("androidx.percentlayout:percentlayout:1.0.0") 78 83 implementation("androidx.legacy:legacy-support-v4:1.0.0") 79 84 implementation("androidx.recyclerview:recyclerview:1.2.1") ··· 84 89 implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.1") 85 90 implementation("androidx.activity:activity-compose:1.3.1") 86 91 implementation("androidx.appcompat:appcompat:1.6.0") 92 + 93 + implementation(Deps.Google.dagger) 94 + kapt(Deps.Kapt.dagger) 95 + 96 + testImplementation(Deps.Test.junit) 97 + testImplementation(Deps.Test.coroutines) 87 98 androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_version") 88 99 debugImplementation("androidx.compose.ui:ui-tooling:$compose_version") 89 100 debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")
+78
wear/src/main/java/com/example/util/simpletimetracker/presentation/data/WearRPCClient.kt
··· 1 + /* 2 + * This Source Code Form is subject to the terms of the Mozilla Public 3 + * License, v. 2.0. If a copy of the MPL was not distributed with this 4 + * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 + */ 6 + package com.example.util.simpletimetracker.presentation.data 7 + 8 + import com.example.util.simpletimetracker.wearrpc.Activity 9 + import com.example.util.simpletimetracker.wearrpc.CurrentActivity 10 + import com.example.util.simpletimetracker.wearrpc.Request 11 + import com.example.util.simpletimetracker.wearrpc.Settings 12 + import com.example.util.simpletimetracker.wearrpc.Tag 13 + import com.example.util.simpletimetracker.wearrpc.WearCommunicationAPI 14 + import com.google.gson.Gson 15 + import com.google.gson.reflect.TypeToken 16 + import javax.inject.Inject 17 + 18 + class WearRPCClient @Inject constructor( 19 + private val messenger: Messenger, 20 + ) : WearCommunicationAPI { 21 + 22 + private val gson = Gson() 23 + 24 + override suspend fun ping(message: String): String { 25 + val response: String? = messenger 26 + .send(Request.PING, mapToBytes(message)) 27 + ?.let(::mapFromBytes) 28 + 29 + return response ?: throw WearRPCException("No response") 30 + } 31 + 32 + override suspend fun queryActivities(): List<Activity> { 33 + val response: List<Activity>? = messenger 34 + .send(Request.QUERY_ACTIVITIES) 35 + ?.let(::mapFromBytes) 36 + 37 + return response ?: throw WearRPCException("No response") 38 + } 39 + 40 + override suspend fun queryCurrentActivities(): List<CurrentActivity> { 41 + val response: List<CurrentActivity>? = messenger 42 + .send(Request.QUERY_CURRENT_ACTIVITIES) 43 + ?.let(::mapFromBytes) 44 + 45 + return response ?: throw WearRPCException("No response") 46 + } 47 + 48 + override suspend fun setCurrentActivities(starting: List<CurrentActivity>) { 49 + messenger.send(Request.SET_CURRENT_ACTIVITIES, mapToBytes(starting)) 50 + } 51 + 52 + override suspend fun queryTagsForActivity(activityId: Long): List<Tag> { 53 + val response: List<Tag>? = messenger 54 + .send(Request.QUERY_TAGS_FOR_ACTIVITY, mapToBytes(activityId)) 55 + ?.let(::mapFromBytes) 56 + 57 + return response ?: throw WearRPCException("No response") 58 + } 59 + 60 + override suspend fun querySettings(): Settings { 61 + val response: Settings? = messenger 62 + .send(Request.QUERY_SETTINGS) 63 + ?.let(::mapFromBytes) 64 + 65 + return response ?: throw WearRPCException("No response") 66 + } 67 + 68 + private fun <T> mapToBytes(data: T): ByteArray { 69 + return gson.toJson(data).toByteArray() 70 + } 71 + 72 + private inline fun <reified T> mapFromBytes(data: ByteArray): T? { 73 + return runCatching { 74 + val collectionType = object : TypeToken<T>() {}.type 75 + gson.fromJson<T>(String(data), collectionType) 76 + }.getOrNull() 77 + } 78 + }
+9
wear/src/main/java/com/example/util/simpletimetracker/presentation/data/WearRPCException.kt
··· 1 + /* 2 + * This Source Code Form is subject to the terms of the Mozilla Public 3 + * License, v. 2.0. If a copy of the MPL was not distributed with this 4 + * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 + */ 6 + package com.example.util.simpletimetracker.presentation.data 7 + 8 + // TODO catch exception and show error? 9 + class WearRPCException(message: String) : Exception(message)
+1 -1
wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/CurrentActivitiesMediator.kt
··· 3 3 import com.example.util.simpletimetracker.wearrpc.CurrentActivity 4 4 import com.example.util.simpletimetracker.wearrpc.Settings 5 5 import com.example.util.simpletimetracker.wearrpc.Tag 6 - import com.example.util.simpletimetracker.wearrpc.WearRPCClient 6 + import com.example.util.simpletimetracker.presentation.data.WearRPCClient 7 7 8 8 class CurrentActivitiesMediator( 9 9 private val rpc: WearRPCClient,
+2 -2
wear/src/main/java/com/example/util/simpletimetracker/presentation/remember/rpcClient.kt
··· 2 2 3 3 import androidx.compose.runtime.Composable 4 4 import androidx.compose.ui.platform.LocalContext 5 - import com.example.util.simpletimetracker.wearrpc.ContextMessenger 6 - import com.example.util.simpletimetracker.wearrpc.WearRPCClient 5 + import com.example.util.simpletimetracker.presentation.data.ContextMessenger 6 + import com.example.util.simpletimetracker.presentation.data.WearRPCClient 7 7 8 8 @Composable 9 9 fun rememberRPCClient(): WearRPCClient {
+1 -1
wear/src/main/java/com/example/util/simpletimetracker/presentation/screens/ActivitiesScreen.kt
··· 15 15 import com.example.util.simpletimetracker.presentation.remember.rememberCurrentActivities 16 16 import com.example.util.simpletimetracker.presentation.remember.rememberRPCClient 17 17 import com.example.util.simpletimetracker.wearrpc.Activity 18 - import com.example.util.simpletimetracker.wearrpc.StartActivityMediator 18 + import com.example.util.simpletimetracker.presentation.mediators.StartActivityMediator 19 19 import kotlinx.coroutines.Dispatchers 20 20 import kotlinx.coroutines.launch 21 21
+9 -36
wearrpc/build.gradle.kts
··· 1 - import com.example.util.simpletimetracker.Base 2 - import com.example.util.simpletimetracker.Deps 3 - 4 1 /* 5 2 * This Source Code Form is subject to the terms of the Mozilla Public 6 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 4 * file, You can obtain one at https://mozilla.org/MPL/2.0/. 8 5 */ 6 + import com.example.util.simpletimetracker.Base 7 + import com.example.util.simpletimetracker.Deps 8 + import com.example.util.simpletimetracker.applyAndroidLibrary 9 + 9 10 plugins { 10 11 id("com.android.library") 11 - id("org.jetbrains.kotlin.android") 12 + id("kotlin-android") 13 + id("kotlin-parcelize") 12 14 } 15 + 16 + applyAndroidLibrary() 13 17 14 18 android { 15 - namespace = "com.example.util.simpletimetracker.wearrpc" 16 - compileSdk = 34 17 - 18 - defaultConfig { 19 - minSdk = Base.minSDK 20 - 21 - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 22 - consumerProguardFiles("consumer-rules.pro") 23 - } 24 - 25 - buildTypes { 26 - release { 27 - isMinifyEnabled = false 28 - proguardFiles( 29 - getDefaultProguardFile("proguard-android-optimize.txt"), 30 - "proguard-rules.pro" 31 - ) 32 - } 33 - } 34 - compileOptions { 35 - sourceCompatibility = JavaVersion.VERSION_1_8 36 - targetCompatibility = JavaVersion.VERSION_1_8 37 - } 38 - kotlinOptions { 39 - jvmTarget = "1.8" 40 - } 19 + namespace = "${Base.namespace}.wearrpc" 41 20 } 42 21 43 22 dependencies { 44 23 implementation(Deps.Google.services) 45 24 implementation(Deps.Google.gson) 46 - implementation("androidx.core:core-ktx:1.12.0") 47 - implementation("androidx.appcompat:appcompat:1.6.1") 48 - implementation("com.google.android.material:material:1.11.0") 49 - 50 - testImplementation(Deps.Test.junit) 51 - testImplementation(Deps.Test.coroutines) 52 25 }
+1 -3
wearrpc/src/main/AndroidManifest.xml
··· 1 1 <?xml version="1.0" encoding="utf-8"?> 2 - <manifest xmlns:android="http://schemas.android.com/apk/res/android"> 3 - 4 - </manifest> 2 + <manifest />
+11 -4
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/DTO.kt
··· 5 5 */ 6 6 package com.example.util.simpletimetracker.wearrpc 7 7 8 + import android.os.Parcelable 9 + import kotlinx.parcelize.Parcelize 10 + 8 11 /** 9 12 * Data Transfer Objects 10 13 * 11 14 * Object definitions for records sent between Wear/Mobile 12 15 */ 13 16 17 + @Parcelize 14 18 data class Activity( 15 19 val id: Long, 16 20 val name: String, 17 21 val icon: String, 18 22 val color: Long, 19 - ) 23 + ): Parcelable 20 24 25 + @Parcelize 21 26 data class CurrentActivity( 22 27 val id: Long, 23 28 val startedAt: Long, 24 29 val tags: List<Tag>, 25 - ) 30 + ): Parcelable 26 31 32 + @Parcelize 27 33 data class Tag( 28 34 val id: Long, 29 35 val name: String, 30 36 val isGeneral: Boolean, 31 37 val color: Long, 32 - ) 38 + ): Parcelable 33 39 40 + @Parcelize 34 41 data class Settings( 35 42 val allowMultitasking: Boolean, 36 43 val showRecordTagSelection: Boolean, 37 44 val recordTagSelectionCloseAfterOne: Boolean, 38 45 val recordTagSelectionEvenForGeneralTags: Boolean, 39 - ) 46 + ): Parcelable
+28 -24
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/Messenger.kt wear/src/main/java/com/example/util/simpletimetracker/presentation/data/Messenger.kt
··· 3 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 4 * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 5 */ 6 - package com.example.util.simpletimetracker.wearrpc 6 + package com.example.util.simpletimetracker.presentation.data 7 7 8 8 import android.content.Context 9 9 import android.util.Log ··· 14 14 import com.google.android.gms.wearable.Wearable 15 15 import kotlinx.coroutines.CompletableDeferred 16 16 import java.util.concurrent.CancellationException 17 + import javax.inject.Inject 17 18 18 19 interface Messenger { 19 - suspend fun send(capability: String): ByteArray? { 20 - return this.send(capability, ByteArray(0)) 21 - } 22 - suspend fun send(capability: String, message: ByteArray): ByteArray? 20 + suspend fun send( 21 + capability: String, 22 + message: ByteArray = ByteArray(0), 23 + ): ByteArray? 23 24 } 24 25 25 - class ContextMessenger(private val context: Context): Messenger { 26 + class ContextMessenger @Inject constructor( 27 + private val context: Context, 28 + ) : Messenger { 26 29 private val TAG: String = ContextMessenger::class.java.name 27 30 28 31 override suspend fun send(capability: String, message: ByteArray): ByteArray? { 29 - val def = CompletableDeferred<ByteArray?>() 32 + val deferred = CompletableDeferred<ByteArray?>() 30 33 val bestNode = findNearestNode(capability) 31 34 32 35 // Send the message 33 - bestNode?.also { nodeId -> 34 - Log.d(TAG, "Sending message to ${bestNode?.displayName}") 36 + if (bestNode != null) { 37 + Log.d(TAG, "Sending message to ${bestNode.displayName}") 35 38 Log.d(TAG, String(message)) 36 - Wearable.getMessageClient(context).sendRequest(bestNode.id, capability, message) 39 + Wearable.getMessageClient(context) 40 + .sendRequest(bestNode.id, capability, message) 37 41 .addOnSuccessListener { 38 42 Log.d(TAG, "Response received for $capability") 39 43 Log.d(TAG, String(it)) 40 - def.complete(it) 44 + deferred.complete(it) 41 45 }.addOnCanceledListener { 42 - val message = "Request $capability to ${bestNode.displayName} was cancelled" 43 - Log.d(TAG, message) 44 - def.cancel(CancellationException(message)) 46 + val logMessage = "Request $capability to ${bestNode.displayName} was cancelled" 47 + Log.d(TAG, logMessage) 48 + deferred.cancel(CancellationException(logMessage)) 45 49 }.addOnFailureListener { 46 - val message = 47 - "No response received from mobile for $capability : ${String(message)}" 48 - Log.d(TAG, message) 49 - def.cancel(CancellationException(message)) 50 + val logMessage = "No response received from mobile for $capability : ${String(message)}" 51 + Log.d(TAG, logMessage) 52 + deferred.cancel(CancellationException(logMessage)) 50 53 } 51 - } ?: run { 52 - val message = "No nodes found with the capability $capability" 53 - Log.d(TAG, message) 54 - def.cancel(CancellationException(message)) 54 + } else { 55 + val logMessage = "No nodes found with the capability $capability" 56 + Log.d(TAG, logMessage) 57 + deferred.cancel(CancellationException(logMessage)) 55 58 } 56 - return def.await() 59 + 60 + return deferred.await() 57 61 } 58 62 59 - private suspend fun findNearestNode(capability: String): Node? { 63 + private fun findNearestNode(capability: String): Node? { 60 64 // Find all nodes which support the time tracking message 61 65 Log.d(TAG, "Searching for nodes with ${context.packageName} installed") 62 66 val nodeClient = Wearable.getNodeClient(context)
+1 -1
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/MockWearCommunicationAPI.kt
··· 23 23 this.currentActivities = activities 24 24 } 25 25 26 - override suspend fun setCurrentActivities(activities: List<CurrentActivity>) { 26 + override suspend fun setCurrentActivities(starting: List<CurrentActivity>) { 27 27 TODO("Not yet implemented") 28 28 } 29 29
+5 -1
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/StartActivityMediator.kt wear/src/main/java/com/example/util/simpletimetracker/presentation/mediators/StartActivityMediator.kt
··· 3 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 4 * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 5 */ 6 - package com.example.util.simpletimetracker.wearrpc 6 + package com.example.util.simpletimetracker.presentation.mediators 7 + 8 + import com.example.util.simpletimetracker.wearrpc.Activity 9 + import com.example.util.simpletimetracker.wearrpc.Settings 10 + import com.example.util.simpletimetracker.wearrpc.WearCommunicationAPI 7 11 8 12 class StartActivityMediator( 9 13 private val api: WearCommunicationAPI,
+1 -1
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/WearCommunicationAPI.kt
··· 36 36 * 37 37 * Replaces the currently running activity/activities with the given activities 38 38 */ 39 - suspend fun setCurrentActivities(activities: List<CurrentActivity>) 39 + suspend fun setCurrentActivities(starting: List<CurrentActivity>) 40 40 41 41 /** 42 42 * [Request.QUERY_TAGS_FOR_ACTIVITY]
-57
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/WearRPCClient.kt
··· 1 - /* 2 - * This Source Code Form is subject to the terms of the Mozilla Public 3 - * License, v. 2.0. If a copy of the MPL was not distributed with this 4 - * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 - */ 6 - package com.example.util.simpletimetracker.wearrpc 7 - 8 - import com.google.gson.Gson 9 - import com.google.gson.reflect.TypeToken 10 - 11 - class WearRPCClient(private val messenger: Messenger) : WearCommunicationAPI { 12 - 13 - override suspend fun ping(message: String): String { 14 - val response = messenger.send(Request.PING, message.toByteArray()) 15 - if (response != null) return String(response) 16 - else throw WearRPCException("No response") 17 - } 18 - 19 - override suspend fun queryActivities(): List<Activity> { 20 - val response = messenger.send(Request.QUERY_ACTIVITIES) 21 - if (response != null) { 22 - val collectionType = object : TypeToken<List<Activity>>() {}.type 23 - return Gson().fromJson(String(response), collectionType) 24 - } else throw WearRPCException("No response") 25 - } 26 - 27 - override suspend fun queryCurrentActivities(): List<CurrentActivity> { 28 - val response = messenger.send(Request.QUERY_CURRENT_ACTIVITIES) 29 - if (response != null) { 30 - val collectionType = object : TypeToken<List<CurrentActivity>>() {}.type 31 - return Gson().fromJson(String(response), collectionType) 32 - } else throw WearRPCException("No response") 33 - } 34 - 35 - override suspend fun setCurrentActivities(activities: List<CurrentActivity>) { 36 - messenger.send(Request.SET_CURRENT_ACTIVITIES, Gson().toJson(activities).toByteArray()) 37 - } 38 - 39 - override suspend fun queryTagsForActivity(activityId: Long): List<Tag> { 40 - val response = messenger.send( 41 - Request.QUERY_TAGS_FOR_ACTIVITY, 42 - Gson().toJson(activityId).toByteArray(), 43 - ) 44 - if (response != null) { 45 - val collectionType = object : TypeToken<List<Tag>>() {}.type 46 - return Gson().fromJson(String(response), collectionType) 47 - } else throw WearRPCException("No response") 48 - } 49 - 50 - override suspend fun querySettings(): Settings { 51 - val response = messenger.send(Request.QUERY_SETTINGS) 52 - if (response != null) { 53 - val jsonType = object : TypeToken<Settings>() {}.type 54 - return Gson().fromJson(String(response), jsonType) 55 - } else throw WearRPCException("No response") 56 - } 57 - }
-8
wearrpc/src/main/java/com/example/util/simpletimetracker/wearrpc/WearRPCException.kt
··· 1 - /* 2 - * This Source Code Form is subject to the terms of the Mozilla Public 3 - * License, v. 2.0. If a copy of the MPL was not distributed with this 4 - * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 - */ 6 - package com.example.util.simpletimetracker.wearrpc 7 - 8 - class WearRPCException(message: String) : Exception(message) {}
+9 -4
wearrpc/src/test/java/com/example/util/simpletimetracker/wearrpc/StartActivityMediatorTest.kt wear/src/test/java/com/example/util/simpletimetracker/wear/StartActivityMediatorTest.kt
··· 3 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 4 * file, You can obtain one at https://mozilla.org/MPL/2.0/. 5 5 */ 6 - package com.example.util.simpletimetracker.wearrpc 6 + package com.example.util.simpletimetracker.wear 7 7 8 + import com.example.util.simpletimetracker.presentation.mediators.StartActivityMediator 9 + import com.example.util.simpletimetracker.wearrpc.Activity 10 + import com.example.util.simpletimetracker.wearrpc.MockWearCommunicationAPI 11 + import com.example.util.simpletimetracker.wearrpc.Settings 12 + import com.example.util.simpletimetracker.wearrpc.Tag 8 13 import kotlinx.coroutines.test.runTest 9 14 import org.junit.Assert.assertEquals 10 15 import org.junit.Before ··· 66 71 recordTagSelectionEvenForGeneralTags = false, 67 72 ), 68 73 ) 69 - api.mock_queryTagsForActivity(mapOf(sampleActivity.id to arrayOf(sampleGeneralTag))) 74 + api.mock_queryTagsForActivity(mapOf(sampleActivity.id to listOf(sampleGeneralTag))) 70 75 mediator.requestStart(sampleActivity) 71 76 `assert only start callback invoked`() 72 77 } ··· 80 85 @Test 81 86 fun `activity has non-general tags`() = runTest { 82 87 api.mock_querySettings(sampleSettings) 83 - api.mock_queryTagsForActivity(mapOf(sampleActivity.id to arrayOf(sampleNonGeneralTag))) 88 + api.mock_queryTagsForActivity(mapOf(sampleActivity.id to listOf(sampleNonGeneralTag))) 84 89 mediator.requestStart(sampleActivity) 85 90 `assert only tag callback invoked`() 86 91 } ··· 88 93 @Test 89 94 fun `activity has only general tags and tag selection enabled for only generals`() = runTest { 90 95 api.mock_querySettings(sampleSettings.copy(recordTagSelectionEvenForGeneralTags = true)) 91 - api.mock_queryTagsForActivity(mapOf(sampleActivity.id to arrayOf(sampleGeneralTag))) 96 + api.mock_queryTagsForActivity(mapOf(sampleActivity.id to listOf(sampleGeneralTag))) 92 97 mediator.requestStart(sampleActivity) 93 98 `assert only tag callback invoked`() 94 99 }