Skip to content

Commit fc2a071

Browse files
authored
[Android] virtual-device-app: Implement doorlock viewmodel (#30236)
* virtual-device-app: Implement doorlock viewmodel Signed-off-by: Jaehoon You <[email protected]> Signed-off-by: Charles Kim <[email protected]> * virtual-device-app: Apply 'LockState' enum type to align with Doorlock cluster specification Signed-off-by: Jaehoon You <[email protected]> Signed-off-by: Charles Kim <[email protected]> * virtual-device-app: Change variable name more obviously Signed-off-by: Jaehoon You <[email protected]> Signed-off-by: Charles Kim <[email protected]> * virtual-device-app: Fix initial value mismatching Signed-off-by: Jaehoon You <[email protected]> Signed-off-by: Charles Kim <[email protected]> --------- Signed-off-by: Jaehoon You <[email protected]> Signed-off-by: Charles Kim <[email protected]>
1 parent a454ccd commit fc2a071

File tree

9 files changed

+130
-25
lines changed

9 files changed

+130
-25
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package com.matter.virtual.device.app.core.data.repository.cluster
22

3+
import com.matter.virtual.device.app.core.model.matter.LockState
34
import kotlinx.coroutines.flow.StateFlow
45

56
interface DoorLockManagerRepository {
6-
fun getLockStateFlow(): StateFlow<Boolean>
7+
fun getLockStateFlow(): StateFlow<LockState>
78

8-
suspend fun setLockState(value: Boolean)
9+
suspend fun setLockState(lockState: LockState)
910

1011
suspend fun sendLockAlarmEvent()
1112
}

examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/DoorLockManagerRepositoryImpl.kt

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.matter.virtual.device.app.core.data.repository.cluster
22

33
import com.matter.virtual.device.app.core.matter.manager.DoorLockManagerStub
4+
import com.matter.virtual.device.app.core.model.matter.LockState
45
import javax.inject.Inject
56
import kotlinx.coroutines.flow.StateFlow
67
import timber.log.Timber
@@ -9,13 +10,13 @@ internal class DoorLockManagerRepositoryImpl
910
@Inject
1011
constructor(private val doorLockManagerStub: DoorLockManagerStub) : DoorLockManagerRepository {
1112

12-
override fun getLockStateFlow(): StateFlow<Boolean> {
13+
override fun getLockStateFlow(): StateFlow<LockState> {
1314
return doorLockManagerStub.lockState
1415
}
1516

16-
override suspend fun setLockState(value: Boolean) {
17-
Timber.d("setLockState():$value")
18-
doorLockManagerStub.setLockState(value)
17+
override suspend fun setLockState(lockState: LockState) {
18+
Timber.d("setLockState():$lockState")
19+
doorLockManagerStub.setLockState(lockState)
1920
}
2021

2122
override suspend fun sendLockAlarmEvent() {
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package com.matter.virtual.device.app.core.domain.usecase.matter.cluster.doorlock
22

33
import com.matter.virtual.device.app.core.data.repository.cluster.DoorLockManagerRepository
4+
import com.matter.virtual.device.app.core.model.matter.LockState
45
import javax.inject.Inject
56
import kotlinx.coroutines.flow.StateFlow
67

78
class GetLockStateFlowUseCase
89
@Inject
910
constructor(private val doorLockManagerRepository: DoorLockManagerRepository) {
1011

11-
operator fun invoke(): StateFlow<Boolean> = doorLockManagerRepository.getLockStateFlow()
12+
operator fun invoke(): StateFlow<LockState> = doorLockManagerRepository.getLockStateFlow()
1213
}

examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/doorlock/SetLockStateUseCase.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.matter.virtual.device.app.core.domain.usecase.matter.cluster.doorloc
33
import com.matter.virtual.device.app.core.common.di.IoDispatcher
44
import com.matter.virtual.device.app.core.data.repository.cluster.DoorLockManagerRepository
55
import com.matter.virtual.device.app.core.domain.CoroutineUseCase
6+
import com.matter.virtual.device.app.core.model.matter.LockState
67
import javax.inject.Inject
78
import kotlinx.coroutines.CoroutineDispatcher
89

@@ -11,9 +12,9 @@ class SetLockStateUseCase
1112
constructor(
1213
private val doorLockManagerRepository: DoorLockManagerRepository,
1314
@IoDispatcher dispatcher: CoroutineDispatcher
14-
) : CoroutineUseCase<Boolean, Unit>(dispatcher) {
15+
) : CoroutineUseCase<LockState, Unit>(dispatcher) {
1516

16-
override suspend fun execute(param: Boolean) {
17+
override suspend fun execute(param: LockState) {
1718
doorLockManagerRepository.setLockState(param)
1819
}
1920
}

examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/manager/DoorLockManagerStub.kt

+20-14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.matter.virtual.device.app.core.matter.manager
33
import com.matter.virtual.device.app.DeviceApp
44
import com.matter.virtual.device.app.DoorLockManager
55
import com.matter.virtual.device.app.core.common.MatterConstants
6+
import com.matter.virtual.device.app.core.model.matter.LockState
67
import javax.inject.Inject
78
import javax.inject.Singleton
89
import kotlinx.coroutines.flow.MutableStateFlow
@@ -12,14 +13,14 @@ import timber.log.Timber
1213
@Singleton
1314
class DoorLockManagerStub @Inject constructor(private val deviceApp: DeviceApp) : DoorLockManager {
1415

15-
private val _lockState = MutableStateFlow(false)
16-
val lockState: StateFlow<Boolean>
16+
private val _lockState = MutableStateFlow(LockState.LOCKED)
17+
val lockState: StateFlow<LockState>
1718
get() = _lockState
1819

1920
override fun initAttributeValue() {
2021
Timber.d("initAttributeValue()")
2122
deviceApp.setLockType(MatterConstants.DEFAULT_ENDPOINT, DoorLockManager.DlLockType_kMagnetic)
22-
deviceApp.setLockState(MatterConstants.DEFAULT_ENDPOINT, lockState.value.asLockState())
23+
deviceApp.setLockState(MatterConstants.DEFAULT_ENDPOINT, DoorLockManager.DlLockState_kLocked)
2324
deviceApp.setActuatorEnabled(MatterConstants.DEFAULT_ENDPOINT, true)
2425
deviceApp.setOperatingMode(
2526
MatterConstants.DEFAULT_ENDPOINT,
@@ -33,29 +34,34 @@ class DoorLockManagerStub @Inject constructor(private val deviceApp: DeviceApp)
3334

3435
override fun handleLockStateChanged(value: Int) {
3536
Timber.d("handleLockStateChanged():$value")
36-
_lockState.value = value.asBooleanLockState()
37+
_lockState.value = value.asLockStateEnum()
3738
}
3839

39-
fun setLockState(value: Boolean) {
40-
Timber.d("setLockState():$value")
41-
deviceApp.setLockState(MatterConstants.DEFAULT_ENDPOINT, value.asLockState())
40+
fun setLockState(lockState: LockState) {
41+
Timber.d("setLockState():$lockState")
42+
deviceApp.setLockState(MatterConstants.DEFAULT_ENDPOINT, lockState.asLockState())
4243
}
4344

4445
fun sendLockAlarmEvent() {
4546
Timber.d("sendLockAlarmEvent()")
4647
deviceApp.sendLockAlarmEvent(MatterConstants.DEFAULT_ENDPOINT)
4748
}
4849

49-
private fun Boolean.asLockState() =
50+
private fun LockState.asLockState() =
5051
when (this) {
51-
true -> DoorLockManager.DlLockState_kUnlocked
52-
false -> DoorLockManager.DlLockState_kLocked
52+
LockState.NOT_FULLY_LOCKED -> DoorLockManager.DlLockState_kNotFullyLocked
53+
LockState.LOCKED -> DoorLockManager.DlLockState_kLocked
54+
LockState.UNLOCKED -> DoorLockManager.DlLockState_kUnlocked
55+
LockState.UNLATCHED -> DoorLockManager.DlLockState_kUnlatched
56+
else -> DoorLockManager.DlLockState_kUnknownEnumValue
5357
}
5458

55-
private fun Int.asBooleanLockState() =
59+
private fun Int.asLockStateEnum() =
5660
when (this) {
57-
DoorLockManager.DlLockState_kUnlocked -> true
58-
DoorLockManager.DlLockState_kLocked -> false
59-
else -> false
61+
DoorLockManager.DlLockState_kNotFullyLocked -> LockState.NOT_FULLY_LOCKED
62+
DoorLockManager.DlLockState_kLocked -> LockState.LOCKED
63+
DoorLockManager.DlLockState_kUnlocked -> LockState.UNLOCKED
64+
DoorLockManager.DlLockState_kUnlatched -> LockState.UNLATCHED
65+
else -> LockState.UNKNOWN_ENUM_VALUE
6066
}
6167
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.matter.virtual.device.app.core.model.matter
2+
3+
enum class LockState {
4+
NOT_FULLY_LOCKED,
5+
LOCKED,
6+
UNLOCKED,
7+
UNLATCHED,
8+
UNKNOWN_ENUM_VALUE
9+
}

examples/virtual-device-app/android/App/feature/closure/build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ dependencies {
4747

4848
implementation(project(":core:common"))
4949
implementation(project(":core:domain"))
50+
implementation(project(":core:model"))
5051
implementation(project(":core:ui"))
5152

5253
implementation(Deps.AndroidX.core)
5354
implementation(Deps.AndroidX.appcompat)
5455
implementation(Deps.AndroidX.fragment)
5556
implementation(Deps.AndroidX.Lifecycle.viewmodel)
57+
implementation(Deps.AndroidX.Lifecycle.livedata)
5658

5759
implementation(Deps.Kotlin.serialization)
5860

Original file line numberDiff line numberDiff line change
@@ -1,17 +1,100 @@
11
package com.matter.virtual.device.app.feature.closure
22

3+
import androidx.lifecycle.LiveData
34
import androidx.lifecycle.SavedStateHandle
5+
import androidx.lifecycle.asLiveData
6+
import androidx.lifecycle.viewModelScope
7+
import com.matter.virtual.device.app.core.common.successOr
8+
import com.matter.virtual.device.app.core.domain.usecase.matter.IsFabricRemovedUseCase
9+
import com.matter.virtual.device.app.core.domain.usecase.matter.StartMatterAppServiceUseCase
10+
import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.doorlock.GetLockStateFlowUseCase
11+
import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.doorlock.SendLockAlarmEventUseCase
12+
import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.doorlock.SetLockStateUseCase
13+
import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.powersource.GetBatPercentRemainingUseCase
14+
import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.powersource.SetBatPercentRemainingUseCase
15+
import com.matter.virtual.device.app.core.model.matter.LockState
416
import com.matter.virtual.device.app.core.ui.BaseViewModel
517
import dagger.hilt.android.lifecycle.HiltViewModel
618
import javax.inject.Inject
19+
import kotlinx.coroutines.flow.MutableStateFlow
20+
import kotlinx.coroutines.flow.StateFlow
21+
import kotlinx.coroutines.launch
722
import timber.log.Timber
823

924
@HiltViewModel
10-
class DoorLockViewModel @Inject constructor(savedStateHandle: SavedStateHandle) :
11-
BaseViewModel(savedStateHandle) {
25+
class DoorLockViewModel
26+
@Inject
27+
constructor(
28+
getLockStateFlowUseCase: GetLockStateFlowUseCase,
29+
getBatPercentRemainingUseCase: GetBatPercentRemainingUseCase,
30+
private val setLockStateUseCase: SetLockStateUseCase,
31+
private val sendLockAlarmEventUseCase: SendLockAlarmEventUseCase,
32+
private val setBatPercentRemainingUseCase: SetBatPercentRemainingUseCase,
33+
private val startMatterAppServiceUseCase: StartMatterAppServiceUseCase,
34+
private val isFabricRemovedUseCase: IsFabricRemovedUseCase,
35+
savedStateHandle: SavedStateHandle
36+
) : BaseViewModel(savedStateHandle) {
37+
38+
private val _lockState: StateFlow<LockState> = getLockStateFlowUseCase()
39+
val lockState: LiveData<LockState>
40+
get() = _lockState.asLiveData()
41+
42+
private val _batteryRemainingPercentage: MutableStateFlow<Int> =
43+
getBatPercentRemainingUseCase() as MutableStateFlow<Int>
44+
val batteryRemainingPercentage: LiveData<Int>
45+
get() = _batteryRemainingPercentage.asLiveData()
46+
47+
init {
48+
viewModelScope.launch { startMatterAppServiceUseCase(matterSettings) }
49+
50+
viewModelScope.launch {
51+
val isFabricRemoved = isFabricRemovedUseCase().successOr(false)
52+
if (isFabricRemoved) {
53+
Timber.d("Fabric Removed")
54+
onFabricRemoved()
55+
}
56+
}
57+
}
1258

1359
override fun onCleared() {
1460
Timber.d("onCleared()")
1561
super.onCleared()
1662
}
63+
64+
fun onClickButton() {
65+
Timber.d("onClickButton()")
66+
viewModelScope.launch {
67+
Timber.d("current lockState value = ${_lockState.value}")
68+
if (_lockState.value == LockState.LOCKED) {
69+
Timber.d("set value = unlocked")
70+
setLockStateUseCase(LockState.UNLOCKED)
71+
} else {
72+
Timber.d("set value = locked")
73+
setLockStateUseCase(LockState.LOCKED)
74+
}
75+
}
76+
}
77+
78+
fun onClickSendLockAlarmEventButton() {
79+
Timber.d("onClickSendLockAlarmEventButton()")
80+
viewModelScope.launch {
81+
if (_lockState.value == LockState.LOCKED) {
82+
// if lockState == locked, send alarm event and change the lockState to unlocked
83+
sendLockAlarmEventUseCase()
84+
setLockStateUseCase(LockState.UNLOCKED)
85+
}
86+
}
87+
}
88+
89+
fun updateBatterySeekbarProgress(progress: Int) {
90+
_batteryRemainingPercentage.value = progress
91+
}
92+
93+
fun updateBatteryStatusToCluster(progress: Int) {
94+
Timber.d("progress:$progress")
95+
viewModelScope.launch {
96+
updateBatterySeekbarProgress(progress)
97+
setBatPercentRemainingUseCase(progress)
98+
}
99+
}
17100
}

examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DoorLockManager.java

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public interface DoorLockManager {
66
int DlLockState_kLocked = 1;
77
int DlLockState_kUnlocked = 2;
88
int DlLockState_kUnlatched = 3;
9+
int DlLockState_kUnknownEnumValue = 4;
910

1011
int DlLockType_kDeadBolt = 0;
1112
int DlLockType_kMagnetic = 1;

0 commit comments

Comments
 (0)