Skip to content

Commit 1f5e515

Browse files
authored
[Android] virtual-device-app: Implement door lock view (#30778)
* virtual-device-app: Implement common layout Signed-off-by: Jaehoon You <jaehoon.you@samsung.com> Signed-off-by: Charles Kim <chulspro.kim@samsung.com> * virtual-device-app: Implement doorlock view Signed-off-by: Jaehoon You <jaehoon.you@samsung.com> Signed-off-by: Charles Kim <chulspro.kim@samsung.com> --------- Signed-off-by: Jaehoon You <jaehoon.you@samsung.com> Signed-off-by: Charles Kim <chulspro.kim@samsung.com>
1 parent 2b965b4 commit 1f5e515

File tree

12 files changed

+233
-17
lines changed

12 files changed

+233
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
33
<string name="matter_on_off_switch" translatable="false">Matter OnOff Switch</string>
4+
<string name="matter_door_lock" translatable="false">Matter Door Lock</string>
45
<string name="matter_device" translatable="false">Matter Device</string>
56
<string name="description_icon" translatable="false">icon</string>
67
</resources>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.matter.virtual.device.app.core.model.databinding
2+
3+
import androidx.lifecycle.LiveData
4+
5+
data class SeekbarData(val progress: LiveData<Int>, val min: Int = 0, val max: Int = 100)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<vector android:height="24dp" android:tint="#000000"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
5+
<path android:fillColor="@android:color/white" android:pathData="M12,12m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"/>
6+
</vector>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#000000"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M19.5,12c0,-0.23 -0.01,-0.45 -0.03,-0.68l1.86,-1.41c0.4,-0.3 0.51,-0.86 0.26,-1.3l-1.87,-3.23c-0.25,-0.44 -0.79,-0.62 -1.25,-0.42l-2.15,0.91c-0.37,-0.26 -0.76,-0.49 -1.17,-0.68l-0.29,-2.31C14.8,2.38 14.37,2 13.87,2h-3.73C9.63,2 9.2,2.38 9.14,2.88L8.85,5.19c-0.41,0.19 -0.8,0.42 -1.17,0.68L5.53,4.96c-0.46,-0.2 -1,-0.02 -1.25,0.42L2.41,8.62c-0.25,0.44 -0.14,0.99 0.26,1.3l1.86,1.41C4.51,11.55 4.5,11.77 4.5,12s0.01,0.45 0.03,0.68l-1.86,1.41c-0.4,0.3 -0.51,0.86 -0.26,1.3l1.87,3.23c0.25,0.44 0.79,0.62 1.25,0.42l2.15,-0.91c0.37,0.26 0.76,0.49 1.17,0.68l0.29,2.31C9.2,21.62 9.63,22 10.13,22h3.73c0.5,0 0.93,-0.38 0.99,-0.88l0.29,-2.31c0.41,-0.19 0.8,-0.42 1.17,-0.68l2.15,0.91c0.46,0.2 1,0.02 1.25,-0.42l1.87,-3.23c0.25,-0.44 0.14,-0.99 -0.26,-1.3l-1.86,-1.41C19.49,12.45 19.5,12.23 19.5,12zM12.04,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5s3.5,1.57 3.5,3.5S13.97,15.5 12.04,15.5z"/>
5+
</vector>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
4+
5+
<data>
6+
7+
<variable
8+
name="seekbarData"
9+
type="com.matter.virtual.device.app.core.model.databinding.SeekbarData" />
10+
</data>
11+
12+
<androidx.constraintlayout.widget.ConstraintLayout
13+
android:layout_width="match_parent"
14+
android:layout_height="wrap_content"
15+
android:layout_marginHorizontal="@dimen/device_item_margin_horizontal"
16+
android:layout_marginTop="@dimen/device_item_margin_top"
17+
android:background="@drawable/menu_item_bg"
18+
android:gravity="center_vertical"
19+
android:paddingStart="@dimen/device_item_padding_start"
20+
android:paddingTop="@dimen/device_item_padding_top"
21+
android:paddingEnd="@dimen/device_item_padding_end"
22+
android:paddingBottom="@dimen/device_item_padding_bottom">
23+
24+
<TextView
25+
android:id="@+id/title_text"
26+
android:layout_width="wrap_content"
27+
android:layout_height="wrap_content"
28+
android:textAlignment="viewStart"
29+
android:textSize="@dimen/device_item_text_size"
30+
app:layout_constraintStart_toStartOf="parent"
31+
app:layout_constraintTop_toTopOf="parent" />
32+
33+
<TextView
34+
android:id="@+id/value_text"
35+
android:layout_width="@dimen/device_item_value_text_width"
36+
android:layout_height="wrap_content"
37+
android:textAlignment="viewStart"
38+
android:textSize="@dimen/device_item_value_text_size"
39+
app:layout_constraintStart_toStartOf="parent"
40+
app:layout_constraintTop_toBottomOf="@+id/title_text" />
41+
42+
<SeekBar
43+
android:id="@+id/seekbar"
44+
android:layout_width="@dimen/device_item_seekbar_width"
45+
android:layout_height="@dimen/device_item_seekbar_height"
46+
android:contentDescription="@string/description_seekbar"
47+
android:max="@{seekbarData.max}"
48+
android:min="@{seekbarData.min}"
49+
android:progress="@{seekbarData.progress}"
50+
app:layout_constraintEnd_toEndOf="parent"
51+
app:layout_constraintStart_toEndOf="@+id/value_text"
52+
app:layout_constraintTop_toBottomOf="@+id/title_text" />
53+
</androidx.constraintlayout.widget.ConstraintLayout>
54+
</layout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto">
4+
5+
<androidx.constraintlayout.widget.ConstraintLayout
6+
android:layout_width="match_parent"
7+
android:layout_height="wrap_content"
8+
android:layout_marginHorizontal="@dimen/device_item_margin_horizontal"
9+
android:layout_marginTop="@dimen/device_item_margin_top"
10+
android:background="@drawable/menu_item_bg"
11+
android:gravity="center_vertical"
12+
android:paddingStart="@dimen/device_item_padding_start"
13+
android:paddingTop="@dimen/device_item_padding_top"
14+
android:paddingEnd="@dimen/device_item_padding_end"
15+
android:paddingBottom="@dimen/device_item_padding_bottom">
16+
17+
<TextView
18+
android:id="@+id/title_text"
19+
android:layout_width="wrap_content"
20+
android:layout_height="wrap_content"
21+
android:textAlignment="viewStart"
22+
android:textSize="@dimen/device_item_text_size"
23+
app:layout_constraintStart_toStartOf="parent"
24+
app:layout_constraintTop_toTopOf="parent" />
25+
26+
<TextView
27+
android:id="@+id/value_text"
28+
android:layout_width="wrap_content"
29+
android:layout_height="wrap_content"
30+
android:textAlignment="viewStart"
31+
android:textSize="@dimen/device_item_value_text_size"
32+
app:layout_constraintStart_toStartOf="parent"
33+
app:layout_constraintTop_toBottomOf="@+id/title_text" />
34+
35+
<ImageView
36+
android:id="@+id/button"
37+
android:layout_width="@dimen/device_item_button_width"
38+
android:layout_height="@dimen/device_item_button_height"
39+
android:contentDescription="@string/description_button"
40+
app:layout_constraintBottom_toBottomOf="parent"
41+
app:layout_constraintEnd_toEndOf="parent"
42+
app:layout_constraintTop_toTopOf="parent" />
43+
</androidx.constraintlayout.widget.ConstraintLayout>
44+
</layout>
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
33
<string name="description_button" translatable="false">button</string>
4+
<string name="description_seekbar" translatable="false">seekbar</string>
5+
46
<string name="more_menu_reset" translatable="false">Reset</string>
57

68
<string name="dialog_factory_reset_message">"The Matter device app will be reset and closed. Continue?"</string>
79
<string name="dialog_user_factory_reset_message">"The commissioning was not completed. The Matter device app will be reset and closed. Continue?"</string>
8-
<string name="dialog_fabric_removed_factory_reset_message">"The fabric was removed. The Matter device app will be reset and closed."</string>
10+
<string name="dialog_fabric_removed_factory_reset_message">"The fabric was removed. The Matter device app will be reset and closed."</string>
11+
12+
<string name="battery">Battery</string>
13+
<string name="battery_format" translatable="false">%d &lt;small>&lt;small>%%&lt;/small>&lt;/small></string>
914

15+
<string name="cancel">Cancel</string>
1016
<string name="on_off_switch_power_on">On</string>
1117
<string name="on_off_switch_power_off">Off</string>
1218
</resources>

examples/virtual-device-app/android/App/feature/closure/src/main/java/com/matter/virtual/device/app/feature/closure/DoorLockFragment.kt

+73-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package com.matter.virtual.device.app.feature.closure
22

3+
import android.text.Html
4+
import android.widget.SeekBar
5+
import androidx.appcompat.app.AlertDialog
36
import androidx.fragment.app.viewModels
47
import androidx.navigation.fragment.navArgs
8+
import com.matter.virtual.device.app.core.model.databinding.SeekbarData
9+
import com.matter.virtual.device.app.core.model.matter.LockState
510
import com.matter.virtual.device.app.core.ui.BaseFragment
611
import com.matter.virtual.device.app.core.ui.databinding.LayoutAppbarBinding
712
import com.matter.virtual.device.app.feature.closure.databinding.FragmentDoorLockBinding
@@ -16,6 +21,7 @@ class DoorLockFragment :
1621
BaseFragment<FragmentDoorLockBinding, DoorLockViewModel>(R.layout.fragment_door_lock) {
1722

1823
override val viewModel: DoorLockViewModel by viewModels()
24+
private var lockState: LockState = LockState.LOCKED
1925

2026
@OptIn(ExperimentalSerializationApi::class)
2127
override fun setupNavArgs() {
@@ -25,9 +31,55 @@ class DoorLockFragment :
2531

2632
override fun setupAppbar(): LayoutAppbarBinding = binding.appbar
2733

28-
override fun setupUi() {}
34+
override fun setupUi() {
35+
/** title text */
36+
binding.appbar.toolbarTitle.text = getString(R.string.matter_door_lock)
2937

30-
override fun setupObservers() {}
38+
/** LockState layout */
39+
binding.doorLockLockStateLayout.titleText.text = getString(R.string.door_lock_lock_state)
40+
binding.doorLockLockStateLayout.button.setImageResource(R.drawable.round_settings_24)
41+
binding.doorLockLockStateLayout.button.setOnClickListener { showLockStatePopup() }
42+
43+
/** Send alarm layout */
44+
binding.doorLockSendAlarmLayout.valueText.text =
45+
getString(R.string.door_lock_send_lock_alarm_event)
46+
binding.doorLockSendAlarmLayout.button.setImageResource(
47+
R.drawable.round_radio_button_checked_24
48+
)
49+
binding.doorLockSendAlarmLayout.button.setOnClickListener {
50+
viewModel.onClickSendLockAlarmEventButton()
51+
}
52+
53+
/** Battery layout */
54+
binding.doorLockBatteryLayout.titleText.text = getString(R.string.battery)
55+
binding.doorLockBatteryLayout.seekbarData =
56+
SeekbarData(progress = viewModel.batteryRemainingPercentage)
57+
binding.doorLockBatteryLayout.seekbar.setOnSeekBarChangeListener(
58+
object : SeekBar.OnSeekBarChangeListener {
59+
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
60+
viewModel.updateBatterySeekbarProgress(progress)
61+
}
62+
63+
override fun onStartTrackingTouch(seekBar: SeekBar) {}
64+
65+
override fun onStopTrackingTouch(seekBar: SeekBar) {
66+
viewModel.updateBatteryStatusToCluster(seekBar.progress)
67+
}
68+
}
69+
)
70+
}
71+
72+
override fun setupObservers() {
73+
viewModel.lockState.observe(viewLifecycleOwner) {
74+
this.lockState = it
75+
binding.doorLockLockStateLayout.valueText.text = it.toString()
76+
}
77+
78+
viewModel.batteryRemainingPercentage.observe(viewLifecycleOwner) {
79+
val text: String = getString(R.string.battery_format, it)
80+
binding.doorLockBatteryLayout.valueText.text = Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY)
81+
}
82+
}
3183

3284
override fun onResume() {
3385
Timber.d("onResume()")
@@ -38,4 +90,23 @@ class DoorLockFragment :
3890
Timber.d("onDestroy()")
3991
super.onDestroy()
4092
}
93+
94+
private fun showLockStatePopup() {
95+
val list =
96+
arrayOf(
97+
LockState.NOT_FULLY_LOCKED.toString(),
98+
LockState.LOCKED.toString(),
99+
LockState.UNLOCKED.toString(),
100+
LockState.UNLATCHED.toString()
101+
)
102+
103+
AlertDialog.Builder(requireContext())
104+
.setTitle(R.string.door_lock_lock_state)
105+
.setSingleChoiceItems(list, list.indexOf(this.lockState.toString())) { dialog, which ->
106+
viewModel.setLockState(enumValueOf(list[which]))
107+
dialog.dismiss()
108+
}
109+
.setNegativeButton(R.string.cancel, null)
110+
.show()
111+
}
41112
}

examples/virtual-device-app/android/App/feature/closure/src/main/java/com/matter/virtual/device/app/feature/closure/DoorLockViewModel.kt

+3-12
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,9 @@ constructor(
6161
super.onCleared()
6262
}
6363

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-
}
64+
fun setLockState(lockState: LockState) {
65+
Timber.d("setLockState():new:$lockState")
66+
viewModelScope.launch { setLockStateUseCase(lockState) }
7667
}
7768

7869
fun onClickSendLockAlarmEventButton() {

examples/virtual-device-app/android/App/feature/closure/src/main/res/layout/fragment_door_lock.xml

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<layout xmlns:android="http://schemas.android.com/apk/res/android">
3+
34
<androidx.constraintlayout.widget.ConstraintLayout
45
android:layout_width="match_parent"
56
android:layout_height="match_parent">
@@ -15,6 +16,34 @@
1516
android:layout_height="match_parent"
1617
android:layout_marginTop="?attr/actionBarSize">
1718

19+
<LinearLayout
20+
android:layout_width="match_parent"
21+
android:layout_height="wrap_content"
22+
android:orientation="vertical">
23+
24+
<LinearLayout
25+
android:id="@+id/door_lock_function_layout"
26+
android:layout_width="match_parent"
27+
android:layout_height="wrap_content"
28+
android:orientation="vertical">
29+
30+
<include
31+
android:id="@+id/door_lock_lock_state_layout"
32+
layout="@layout/layout_item_title_value_simple_button" />
33+
34+
<include
35+
android:id="@+id/door_lock_send_alarm_layout"
36+
layout="@layout/layout_item_title_value_simple_button" />
37+
38+
<include
39+
android:id="@+id/door_lock_battery_layout"
40+
layout="@layout/layout_item_title_value_seekbar" />
41+
</LinearLayout>
42+
43+
<!-- Bottom Space -->
44+
<include layout="@layout/layout_space_bottom" />
45+
<!-- Bottom Space -->
46+
</LinearLayout>
1847
</ScrollView>
1948
</androidx.constraintlayout.widget.ConstraintLayout>
20-
</layout>
49+
</layout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<string name="door_lock_lock_state">Lock state</string>
4+
<string name="door_lock_send_lock_alarm_event">Send Alarm</string>
5+
</resources>

examples/virtual-device-app/android/App/feature/setup/src/main/res/values/strings.xml

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
<string name="setup_network_notification_message">Make sure your Mobile/Hub/Device App are connected to the same Wi-Fi network.</string>
1212
<string name="save">Save</string>
1313
<string name="toast_discriminator" translatable="false">Invalid input value</string>
14-
<string name="cancel">Cancel</string>
1514
<string name="start">Start</string>
1615
<string name="setup_ssid_text" translatable="false">Wi-Fi : %1$s</string>
1716
<string name="setup_discriminator_text" translatable="false">%1$s : %2$s</string>

0 commit comments

Comments
 (0)