From 98c5f39594cd935c581ed2e33ae12b0db1df2dd7 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:06:56 +0900 Subject: [PATCH 01/29] virtual-device-app: Update chip device config Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../virtual-device-common/include/CHIPProjectAppConfig.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h b/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h index baaeab39b590dc..ecb57a91b07222 100644 --- a/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h +++ b/examples/virtual-device-app/virtual-device-common/include/CHIPProjectAppConfig.h @@ -38,9 +38,10 @@ #define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1 #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 259 // 0x0103 On/Off Light Switch #define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1 -#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Matter Device" +#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Matter Virtual Device" // Enable app platform #define CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED 0 From 7cfaa6f8fd6b00832a986f70c947f44dc2ef66bf Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:09:03 +0900 Subject: [PATCH 02/29] virtual-device-app: Add java files about chip stack id information Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- examples/virtual-device-app/android/BUILD.gn | 2 + .../matter/virtual/device/app/Clusters.java | 138 ++++++++++++++++++ .../virtual/device/app/DeviceEventType.java | 49 +++++++ 3 files changed, 189 insertions(+) create mode 100644 examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java create mode 100644 examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java diff --git a/examples/virtual-device-app/android/BUILD.gn b/examples/virtual-device-app/android/BUILD.gn index 9926574fcbf792..ffa9a9fe6e3520 100644 --- a/examples/virtual-device-app/android/BUILD.gn +++ b/examples/virtual-device-app/android/BUILD.gn @@ -64,9 +64,11 @@ android_library("java") { ] sources = [ + "java/src/com/matter/virtual/device/app/Clusters.java", "java/src/com/matter/virtual/device/app/DACProvider.java", "java/src/com/matter/virtual/device/app/DeviceApp.java", "java/src/com/matter/virtual/device/app/DeviceAppCallback.java", + "java/src/com/matter/virtual/device/app/DeviceEventType.java", "java/src/com/matter/virtual/device/app/OnOffManager.java", ] diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java new file mode 100644 index 00000000000000..98a95ea8c37a0e --- /dev/null +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java @@ -0,0 +1,138 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.matter.virtual.device.app; + +public class Clusters { + + public static final long ClusterId_PowerConfiguration = 0x00000001; + public static final long ClusterId_DeviceTemperatureConfiguration = 0x00000002; + public static final long ClusterId_Identify = 0x00000003; + public static final long ClusterId_Groups = 0x00000004; + public static final long ClusterId_Scenes = 0x00000005; + public static final long ClusterId_OnOff = 0x00000006; + public static final long ClusterId_OnOffSwitchConfiguration = 0x00000007; + public static final long ClusterId_LevelControl = 0x00000008; + public static final long ClusterId_Alarms = 0x00000009; + public static final long ClusterId_Time = 0x0000000A; + public static final long ClusterId_BinaryInputBasic = 0x0000000F; + public static final long ClusterId_PowerProfile = 0x0000001A; + public static final long ClusterId_ApplianceControl = 0x0000001B; + public static final long ClusterId_PulseWidthModulation = 0x0000001C; + public static final long ClusterId_Descriptor = 0x0000001D; + public static final long ClusterId_Binding = 0x0000001E; + public static final long ClusterId_AccessControl = 0x0000001F; + public static final long ClusterId_PollControl = 0x00000020; + public static final long ClusterId_Actions = 0x00000025; + public static final long ClusterId_Basic = 0x00000028; + public static final long ClusterId_OtaSoftwareUpdateProvider = 0x00000029; + public static final long ClusterId_OtaSoftwareUpdateRequestor = 0x0000002A; + public static final long ClusterId_LocalizationConfiguration = 0x0000002B; + public static final long ClusterId_LocalizationTimeFormat = 0x0000002C; + public static final long ClusterId_LocalizationUnit = 0x0000002D; + public static final long ClusterId_PowerSourceConfiguration = 0x0000002E; + public static final long ClusterId_PowerSource = 0x0000002F; + public static final long ClusterId_GeneralCommissioning = 0x00000030; + public static final long ClusterId_NetworkCommissioning = 0x00000031; + public static final long ClusterId_DiagnosticLogs = 0x00000032; + public static final long ClusterId_GeneralDiagnostics = 0x00000033; + public static final long ClusterId_SoftwareDiagnostics = 0x00000034; + public static final long ClusterId_ThreadNetworkDiagnostics = 0x00000035; + public static final long ClusterId_WiFiNetworkDiagnostics = 0x00000036; + public static final long ClusterId_EthernetNetworkDiagnostics = 0x00000037; + public static final long ClusterId_TimeSynchronization = 0x00000038; + public static final long ClusterId_BridgedDeviceBasic = 0x00000039; + public static final long ClusterId_Switch = 0x0000003B; + public static final long ClusterId_AdministratorCommissioning = 0x0000003C; + public static final long ClusterId_OperationalCredentials = 0x0000003E; + public static final long ClusterId_GroupKeyManagement = 0x0000003F; + public static final long ClusterId_FixedLabel = 0x00000040; + public static final long ClusterId_UserLabel = 0x00000041; + public static final long ClusterId_ProxyConfiguration = 0x00000042; + public static final long ClusterId_ProxyDiscovery = 0x00000043; + public static final long ClusterId_ProxyValid = 0x00000044; + public static final long ClusterId_BooleanState = 0x00000045; + public static final long ClusterId_ModeSelect = 0x00000050; + public static final long ClusterId_ShadeConfiguration = 0x00000100; + public static final long ClusterId_DoorLock = 0x00000101; + public static final long ClusterId_WindowCovering = 0x00000102; + public static final long ClusterId_BarrierControl = 0x00000103; + public static final long ClusterId_PumpConfigurationAndControl = 0x00000200; + public static final long ClusterId_Thermostat = 0x00000201; + public static final long ClusterId_FanControl = 0x00000202; + public static final long ClusterId_DehumidificationControl = 0x00000203; + public static final long ClusterId_ThermostatUserInterfaceConfiguration = 0x00000204; + public static final long ClusterId_ColorControl = 0x00000300; + public static final long ClusterId_BallastConfiguration = 0x00000301; + public static final long ClusterId_IlluminanceMeasurement = 0x00000400; + public static final long ClusterId_TemperatureMeasurement = 0x00000402; + public static final long ClusterId_PressureMeasurement = 0x00000403; + public static final long ClusterId_FlowMeasurement = 0x00000404; + public static final long ClusterId_RelativeHumidityMeasurement = 0x00000405; + public static final long ClusterId_OccupancySensing = 0x00000406; + public static final long ClusterId_CarbonMonoxideConcentrationMeasurement = 0x0000040C; + public static final long ClusterId_CarbonDioxideConcentrationMeasurement = 0x0000040D; + public static final long ClusterId_EthyleneConcentrationMeasurement = 0x0000040E; + public static final long ClusterId_EthyleneOxideConcentrationMeasurement = 0x0000040F; + public static final long ClusterId_HydrogenConcentrationMeasurement = 0x00000410; + public static final long ClusterId_HydrogenSulphideConcentrationMeasurement = 0x00000411; + public static final long ClusterId_NitricOxideConcentrationMeasurement = 0x00000412; + public static final long ClusterId_NitrogenDioxideConcentrationMeasurement = 0x00000413; + public static final long ClusterId_OxygenConcentrationMeasurement = 0x00000414; + public static final long ClusterId_OzoneConcentrationMeasurement = 0x00000415; + public static final long ClusterId_SulfurDioxideConcentrationMeasurement = 0x00000416; + public static final long ClusterId_DissolvedOxygenConcentrationMeasurement = 0x00000417; + public static final long ClusterId_BromateConcentrationMeasurement = 0x00000418; + public static final long ClusterId_ChloraminesConcentrationMeasurement = 0x00000419; + public static final long ClusterId_ChlorineConcentrationMeasurement = 0x0000041A; + public static final long ClusterId_FecalColiformAndEColiConcentrationMeasurement = 0x0000041B; + public static final long ClusterId_FluorideConcentrationMeasurement = 0x0000041C; + public static final long ClusterId_HaloaceticAcidsConcentrationMeasurement = 0x0000041D; + public static final long ClusterId_TotalTrihalomethanesConcentrationMeasurement = 0x0000041E; + public static final long ClusterId_TotalColiformBacteriaConcentrationMeasurement = 0x0000041F; + public static final long ClusterId_TurbidityConcentrationMeasurement = 0x00000420; + public static final long ClusterId_CopperConcentrationMeasurement = 0x00000421; + public static final long ClusterId_LeadConcentrationMeasurement = 0x00000422; + public static final long ClusterId_ManganeseConcentrationMeasurement = 0x00000423; + public static final long ClusterId_SulfateConcentrationMeasurement = 0x00000424; + public static final long ClusterId_BromodichloromethaneConcentrationMeasurement = 0x00000425; + public static final long ClusterId_BromoformConcentrationMeasurement = 0x00000426; + public static final long ClusterId_ChlorodibromomethaneConcentrationMeasurement = 0x00000427; + public static final long ClusterId_ChloroformConcentrationMeasurement = 0x00000428; + public static final long ClusterId_SodiumConcentrationMeasurement = 0x00000429; + public static final long ClusterId_IasZone = 0x00000500; + public static final long ClusterId_IasAce = 0x00000501; + public static final long ClusterId_IasWd = 0x00000502; + public static final long ClusterId_WakeOnLan = 0x00000503; + public static final long ClusterId_Channel = 0x00000504; + public static final long ClusterId_TargetNavigator = 0x00000505; + public static final long ClusterId_MediaPlayback = 0x00000506; + public static final long ClusterId_MediaInput = 0x00000507; + public static final long ClusterId_LowPower = 0x00000508; + public static final long ClusterId_KeypadInput = 0x00000509; + public static final long ClusterId_ContentLauncher = 0x0000050A; + public static final long ClusterId_AudioOutput = 0x0000050B; + public static final long ClusterId_ApplicationLauncher = 0x0000050C; + public static final long ClusterId_ApplicationBasic = 0x0000050D; + public static final long ClusterId_AccountLogin = 0x0000050E; + public static final long ClusterId_TestCluster = 0xFFF1FC05; + public static final long ClusterId_Messaging = 0x00000703; + public static final long ClusterId_ApplianceIdentification = 0x00000B00; + public static final long ClusterId_MeterIdentification = 0x00000B01; + public static final long ClusterId_ApplianceEventsAndAlert = 0x00000B02; + public static final long ClusterId_ApplianceStatistics = 0x00000B03; + public static final long ClusterId_ElectricalMeasurement = 0x00000B04; +} diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java new file mode 100644 index 00000000000000..019bb79d4fd314 --- /dev/null +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.matter.virtual.device.app; + +public class DeviceEventType { + public static final long EventId_WiFiConnectivityChange = 0x8000; + public static final long EventId_ThreadConnectivityChange = 0x8001; + public static final long EventId_InternetConnectivityChange = 0x8002; + public static final long EventId_ServiceConnectivityChange = 0x8003; + public static final long EventId_ServiceProvisioningChange = 0x8004; + public static final long EventId_TimeSyncChange = 0x8005; + public static final long EventId_ICDPollingIntervalChang = 0x8006; + public static final long EventId_CHIPoBLEConnectionEstablished = 0x8007; + public static final long EventId_CHIPoBLEConnectionClosed = 0x8008; + public static final long EventId_ThreadStateChange = 0x8009; + public static final long EventId_ThreadInterfaceStateChange = 0x800A; + public static final long EventId_CHIPoBLEAdvertisingChange = 0x800B; + public static final long EventId_InterfaceIpAddressChanged = 0x800C; + public static final long EventId_CommissioningWindowStatusChanged = 0x800D; + public static final long EventId_CommissioningComplete = 0x800E; + public static final long EventId_FailSafeTimerExpired = 0x800F; + public static final long EventId_FailSafeStateChanged = 0x8010; + public static final long EventId_OperationalNetworkEnabled = 0x8011; + public static final long EventId_DnssdInitialized = 0x8012; + public static final long EventId_DnssdRestartNeeded = 0x8013; + public static final long EventId_BindingsChangedViaCluster = 0x8014; + public static final long EventId_OtaStateChanged = 0x8015; + public static final long EventId_ServerReady = 0x8016; + public static final long EventId_ChipMsgSentEvent = 0x8017; + public static final long EventId_ChipMsgRxEventHandled = 0x8018; + public static final long EventId_AppWakeUpEvent = 0x8018; + + // out of public event range (0x8000) + public static final long EventId_FabricRemoved = 0x9FFF; +} From 456e1a078f5c1b9489fc0fe07406e4f955f9afac Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:14:21 +0900 Subject: [PATCH 03/29] virtual-device-app: Add initialize api for OnOffManager Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/java/OnOffManager.cpp | 4 ++-- .../virtual/device/app/OnOffManager.java | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/examples/virtual-device-app/android/java/OnOffManager.cpp b/examples/virtual-device-app/android/java/OnOffManager.cpp index 09d5265df8ab09..c5a12dfebf30bf 100644 --- a/examples/virtual-device-app/android/java/OnOffManager.cpp +++ b/examples/virtual-device-app/android/java/OnOffManager.cpp @@ -97,10 +97,10 @@ CHIP_ERROR OnOffManager::InitializeWithObjects(jobject managerObject) jclass OnOffManagerClass = env->GetObjectClass(managerObject); VerifyOrReturnLogError(OnOffManagerClass != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - mHandleOnOffChangedMethod = env->GetMethodID(OnOffManagerClass, "HandleOnOffChanged", "(Z)V"); + mHandleOnOffChangedMethod = env->GetMethodID(OnOffManagerClass, "handleOnOffChanged", "(Z)V"); if (mHandleOnOffChangedMethod == nullptr) { - ChipLogError(Zcl, "Failed to access OnOffManager 'HandleOnOffChanged' method"); + ChipLogError(Zcl, "Failed to access OnOffManager 'handleOnOffChanged' method"); env->ExceptionClear(); return CHIP_ERROR_INVALID_ARGUMENT; } diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java index d6ec0f2d56d543..faa12f221e2909 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java @@ -1,11 +1,18 @@ package com.matter.virtual.device.app; public interface OnOffManager { - /** - * Notify that the OnOff value be changed by matter and should effect it. Note, set by TvApp will - * also trigger this function, so must check if value is same - * - * @param value - */ - void HandleOnOffChanged(boolean value); + + /** + * initialize OnOff value by DeviceApp + */ + void initAttributeValue(); + + /** + * Notify that the OnOff value be changed by matter and should effect it. Note, + * set by DeviceApp will + * also trigger this function, so must check if value is same + * + * @param value + */ + void handleOnOffChanged(boolean value); } From 8cd07a09ad615788a79b192a5759b0d7bf0a3f3b Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:19:29 +0900 Subject: [PATCH 04/29] virtual-device-app: Update parameter types about chip stack id Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/java/DeviceApp-JNI.cpp | 8 +-- .../matter/virtual/device/app/DeviceApp.java | 58 +++++++++---------- .../virtual/device/app/DeviceAppCallback.java | 4 +- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp index 1f1b918b6d1aee..1f7e937c21b183 100644 --- a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp +++ b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp @@ -58,14 +58,14 @@ void DeviceAppJNI::InitializeWithObjects(jobject app) jclass managerClass = env->GetObjectClass(mDeviceAppObject); VerifyOrReturn(managerClass != nullptr, ChipLogError(Zcl, "Failed to get DeviceAppJNI Java class")); - mPostClusterInitMethod = env->GetMethodID(managerClass, "postClusterInit", "(II)V"); + mPostClusterInitMethod = env->GetMethodID(managerClass, "postClusterInit", "(JI)V"); if (mPostClusterInitMethod == nullptr) { ChipLogError(Zcl, "Failed to access DeviceApp 'postClusterInit' method"); env->ExceptionClear(); } - mPostEventMethod = env->GetMethodID(managerClass, "postEvent", "(I)V"); + mPostEventMethod = env->GetMethodID(managerClass, "postEvent", "(J)V"); if (mPostEventMethod == nullptr) { ChipLogError(Zcl, "Failed to access DeviceApp 'postEvent' method"); @@ -80,7 +80,7 @@ void DeviceAppJNI::PostClusterInit(int clusterId, int endpoint) VerifyOrReturn(mDeviceAppObject != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mDeviceAppObject null")); VerifyOrReturn(mPostClusterInitMethod != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mPostClusterInitMethod null")); - env->CallVoidMethod(mDeviceAppObject, mPostClusterInitMethod, static_cast(clusterId), static_cast(endpoint)); + env->CallVoidMethod(mDeviceAppObject, mPostClusterInitMethod, static_cast(clusterId), static_cast(endpoint)); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Failed to call DeviceAppJNI 'postClusterInit' method"); @@ -95,7 +95,7 @@ void DeviceAppJNI::PostEvent(int event) VerifyOrReturn(mDeviceAppObject != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mDeviceAppObject null")); VerifyOrReturn(mPostEventMethod != nullptr, ChipLogError(Zcl, "DeviceAppJNI::mPostEventMethod null")); - env->CallVoidMethod(mDeviceAppObject, mPostEventMethod, static_cast(event)); + env->CallVoidMethod(mDeviceAppObject, mPostEventMethod, static_cast(event)); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Failed to call DeviceAppJNI 'postEventMethod' method"); diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java index 6d86374cdf7b0c..dc20e794c11d43 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java @@ -20,43 +20,43 @@ import android.util.Log; public class DeviceApp { - private DeviceAppCallback mCallback; - private static final String TAG = "DeviceApp"; - - public DeviceApp(DeviceAppCallback callback) { - mCallback = callback; - nativeInit(); - } - - private void postClusterInit(int clusterId, int endpoint) { - Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); - if (mCallback != null) { - mCallback.onClusterInit(this, clusterId, endpoint); + private DeviceAppCallback mCallback; + private static final String TAG = "DeviceApp"; + + public DeviceApp(DeviceAppCallback callback) { + mCallback = callback; + nativeInit(); + } + + private void postClusterInit(long clusterId, int endpoint) { + Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); + if (mCallback != null) { + mCallback.onClusterInit(this, clusterId, endpoint); + } } - } - private void postEvent(int event) { - Log.d(TAG, "postEvent : " + event); - if (mCallback != null) { - mCallback.onEvent(event); + private void postEvent(long event) { + Log.d(TAG, "postEvent : " + event); + if (mCallback != null) { + mCallback.onEvent(event); + } } - } - public native void nativeInit(); + public native void nativeInit(); - // called before Matter server is initiated - public native void preServerInit(); + // called before Matter server is initiated + public native void preServerInit(); - // called after Matter server is initiated - public native void postServerInit(int deviceTypeId); + // called after Matter server is initiated + public native void postServerInit(int deviceTypeId); - public native void setOnOffManager(int endpoint, OnOffManager manager); + public native void setOnOffManager(int endpoint, OnOffManager manager); - public native boolean setOnOff(int endpoint, boolean value); + public native boolean setOnOff(int endpoint, boolean value); - public native void setDACProvider(DACProvider provider); + public native void setDACProvider(DACProvider provider); - static { - System.loadLibrary("DeviceApp"); - } + static { + System.loadLibrary("DeviceApp"); + } } diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java index d0cb46a341d448..a627dbcb82a158 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java @@ -17,7 +17,7 @@ package com.matter.virtual.device.app; public interface DeviceAppCallback { - void onClusterInit(DeviceApp app, int clusterId, int endpoint); + void onClusterInit(DeviceApp app, long clusterId, int endpoint); - void onEvent(int event); + void onEvent(long event); } From 7c35f5d62ca5c906f9a6b38069e700a6d4f27b7a Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:21:54 +0900 Subject: [PATCH 05/29] virtual-device-app: Add setCallback api Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../src/com/matter/virtual/device/app/DeviceApp.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java index dc20e794c11d43..b70adf9e811a78 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java @@ -20,14 +20,17 @@ import android.util.Log; public class DeviceApp { - private DeviceAppCallback mCallback; + private DeviceAppCallback mCallback = null; private static final String TAG = "DeviceApp"; - public DeviceApp(DeviceAppCallback callback) { - mCallback = callback; + public DeviceApp() { nativeInit(); } + public void setCallback(DeviceAppCallback callback) { + mCallback = callback; + } + private void postClusterInit(long clusterId, int endpoint) { Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); if (mCallback != null) { From b0a5e5f168299a75606b9fff20592b77fbedd9f6 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:24:56 +0900 Subject: [PATCH 06/29] virtual-device-app: Use ExampleDACProvider Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- examples/virtual-device-app/android/java/DeviceApp-JNI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp index 1f7e937c21b183..6e44f1fbd40777 100644 --- a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp +++ b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -139,8 +140,7 @@ JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) { if (!chip::Credentials::IsDeviceAttestationCredentialsProviderSet()) { - JNIDACProvider * p = new JNIDACProvider(provider); - chip::Credentials::SetDeviceAttestationCredentialsProvider(p); + chip::Credentials::SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider()); } } From cb459c49d646ce24a0af322c7f02f8db6c083021 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:29:13 +0900 Subject: [PATCH 07/29] virtual-device-app: Add core:ui module Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/core/ui/.gitignore | 0 .../android/App/core/ui/build.gradle.kts | 67 +++++++++++++++++++ .../android/App/core/ui/proguard-rules.pro | 21 ++++++ .../app/core/ui/ExampleInstrumentedTest.kt | 22 ++++++ .../App/core/ui/src/main/AndroidManifest.xml | 4 ++ .../device/app/core/ui/ExampleUnitTest.kt | 16 +++++ .../android/App/settings.gradle.kts | 1 + 7 files changed, 131 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/ui/.gitignore create mode 100644 examples/virtual-device-app/android/App/core/ui/build.gradle.kts create mode 100644 examples/virtual-device-app/android/App/core/ui/proguard-rules.pro create mode 100644 examples/virtual-device-app/android/App/core/ui/src/androidTest/java/com/matter/virtual/device/app/core/ui/ExampleInstrumentedTest.kt create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/AndroidManifest.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/test/java/com/matter/virtual/device/app/core/ui/ExampleUnitTest.kt diff --git a/examples/virtual-device-app/android/App/core/ui/.gitignore b/examples/virtual-device-app/android/App/core/ui/.gitignore new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/examples/virtual-device-app/android/App/core/ui/build.gradle.kts b/examples/virtual-device-app/android/App/core/ui/build.gradle.kts new file mode 100644 index 00000000000000..27cf142a1b85e2 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/build.gradle.kts @@ -0,0 +1,67 @@ +import com.matter.buildsrc.Deps +import com.matter.buildsrc.Versions + +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + id("com.google.dagger.hilt.android") + kotlin("kapt") +} + +android { + namespace = "com.matter.virtual.device.app.core.ui" + compileSdk = Versions.compileSdkVersion + + defaultConfig { + minSdk = Versions.minSdkVersion + targetSdk = Versions.targetSdkVersion + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + dataBinding = true + } +} + +dependencies { + + implementation(project(":core:common")) + implementation(project(":core:domain")) + implementation(project(":core:model")) + + implementation(Deps.AndroidX.core) + implementation(Deps.AndroidX.appcompat) + implementation(Deps.AndroidX.fragment) + implementation(Deps.AndroidX.Lifecycle.viewmodel) + implementation(Deps.material) + + implementation(Deps.Kotlin.serialization) + + implementation(Deps.Dagger.hiltAndroid) + kapt(Deps.Dagger.hiltAndroidCompiler) + + implementation(Deps.timber) + + testImplementation(Deps.Test.junit) + androidTestImplementation(Deps.Test.junitExt) + androidTestImplementation(Deps.Test.espresso) +} \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/proguard-rules.pro b/examples/virtual-device-app/android/App/core/ui/proguard-rules.pro new file mode 100644 index 00000000000000..481bb434814107 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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/examples/virtual-device-app/android/App/core/ui/src/androidTest/java/com/matter/virtual/device/app/core/ui/ExampleInstrumentedTest.kt b/examples/virtual-device-app/android/App/core/ui/src/androidTest/java/com/matter/virtual/device/app/core/ui/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000000..ba6f86d1419bdb --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/androidTest/java/com/matter/virtual/device/app/core/ui/ExampleInstrumentedTest.kt @@ -0,0 +1,22 @@ +package com.matter.virtual.device.app.core.ui + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.* +import org.junit.Test +import org.junit.runner.RunWith + +/** + * 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.matter.virtual.device.app.core.ui.test", appContext.packageName) + } +} diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/ui/src/main/AndroidManifest.xml new file mode 100644 index 00000000000000..a5918e68abcdde --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/test/java/com/matter/virtual/device/app/core/ui/ExampleUnitTest.kt b/examples/virtual-device-app/android/App/core/ui/src/test/java/com/matter/virtual/device/app/core/ui/ExampleUnitTest.kt new file mode 100644 index 00000000000000..abb1e0f8802fcf --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/test/java/com/matter/virtual/device/app/core/ui/ExampleUnitTest.kt @@ -0,0 +1,16 @@ +package com.matter.virtual.device.app.core.ui + +import org.junit.Assert.* +import org.junit.Test + +/** + * 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) + } +} diff --git a/examples/virtual-device-app/android/App/settings.gradle.kts b/examples/virtual-device-app/android/App/settings.gradle.kts index 78cbf5ec8af59d..a1bded5ee3a6b0 100644 --- a/examples/virtual-device-app/android/App/settings.gradle.kts +++ b/examples/virtual-device-app/android/App/settings.gradle.kts @@ -19,6 +19,7 @@ include(":core:data") include(":core:domain") include(":core:matter") include(":core:model") +include(":core:ui") include(":feature:control") include(":feature:main") include(":feature:qrcode") From 1874ad6f9ae4da4f02dbb727bc67b85f9dd65b36 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:32:57 +0900 Subject: [PATCH 08/29] virtual-device-app: Add MatterModule for provide DeviceApp library Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../device/app/core/matter/di/MatterModule.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/di/MatterModule.kt diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/di/MatterModule.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/di/MatterModule.kt new file mode 100644 index 00000000000000..027530830db428 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/di/MatterModule.kt @@ -0,0 +1,15 @@ +package com.matter.virtual.device.app.core.matter.di + +import com.matter.virtual.device.app.DeviceApp +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +internal object MatterModule { + + @Provides @Singleton fun provideDeviceApp(): DeviceApp = DeviceApp() +} From 5b38336c0f4b458e021b2be5a1ca4fe1b1770cc0 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:37:02 +0900 Subject: [PATCH 09/29] virtual-device-app: Add OnOffManager stub Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../device/app/core/common/MatterConstants.kt | 3 +- .../core/matter/manager/OnOffManagerStub.kt | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/manager/OnOffManagerStub.kt diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt index 84f26bfca81b68..a4d2a44a0f48c3 100644 --- a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt @@ -3,9 +3,10 @@ package com.matter.virtual.device.app.core.common object MatterConstants { const val DEFAULT_VERSION = 0 const val DEFAULT_VENDOR_ID = 0xFFF1 - const val DEFAULT_PRODUCT_ID = 0x8001 + const val DEFAULT_PRODUCT_ID = 0x8003 const val DEFAULT_COMMISSIONING_FLOW = 0 const val DEFAULT_SETUP_PINCODE = 20202021L const val DEFAULT_DISCRIMINATOR = 3840 const val DEFAULT_DEVICE_NAME = "Matter Device" + const val DEFAULT_ENDPOINT = 1 } diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/manager/OnOffManagerStub.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/manager/OnOffManagerStub.kt new file mode 100644 index 00000000000000..267c9537b7492b --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/manager/OnOffManagerStub.kt @@ -0,0 +1,34 @@ +package com.matter.virtual.device.app.core.matter.manager + +import com.matter.virtual.device.app.DeviceApp +import com.matter.virtual.device.app.OnOffManager +import com.matter.virtual.device.app.core.common.MatterConstants +import javax.inject.Inject +import javax.inject.Singleton +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import timber.log.Timber + +@Singleton +class OnOffManagerStub @Inject constructor(private val deviceApp: DeviceApp) : OnOffManager { + + private val _onOff = MutableStateFlow(false) + val onOff: StateFlow + get() = _onOff + + override fun initAttributeValue() { + Timber.d("initAttributeValue()") + deviceApp.setOnOff(MatterConstants.DEFAULT_ENDPOINT, onOff.value) + } + + override fun handleOnOffChanged(value: Boolean) { + Timber.d("value:$value") + _onOff.value = value + } + + fun setOnOff(value: Boolean) { + Timber.d("value:$value") + _onOff.value = value + deviceApp.setOnOff(MatterConstants.DEFAULT_ENDPOINT, value) + } +} From 1943fe2e0346076687b2c48c3e9765ef6335c5da Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:44:42 +0900 Subject: [PATCH 10/29] virtual-device-app: Implement chip stack initialize code Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../device/app/core/common/MatterConstants.kt | 6 ++ .../device/app/core/matter/MatterApp.kt | 91 ++++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt index a4d2a44a0f48c3..931bcdab72d84a 100644 --- a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/MatterConstants.kt @@ -9,4 +9,10 @@ object MatterConstants { const val DEFAULT_DISCRIMINATOR = 3840 const val DEFAULT_DEVICE_NAME = "Matter Device" const val DEFAULT_ENDPOINT = 1 + + const val TEST_SPAKE2P_VERIFIER = + "uWFwqugDNGiEck/po7KHwwMwwqZgN10XuyBajPGuyzUEV/iree4lOrao5GuwnlQ65CJzbeUB49s31EH+NEkg0JVI5MGCQGMMT/SRPFNRODm3wH/MBiehuFc6FJ/NH6Rmzw==" + const val TEST_SPAKE2P_SALT = "U1BBS0UyUCBLZXkgU2FsdA==" + const val TEST_SPAKE2P_ITERATION_COUNT = 1000 + const val TEST_SETUP_PASSCODE: Long = 20202021 } diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt index 3b38261bf85496..aec7e712c1b59a 100644 --- a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt @@ -1,17 +1,102 @@ package com.matter.virtual.device.app.core.matter +import android.content.Context import chip.appserver.ChipAppServer import chip.appserver.ChipAppServerDelegate +import chip.platform.* +import com.matter.virtual.device.app.Clusters +import com.matter.virtual.device.app.DeviceApp +import com.matter.virtual.device.app.DeviceAppCallback +import com.matter.virtual.device.app.DeviceEventType +import com.matter.virtual.device.app.core.common.MatterConstants +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.matter.manager.OnOffManagerStub +import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import javax.inject.Singleton import timber.log.Timber @Singleton -class MatterApp @Inject constructor() { +class MatterApp +@Inject +constructor( + @ApplicationContext private val context: Context, + private val deviceApp: DeviceApp, + private val onOffManagerStub: OnOffManagerStub +) { + private var androidChipPlatform: AndroidChipPlatform? = null private var chipAppServer: ChipAppServer? = null - fun start() { + fun start(matterSettings: MatterSettings) { + Timber.d("start():$matterSettings") + + deviceApp.setCallback( + object : DeviceAppCallback { + override fun onClusterInit(app: DeviceApp, clusterId: Long, endpoint: Int) { + Timber.d("onClusterInit():clusterId:$clusterId,endpoint:$endpoint") + when (clusterId) { + Clusters.ClusterId_OnOff -> { + app.setOnOffManager(endpoint, onOffManagerStub) + onOffManagerStub.initAttributeValue() + } + } + } + + override fun onEvent(event: Long) { + Timber.d("onEvent():event:$event") + + when (event) { + DeviceEventType.EventId_DnssdInitialized -> { + Timber.d("DNS-SD Platform Initialized") + } + DeviceEventType.EventId_CHIPoBLEConnectionEstablished -> { + Timber.d("BLE Connection Established") + } + DeviceEventType.EventId_CommissioningComplete -> { + Timber.d("Commissioning Complete") + } + DeviceEventType.EventId_FabricRemoved -> { + Timber.d("Fabric Removed") + } + } + } + } + ) + + val preferencesConfigurationManager = PreferencesConfigurationManager(context) + // Write discriminator + try { + preferencesConfigurationManager.writeConfigValueLong( + ConfigurationManager.kConfigNamespace_ChipFactory, + ConfigurationManager.kConfigKey_SetupDiscriminator, + matterSettings.discriminator.toLong() + ) + } catch (e: AndroidChipPlatformException) { + e.printStackTrace() + } + + androidChipPlatform = + AndroidChipPlatform( + AndroidBleManager(), + PreferencesKeyValueStoreManager(context), + preferencesConfigurationManager, + NsdManagerServiceResolver(context), + NsdManagerServiceBrowser(context), + ChipMdnsCallbackImpl(), + DiagnosticDataProviderImpl(context) + ) + + androidChipPlatform?.updateCommissionableDataProviderData( + MatterConstants.TEST_SPAKE2P_VERIFIER, + MatterConstants.TEST_SPAKE2P_SALT, + MatterConstants.TEST_SPAKE2P_ITERATION_COUNT, + MatterConstants.TEST_SETUP_PASSCODE, + matterSettings.discriminator + ) + + deviceApp.preServerInit() + chipAppServer = ChipAppServer() chipAppServer?.startAppWithDelegate( object : ChipAppServerDelegate { @@ -40,6 +125,8 @@ class MatterApp @Inject constructor() { } } ) + + deviceApp.postServerInit(matterSettings.device.deviceTypeId.toInt()) } fun stop() { From 9cb969d575937fe50b4c21491dbbade0c83aa410 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:47:56 +0900 Subject: [PATCH 11/29] virtual-device-app: Add device event callback Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../device/app/core/matter/MatterApp.kt | 27 ++++++++++++++++++- .../core/matter/MatterDeviceEventCallback.kt | 15 +++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterDeviceEventCallback.kt diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt index aec7e712c1b59a..d48b44cbc64dd5 100644 --- a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterApp.kt @@ -27,6 +27,7 @@ constructor( private var androidChipPlatform: AndroidChipPlatform? = null private var chipAppServer: ChipAppServer? = null + private val deviceEventCallbackList = ArrayList() fun start(matterSettings: MatterSettings) { Timber.d("start():$matterSettings") @@ -55,9 +56,11 @@ constructor( } DeviceEventType.EventId_CommissioningComplete -> { Timber.d("Commissioning Complete") + deviceEventCallbackList.forEach { callback -> callback.onCommissioningCompleted() } } DeviceEventType.EventId_FabricRemoved -> { Timber.d("Fabric Removed") + deviceEventCallbackList.forEach { callback -> callback.onFabricRemoved() } } } } @@ -95,13 +98,16 @@ constructor( matterSettings.discriminator ) - deviceApp.preServerInit() + deviceApp.preServerInit() chipAppServer = ChipAppServer() chipAppServer?.startAppWithDelegate( object : ChipAppServerDelegate { override fun onCommissioningSessionEstablishmentStarted() { Timber.d("onCommissioningSessionEstablishmentStarted()") + deviceEventCallbackList.forEach { callback -> + callback.onCommissioningSessionEstablishmentStarted() + } } override fun onCommissioningSessionStarted() { @@ -110,6 +116,9 @@ constructor( override fun onCommissioningSessionEstablishmentError(errorCode: Int) { Timber.d("onCommissioningSessionEstablishmentError():$errorCode") + deviceEventCallbackList.forEach { callback -> + callback.onCommissioningSessionEstablishmentError(errorCode) + } } override fun onCommissioningSessionStopped() { @@ -136,4 +145,20 @@ constructor( fun reset() { chipAppServer?.resetApp() } + + fun addDeviceEventCallback(deviceEventCallback: MatterDeviceEventCallback) { + Timber.d("Hit") + if (!this.deviceEventCallbackList.contains(deviceEventCallback)) { + Timber.d("Add") + this.deviceEventCallbackList.add(deviceEventCallback) + } + } + + fun removeDeviceEventCallback(deviceEventCallback: MatterDeviceEventCallback) { + Timber.d("Hit") + if (this.deviceEventCallbackList.contains(deviceEventCallback)) { + Timber.d("Remove") + this.deviceEventCallbackList.remove(deviceEventCallback) + } + } } diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterDeviceEventCallback.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterDeviceEventCallback.kt new file mode 100644 index 00000000000000..abf3d8d7230243 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterDeviceEventCallback.kt @@ -0,0 +1,15 @@ +package com.matter.virtual.device.app.core.matter + +import timber.log.Timber + +interface MatterDeviceEventCallback { + fun onCommissioningCompleted() = Timber.d("onCommissioningCompleted") + + fun onCommissioningSessionEstablishmentStarted() = + Timber.d("onCommissioningSessionEstablishmentStarted") + + fun onCommissioningSessionEstablishmentError(errorCode: Int) = + Timber.e("onCommissioningSessionEstablishmentError:$errorCode") + + fun onFabricRemoved() = Timber.d("onFabricRemoved") +} From 1136d54a77cbc5db96e7db683850a229b1f28111 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:50:03 +0900 Subject: [PATCH 12/29] virtual-device-app: Add permissions about stack related Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/core/matter/src/main/AndroidManifest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml index a5918e68abcdde..64ad6960a62c3f 100644 --- a/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml +++ b/examples/virtual-device-app/android/App/core/matter/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ - + + \ No newline at end of file From 592f65486caa3319c9925443ef95e6cecdac99cd Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Sun, 6 Aug 2023 23:59:40 +0900 Subject: [PATCH 13/29] virtual-device-app: Implement service managing code Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../App/app/src/main/AndroidManifest.xml | 4 + .../android/App/core/data/build.gradle.kts | 2 + .../core/data/repository/MatterRepository.kt | 5 ++ .../data/repository/MatterRepositoryImpl.kt | 74 ++++++++++++++++++- .../android/App/core/matter/build.gradle.kts | 2 + .../app/core/matter/MatterAppService.kt | 30 +++++++- 6 files changed, 111 insertions(+), 6 deletions(-) diff --git a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml index b971d9fb375a99..a2db5e322bc071 100644 --- a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml +++ b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml @@ -1,10 +1,14 @@ + + + + = Build.VERSION_CODES.O) { + context.startForegroundService(intent) + } else { + context.startService(intent) + } + } + } + + override suspend fun stopMatterAppService() { + Timber.d("stopMatterAppService()") + + if (isMatterAppServiceRunning()) { + val intent = + Intent(context, MatterAppService::class.java).apply { + this.action = MatterAppServiceConstants.ACTION_STOP_MATTER_APP_SERVICE + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(intent) + } else { + context.startService(intent) + } + } + } + + private fun isMatterAppServiceRunning(): Boolean { + val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager? + activityManager?.let { + it.getRunningServices(Integer.MAX_VALUE).forEach { serviceInfo -> + Timber.d("${serviceInfo.service.className}:${MatterAppService::class.java.name}") + if (serviceInfo.service.className == MatterAppService::class.java.name) { + Timber.d("true") + return true + } + } + } + + Timber.d("false") + return false + } } diff --git a/examples/virtual-device-app/android/App/core/matter/build.gradle.kts b/examples/virtual-device-app/android/App/core/matter/build.gradle.kts index 9f94201ac02cf8..c96acdae05c95c 100644 --- a/examples/virtual-device-app/android/App/core/matter/build.gradle.kts +++ b/examples/virtual-device-app/android/App/core/matter/build.gradle.kts @@ -49,6 +49,8 @@ dependencies { implementation(project(":core:common")) implementation(project(":core:model")) + implementation(Deps.Kotlin.serialization) + implementation(Deps.Dagger.hiltAndroid) kapt(Deps.Dagger.hiltAndroidCompiler) diff --git a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterAppService.kt b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterAppService.kt index 0bcbee73e5fcd2..cf78e9f36046bc 100644 --- a/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterAppService.kt +++ b/examples/virtual-device-app/android/App/core/matter/src/main/java/com/matter/virtual/device/app/core/matter/MatterAppService.kt @@ -8,12 +8,19 @@ import android.content.Intent import android.os.Build import android.os.IBinder import androidx.core.app.NotificationCompat +import com.matter.virtual.device.app.core.common.MatterSettings import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import timber.log.Timber @AndroidEntryPoint class MatterAppService : Service() { + @Inject lateinit var matterApp: MatterApp + override fun onCreate() { super.onCreate() Timber.d("onCreate()") @@ -29,17 +36,24 @@ class MatterAppService : Service() { return null } + @OptIn(ExperimentalSerializationApi::class) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Timber.d("Hit") + Timber.d("onStartCommand()") intent?.let { when (it.action) { MatterAppServiceConstants.ACTION_START_MATTER_APP_SERVICE -> { Timber.i("Start matter app service") startService() + val jsonSetting = it.getStringExtra("setting") + jsonSetting?.let { + val matterSettings = Json.decodeFromString(jsonSetting) + startApp(matterSettings) + } } MatterAppServiceConstants.ACTION_STOP_MATTER_APP_SERVICE -> { Timber.i("Stop matter app service") + stopApp() stopService() } else -> {} @@ -69,7 +83,7 @@ class MatterAppService : Service() { } private fun startService() { - Timber.d("Hit") + Timber.d("startService()") createNotificationChannel() @@ -84,9 +98,19 @@ class MatterAppService : Service() { } private fun stopService() { - Timber.d("Hit") + Timber.d("stopService()") cancelNotificationChannel() stopForeground(true) stopSelf() } + + private fun startApp(matterSettings: MatterSettings) { + Timber.d("startApp()") + matterApp.start(matterSettings) + } + + private fun stopApp() { + Timber.d("stopApp()") + matterApp.stop() + } } From c17657e628a8ac3c838d1f457a5d329d196fd3c0 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:07:59 +0900 Subject: [PATCH 14/29] virtual-device-app: Add SharedPreferences feature for managing commissioning state Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/core/common/build.gradle.kts | 1 + .../sharedpreferences/SharedPreferencesKey.kt | 7 +++ .../SharedPreferencesManager.kt | 59 +++++++++++++++++++ .../device/app/core/data/di/DataModule.kt | 10 ++-- .../repository/SharedPreferencesRepository.kt | 19 ++++++ .../SharedPreferencesRepositoryImpl.kt | 40 +++++++++++++ 6 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesKey.kt create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesManager.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepository.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepositoryImpl.kt diff --git a/examples/virtual-device-app/android/App/core/common/build.gradle.kts b/examples/virtual-device-app/android/App/core/common/build.gradle.kts index d424108ab919de..949269ded960ed 100644 --- a/examples/virtual-device-app/android/App/core/common/build.gradle.kts +++ b/examples/virtual-device-app/android/App/core/common/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { implementation(Deps.Navigation.fragment) implementation(Deps.Navigation.ui) + implementation(Deps.timber) implementation(Deps.zxing) testImplementation(Deps.Test.junit) diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesKey.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesKey.kt new file mode 100644 index 00000000000000..a417aee68a784d --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesKey.kt @@ -0,0 +1,7 @@ +package com.matter.virtual.device.app.core.common.sharedpreferences + +object SharedPreferencesKey { + const val COMMISSIONING_DEVICE_COMPLETED = "commissioningDeviceCompleted" + const val COMMISSIONED_DEVICE = "commissionedDevice" + const val COMMISSIONING_SEQUENCE = "commissioningSequence" +} diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesManager.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesManager.kt new file mode 100644 index 00000000000000..2748748c152e86 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/sharedpreferences/SharedPreferencesManager.kt @@ -0,0 +1,59 @@ +package com.matter.virtual.device.app.core.common.sharedpreferences + +import android.content.Context +import android.content.SharedPreferences +import dagger.hilt.android.qualifiers.ApplicationContext +import javax.inject.Inject +import javax.inject.Singleton +import timber.log.Timber + +@Singleton +class SharedPreferencesManager +@Inject +constructor(@ApplicationContext private val context: Context) { + + private val sharedPreferences: SharedPreferences by lazy { + context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) + } + + fun getString(key: String): String { + val value = sharedPreferences.getString(key, DEFAULT_VALUE_STRING) + return value ?: "" + } + + fun setString(key: String, value: String) { + val editor = sharedPreferences.edit() + editor.putString(key, value) + editor.apply() + } + + fun getBoolean(key: String): Boolean { + return sharedPreferences.getBoolean(key, DEFAULT_VALUE_BOOLEAN) + } + + fun setBoolean(key: String, value: Boolean) { + val editor = sharedPreferences.edit() + editor.putBoolean(key, value) + editor.apply() + } + + fun deleteMatterSharedPreferences() { + Timber.d("deleteMatterSharedPreferences()") + if (!context.deleteSharedPreferences(PREFERENCES_NAME_MATTER_KEY_VALUE_STORE)) { + Timber.e("delete failure($PREFERENCES_NAME_MATTER_KEY_VALUE_STORE)") + } + + if (!context.deleteSharedPreferences(PREFERENCES_NAME_MATTER_CONFIGURATION_MANAGER)) { + Timber.e("delete failure($PREFERENCES_NAME_MATTER_CONFIGURATION_MANAGER)") + } + } + + companion object { + private const val PREFERENCES_NAME = "virtualdeviceapp" + private const val PREFERENCES_NAME_MATTER_KEY_VALUE_STORE = "chip.platform.KeyValueStore" + private const val PREFERENCES_NAME_MATTER_CONFIGURATION_MANAGER = + "chip.platform.ConfigurationManager" + private const val DEFAULT_VALUE_STRING = "" + private const val DEFAULT_VALUE_BOOLEAN = false + } +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt index c0352d531da3b5..d411bd13c30c71 100644 --- a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt @@ -1,9 +1,6 @@ package com.matter.virtual.device.app.core.data.di -import com.matter.virtual.device.app.core.data.repository.MatterRepository -import com.matter.virtual.device.app.core.data.repository.MatterRepositoryImpl -import com.matter.virtual.device.app.core.data.repository.NetworkRepository -import com.matter.virtual.device.app.core.data.repository.NetworkRepositoryImpl +import com.matter.virtual.device.app.core.data.repository.* import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -16,4 +13,9 @@ internal abstract class DataModule { @Binds abstract fun bindMatterRepository(repository: MatterRepositoryImpl): MatterRepository @Binds abstract fun bindNetworkRepository(repository: NetworkRepositoryImpl): NetworkRepository + + @Binds + abstract fun bindSharedPreferencesRepository( + repository: SharedPreferencesRepositoryImpl + ): SharedPreferencesRepository } diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepository.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepository.kt new file mode 100644 index 00000000000000..20451881821664 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepository.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.data.repository + +import com.matter.virtual.device.app.core.common.Device + +interface SharedPreferencesRepository { + suspend fun isCommissioningDeviceCompleted(): Boolean + + suspend fun setCommissioningDeviceCompleted(value: Boolean) + + suspend fun getCommissionedDevice(): Device + + suspend fun setCommissionedDevice(device: Device) + + suspend fun deleteMatterSharedPreferences() + + suspend fun setCommissioningSequence(value: Boolean) + + suspend fun isCommissioningSequence(): Boolean +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepositoryImpl.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepositoryImpl.kt new file mode 100644 index 00000000000000..9da11f0d23bf98 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/SharedPreferencesRepositoryImpl.kt @@ -0,0 +1,40 @@ +package com.matter.virtual.device.app.core.data.repository + +import com.matter.virtual.device.app.core.common.Device +import com.matter.virtual.device.app.core.common.sharedpreferences.SharedPreferencesKey +import com.matter.virtual.device.app.core.common.sharedpreferences.SharedPreferencesManager +import javax.inject.Inject + +internal class SharedPreferencesRepositoryImpl +@Inject +constructor(private val sharedPreferencesManager: SharedPreferencesManager) : + SharedPreferencesRepository { + + override suspend fun isCommissioningDeviceCompleted(): Boolean { + return sharedPreferencesManager.getBoolean(SharedPreferencesKey.COMMISSIONING_DEVICE_COMPLETED) + } + + override suspend fun setCommissioningDeviceCompleted(value: Boolean) { + sharedPreferencesManager.setBoolean(SharedPreferencesKey.COMMISSIONING_DEVICE_COMPLETED, value) + } + + override suspend fun getCommissionedDevice(): Device { + return Device.map(sharedPreferencesManager.getString(SharedPreferencesKey.COMMISSIONED_DEVICE)) + } + + override suspend fun setCommissionedDevice(device: Device) { + sharedPreferencesManager.setString(SharedPreferencesKey.COMMISSIONED_DEVICE, device.title) + } + + override suspend fun deleteMatterSharedPreferences() { + sharedPreferencesManager.deleteMatterSharedPreferences() + } + + override suspend fun setCommissioningSequence(value: Boolean) { + sharedPreferencesManager.setBoolean(SharedPreferencesKey.COMMISSIONING_SEQUENCE, value) + } + + override suspend fun isCommissioningSequence(): Boolean { + return sharedPreferencesManager.getBoolean(SharedPreferencesKey.COMMISSIONING_SEQUENCE) + } +} From 8107188d98680d333e9b746345bb9a9f6e4b879e Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:11:53 +0900 Subject: [PATCH 15/29] virtual-device-app: Add OnOffManager repository Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/core/data/build.gradle.kts | 6 ++++++ .../device/app/core/data/di/DataModule.kt | 7 +++++++ .../cluster/OnOffManagerRepository.kt | 9 ++++++++ .../cluster/OnOffManagerRepositoryImpl.kt | 21 +++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepository.kt create mode 100644 examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepositoryImpl.kt diff --git a/examples/virtual-device-app/android/App/core/data/build.gradle.kts b/examples/virtual-device-app/android/App/core/data/build.gradle.kts index 288ef7d63668fc..5d724f34d3cca7 100644 --- a/examples/virtual-device-app/android/App/core/data/build.gradle.kts +++ b/examples/virtual-device-app/android/App/core/data/build.gradle.kts @@ -36,9 +36,15 @@ android { kotlinOptions { jvmTarget = "1.8" } + sourceSets { + getByName("main") { + jniLibs.setSrcDirs(listOf("../../app/libs/jniLibs")) + } + } } dependencies { + implementation(fileTree(mapOf("dir" to "../../app/libs", "include" to listOf("*.jar")))) implementation(project(":core:common")) implementation(project(":core:matter")) diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt index d411bd13c30c71..8168f632c10275 100644 --- a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/di/DataModule.kt @@ -1,6 +1,8 @@ package com.matter.virtual.device.app.core.data.di import com.matter.virtual.device.app.core.data.repository.* +import com.matter.virtual.device.app.core.data.repository.cluster.OnOffManagerRepository +import com.matter.virtual.device.app.core.data.repository.cluster.OnOffManagerRepositoryImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -10,6 +12,11 @@ import dagger.hilt.components.SingletonComponent @Module internal abstract class DataModule { + @Binds + abstract fun bindOnOffManagerRepository( + repository: OnOffManagerRepositoryImpl + ): OnOffManagerRepository + @Binds abstract fun bindMatterRepository(repository: MatterRepositoryImpl): MatterRepository @Binds abstract fun bindNetworkRepository(repository: NetworkRepositoryImpl): NetworkRepository diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepository.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepository.kt new file mode 100644 index 00000000000000..5b168469bbea53 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepository.kt @@ -0,0 +1,9 @@ +package com.matter.virtual.device.app.core.data.repository.cluster + +import kotlinx.coroutines.flow.StateFlow + +interface OnOffManagerRepository { + fun getOnOffFlow(): StateFlow + + suspend fun setOnOff(value: Boolean) +} diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepositoryImpl.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepositoryImpl.kt new file mode 100644 index 00000000000000..33f9113c00778e --- /dev/null +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/cluster/OnOffManagerRepositoryImpl.kt @@ -0,0 +1,21 @@ +package com.matter.virtual.device.app.core.data.repository.cluster + +import com.matter.virtual.device.app.core.matter.manager.OnOffManagerStub +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow +import timber.log.Timber + +internal class OnOffManagerRepositoryImpl +@Inject +constructor(private val onOffManagerStub: OnOffManagerStub) : OnOffManagerRepository { + + override fun getOnOffFlow(): StateFlow { + Timber.d("Hit") + return onOffManagerStub.onOff + } + + override suspend fun setOnOff(value: Boolean) { + Timber.d("value:$value") + onOffManagerStub.setOnOff(value) + } +} From c091d600643c4f925ea1b8858d57c97490836701 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:15:24 +0900 Subject: [PATCH 16/29] virtual-device-app: Update matter repository for device event callback Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../core/data/repository/MatterRepository.kt | 10 ++- .../data/repository/MatterRepositoryImpl.kt | 71 ++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt index eabf56b26dc905..cefb125c066269 100644 --- a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepository.kt @@ -10,5 +10,13 @@ interface MatterRepository { suspend fun startMatterAppService(matterSettings: MatterSettings) - suspend fun stopMatterAppService() + suspend fun stopMatterAppService() + + fun reset() + + suspend fun isCommissioningCompleted(): Boolean + + suspend fun isCommissioningSessionEstablishmentStarted(): Boolean + + suspend fun isFabricRemoved(): Boolean } diff --git a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt index 2e93ed6c50573d..04911eb0758229 100644 --- a/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt +++ b/examples/virtual-device-app/android/App/core/data/src/main/java/com/matter/virtual/device/app/core/data/repository/MatterRepositoryImpl.kt @@ -9,6 +9,9 @@ import com.matter.virtual.device.app.core.matter.* import com.matter.virtual.device.app.core.model.Payload import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject +import kotlin.coroutines.resume +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withTimeout import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -67,6 +70,72 @@ constructor( } } + override fun reset() { + Timber.d("reset()") + matterApp.reset() + } + + override suspend fun isCommissioningCompleted() = + withTimeout(300000) { + suspendCancellableCoroutine { cancellableContinuation -> + Timber.d("isCommissioningCompleted()") + val deviceEventCallback = + object : MatterDeviceEventCallback { + override fun onCommissioningCompleted() { + Timber.d("onCommissioningCompleted()") + if (cancellableContinuation.isActive) { + cancellableContinuation.resume(true) + } + } + } + + matterApp.addDeviceEventCallback(deviceEventCallback) + + cancellableContinuation.invokeOnCancellation { + matterApp.removeDeviceEventCallback(deviceEventCallback) + } + } + } + + override suspend fun isCommissioningSessionEstablishmentStarted() = + suspendCancellableCoroutine { cancellableContinuation -> + Timber.d("isCommissioningSessionEstablishmentStarted()") + val deviceEventCallback = + object : MatterDeviceEventCallback { + override fun onCommissioningSessionEstablishmentStarted() { + Timber.d("onCommissioningSessionEstablishmentStarted()") + if (cancellableContinuation.isActive) { + cancellableContinuation.resume(true) + } + } + } + + matterApp.addDeviceEventCallback(deviceEventCallback) + + cancellableContinuation.invokeOnCancellation { + matterApp.removeDeviceEventCallback(deviceEventCallback) + } + } + + override suspend fun isFabricRemoved() = suspendCancellableCoroutine { cancellableContinuation -> + Timber.d("isFabricRemoved()") + val deviceEventCallback = + object : MatterDeviceEventCallback { + override fun onFabricRemoved() { + Timber.d("onFabricRemoved()") + if (cancellableContinuation.isActive) { + cancellableContinuation.resume(true) + } + } + } + + matterApp.addDeviceEventCallback(deviceEventCallback) + + cancellableContinuation.invokeOnCancellation { + matterApp.removeDeviceEventCallback(deviceEventCallback) + } + } + private fun isMatterAppServiceRunning(): Boolean { val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager? activityManager?.let { @@ -81,5 +150,5 @@ constructor( Timber.d("false") return false - } + } } From c510c45cd5b313ca13a1447725205e6bf00b8d41 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:17:35 +0900 Subject: [PATCH 17/29] virtual-device-app: Implement sharedpreferences usecase Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../GetCommissionedDeviceUseCase.kt | 20 +++++++++++++++++++ .../IsCommissioningDeviceCompletedUseCase.kt | 19 ++++++++++++++++++ .../IsCommissioningSequenceUseCase.kt | 19 ++++++++++++++++++ .../SetCommissionedDeviceUseCase.kt | 20 +++++++++++++++++++ .../SetCommissioningDeviceCompletedUseCase.kt | 19 ++++++++++++++++++ .../SetCommissioningSequenceFlagUseCase.kt | 19 ++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/GetCommissionedDeviceUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningDeviceCompletedUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningSequenceUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissionedDeviceUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningDeviceCompletedUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningSequenceFlagUseCase.kt diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/GetCommissionedDeviceUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/GetCommissionedDeviceUseCase.kt new file mode 100644 index 00000000000000..6ae545ac51b6b1 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/GetCommissionedDeviceUseCase.kt @@ -0,0 +1,20 @@ +package com.matter.virtual.device.app.core.domain.usecase.sharedpreferences + +import com.matter.virtual.device.app.core.common.Device +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class GetCommissionedDeviceUseCase +@Inject +constructor( + private val sharedPreferencesRepository: SharedPreferencesRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): Device { + return sharedPreferencesRepository.getCommissionedDevice() + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningDeviceCompletedUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningDeviceCompletedUseCase.kt new file mode 100644 index 00000000000000..7aa55f6f635d10 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningDeviceCompletedUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.sharedpreferences + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class IsCommissioningDeviceCompletedUseCase +@Inject +constructor( + private val sharedPreferencesRepository: SharedPreferencesRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): Boolean { + return sharedPreferencesRepository.isCommissioningDeviceCompleted() + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningSequenceUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningSequenceUseCase.kt new file mode 100644 index 00000000000000..ae8dff2ff9b7ce --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/IsCommissioningSequenceUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.sharedpreferences + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class IsCommissioningSequenceUseCase +@Inject +constructor( + private val sharedPreferencesRepository: SharedPreferencesRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): Boolean { + return sharedPreferencesRepository.isCommissioningSequence() + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissionedDeviceUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissionedDeviceUseCase.kt new file mode 100644 index 00000000000000..223c5824f62f55 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissionedDeviceUseCase.kt @@ -0,0 +1,20 @@ +package com.matter.virtual.device.app.core.domain.usecase.sharedpreferences + +import com.matter.virtual.device.app.core.common.Device +import com.matter.virtual.device.app.core.common.di.MainImmediateDispatcher +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class SetCommissionedDeviceUseCase +@Inject +constructor( + private val sharedPreferencesRepository: SharedPreferencesRepository, + @MainImmediateDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: Device) { + sharedPreferencesRepository.setCommissionedDevice(param) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningDeviceCompletedUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningDeviceCompletedUseCase.kt new file mode 100644 index 00000000000000..c6d4bcd484dbea --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningDeviceCompletedUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.sharedpreferences + +import com.matter.virtual.device.app.core.common.di.MainImmediateDispatcher +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class SetCommissioningDeviceCompletedUseCase +@Inject +constructor( + private val sharedPreferencesRepository: SharedPreferencesRepository, + @MainImmediateDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: Boolean) { + sharedPreferencesRepository.setCommissioningDeviceCompleted(param) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningSequenceFlagUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningSequenceFlagUseCase.kt new file mode 100644 index 00000000000000..e748dba04fdcf1 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/sharedpreferences/SetCommissioningSequenceFlagUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.sharedpreferences + +import com.matter.virtual.device.app.core.common.di.MainImmediateDispatcher +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class SetCommissioningSequenceFlagUseCase +@Inject +constructor( + private val sharedPreferencesRepository: SharedPreferencesRepository, + @MainImmediateDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: Boolean) { + sharedPreferencesRepository.setCommissioningSequence(param) + } +} From da9f523347d2a5e39dd8377f8bcdb853f5dc9e33 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:21:18 +0900 Subject: [PATCH 18/29] virtual-device-app: Implement matter usecase Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/core/domain/build.gradle.kts | 1 + .../matter/IsCommissioningCompletedUseCase.kt | 28 +++++++++++++++++++ ...ommissioningSessionEstablishmentStarted.kt | 19 +++++++++++++ .../usecase/matter/IsFabricRemovedUseCase.kt | 19 +++++++++++++ .../usecase/matter/ResetMatterAppUseCase.kt | 25 +++++++++++++++++ .../matter/StartMatterAppServiceUseCase.kt | 20 +++++++++++++ .../matter/cluster/GetOnOffFlowUseCase.kt | 11 ++++++++ .../usecase/matter/cluster/SetOnOffUseCase.kt | 19 +++++++++++++ 8 files changed, 142 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningCompletedUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningSessionEstablishmentStarted.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsFabricRemovedUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/ResetMatterAppUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/StartMatterAppServiceUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/GetOnOffFlowUseCase.kt create mode 100644 examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/SetOnOffUseCase.kt diff --git a/examples/virtual-device-app/android/App/core/domain/build.gradle.kts b/examples/virtual-device-app/android/App/core/domain/build.gradle.kts index 6cc2a239897333..ef6313020146c0 100644 --- a/examples/virtual-device-app/android/App/core/domain/build.gradle.kts +++ b/examples/virtual-device-app/android/App/core/domain/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { implementation(Deps.Kotlin.coroutinesCore) implementation(Deps.inject) + implementation(Deps.timber) testImplementation(Deps.Test.junit) androidTestImplementation(Deps.Test.junitExt) diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningCompletedUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningCompletedUseCase.kt new file mode 100644 index 00000000000000..d7cfb92c85d6cb --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningCompletedUseCase.kt @@ -0,0 +1,28 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import timber.log.Timber + +class IsCommissioningCompletedUseCase +@Inject +constructor( + private val matterRepository: MatterRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): Boolean { + var result = false + + runCatching { result = matterRepository.isCommissioningCompleted() } + .onFailure { + Timber.e(it, "error") + result = false + } + + return result + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningSessionEstablishmentStarted.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningSessionEstablishmentStarted.kt new file mode 100644 index 00000000000000..ad666f1a9d23c5 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsCommissioningSessionEstablishmentStarted.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class IsCommissioningSessionEstablishmentStarted +@Inject +constructor( + private val matterRepository: MatterRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): Boolean { + return matterRepository.isCommissioningSessionEstablishmentStarted() + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsFabricRemovedUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsFabricRemovedUseCase.kt new file mode 100644 index 00000000000000..0bf063b4205ecb --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/IsFabricRemovedUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class IsFabricRemovedUseCase +@Inject +constructor( + private val matterRepository: MatterRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute(): Boolean { + return matterRepository.isFabricRemoved() + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/ResetMatterAppUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/ResetMatterAppUseCase.kt new file mode 100644 index 00000000000000..1275a33a182380 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/ResetMatterAppUseCase.kt @@ -0,0 +1,25 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.data.repository.SharedPreferencesRepository +import com.matter.virtual.device.app.core.domain.NonParamCoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class ResetMatterAppUseCase +@Inject +constructor( + private val matterRepository: MatterRepository, + private val sharedPreferencesRepository: SharedPreferencesRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : NonParamCoroutineUseCase(dispatcher) { + + override suspend fun execute() { + matterRepository.reset() + matterRepository.stopMatterAppService() + sharedPreferencesRepository.deleteMatterSharedPreferences() + sharedPreferencesRepository.setCommissioningDeviceCompleted(false) + sharedPreferencesRepository.setCommissioningSequence(false) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/StartMatterAppServiceUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/StartMatterAppServiceUseCase.kt new file mode 100644 index 00000000000000..9f8bfb24368cca --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/StartMatterAppServiceUseCase.kt @@ -0,0 +1,20 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter + +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.MatterRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class StartMatterAppServiceUseCase +@Inject +constructor( + private val matterRepository: MatterRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: MatterSettings) { + matterRepository.startMatterAppService(param) + } +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/GetOnOffFlowUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/GetOnOffFlowUseCase.kt new file mode 100644 index 00000000000000..02685602405674 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/GetOnOffFlowUseCase.kt @@ -0,0 +1,11 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter.cluster + +import com.matter.virtual.device.app.core.data.repository.cluster.OnOffManagerRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +class GetOnOffFlowUseCase +@Inject +constructor(private val onOffManagerRepository: OnOffManagerRepository) { + operator fun invoke(): StateFlow = onOffManagerRepository.getOnOffFlow() +} diff --git a/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/SetOnOffUseCase.kt b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/SetOnOffUseCase.kt new file mode 100644 index 00000000000000..3a147fa5e897d3 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/domain/src/main/java/com/matter/virtual/device/app/core/domain/usecase/matter/cluster/SetOnOffUseCase.kt @@ -0,0 +1,19 @@ +package com.matter.virtual.device.app.core.domain.usecase.matter.cluster + +import com.matter.virtual.device.app.core.common.di.IoDispatcher +import com.matter.virtual.device.app.core.data.repository.cluster.OnOffManagerRepository +import com.matter.virtual.device.app.core.domain.CoroutineUseCase +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher + +class SetOnOffUseCase +@Inject +constructor( + private val onOffManagerRepository: OnOffManagerRepository, + @IoDispatcher dispatcher: CoroutineDispatcher +) : CoroutineUseCase(dispatcher) { + + override suspend fun execute(param: Boolean) { + onOffManagerRepository.setOnOff(param) + } +} From fdc8f869f5716e8ccad2f44acb35802bdba3dd70 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:26:30 +0900 Subject: [PATCH 19/29] virtual-device-app: Add ignore batter optimization feature Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../App/app/src/main/AndroidManifest.xml | 1 + .../matter/virtual/device/app/MainActivity.kt | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml index a2db5e322bc071..ba892cba76bd9e 100644 --- a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml +++ b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ + + if (!manager.isIgnoringBatteryOptimizations(packageName)) { + Timber.d("not in battery optimization whitelist") + val intent = + Intent().apply { + action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS + data = Uri.parse("package:$packageName") + } + startActivity(intent) + } + } + binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) } From 3820c5288f5d2ab16b3b2f43e6bf3f9c24442be6 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:31:08 +0900 Subject: [PATCH 20/29] virtual-device-app: Add SharedViewModel for managing reset popup Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/app/build.gradle.kts | 1 + .../matter/virtual/device/app/MainActivity.kt | 51 ++++++++++++++++++ .../virtual/device/app/core/common/Event.kt | 25 +++++++++ .../device/app/core/ui/SharedViewModel.kt | 52 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Event.kt create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/SharedViewModel.kt diff --git a/examples/virtual-device-app/android/App/app/build.gradle.kts b/examples/virtual-device-app/android/App/app/build.gradle.kts index 3b139f2b61b6ad..dbc45d07e0694a 100644 --- a/examples/virtual-device-app/android/App/app/build.gradle.kts +++ b/examples/virtual-device-app/android/App/app/build.gradle.kts @@ -76,6 +76,7 @@ dependencies { implementation(project(":core:data")) implementation(project(":core:domain")) implementation(project(":core:model")) + implementation(project(":core:ui")) implementation(project(":feature:main")) implementation(project(":feature:qrcode")) implementation(project(":feature:setup")) diff --git a/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt b/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt index 9b15c211fbfde6..26ba166cb00866 100644 --- a/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt +++ b/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt @@ -8,10 +8,17 @@ import android.net.Uri import android.os.Bundle import android.os.PowerManager import android.provider.Settings +import android.view.Gravity import android.view.MenuItem +import android.view.View import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat +import com.matter.virtual.device.app.core.common.EventObserver +import com.matter.virtual.device.app.core.ui.SharedViewModel +import com.matter.virtual.device.app.core.ui.UiState import com.matter.virtual.device.app.databinding.ActivityMainBinding import dagger.hilt.android.AndroidEntryPoint import timber.log.Timber @@ -20,6 +27,7 @@ import timber.log.Timber class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding + private val viewModel by viewModels() private val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) @@ -57,6 +65,25 @@ class MainActivity : AppCompatActivity() { binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + + viewModel.uiState.observe( + this, + EventObserver { uiState -> + when (uiState) { + UiState.Waiting -> { + binding.progress.visibility = View.VISIBLE + } + UiState.Exit -> { + binding.progress.visibility = View.GONE + finishAffinity() + } + is UiState.Reset -> { + showFactoryResetPopup(getString(uiState.messageResId), uiState.isCancelable) + } + else -> {} + } + } + ) } override fun onDestroy() { @@ -83,4 +110,28 @@ class MainActivity : AppCompatActivity() { Timber.d("RequestCode:$requestCode") super.onRequestPermissionsResult(requestCode, permissions, grantResults) } + + private fun showFactoryResetPopup(message: String, isCancelable: Boolean) { + val builder = + AlertDialog.Builder(this) + .setTitle("Factory Reset") + .setMessage(message) + .setPositiveButton("Ok") { dialog, _ -> + Timber.d("Ok") + dialog.dismiss() + viewModel.resetMatterAppServer() + } + .setCancelable(false) + + if (isCancelable) { + builder.setNegativeButton("Cancel") { dialog, _ -> + Timber.d("Cancel") + dialog.dismiss() + } + } + + val dialog = builder.create() + dialog.window?.setGravity(Gravity.BOTTOM) + dialog.show() + } } diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Event.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Event.kt new file mode 100644 index 00000000000000..f9eb734468292a --- /dev/null +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/Event.kt @@ -0,0 +1,25 @@ +package com.matter.virtual.device.app.core.common + +import androidx.lifecycle.Observer + +open class Event(private val content: T) { + var hasBeenHandled = false + private set + + fun getContentIfNotHandled(): T? { + return if (hasBeenHandled) { + null + } else { + hasBeenHandled = true + content + } + } + + fun peekContent(): T = content +} + +class EventObserver(private val onEventUnHandledContent: (T) -> Unit) : Observer> { + override fun onChanged(event: Event?) { + event?.getContentIfNotHandled()?.let { value -> onEventUnHandledContent(value) } + } +} diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/SharedViewModel.kt b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/SharedViewModel.kt new file mode 100644 index 00000000000000..fa588ec9f60cc0 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/SharedViewModel.kt @@ -0,0 +1,52 @@ +package com.matter.virtual.device.app.core.ui + +import androidx.annotation.StringRes +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.matter.virtual.device.app.core.common.Event +import com.matter.virtual.device.app.core.domain.usecase.matter.ResetMatterAppUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import timber.log.Timber + +@HiltViewModel +class SharedViewModel +@Inject +constructor(private val resetMatterAppUseCase: ResetMatterAppUseCase) : ViewModel() { + + private val _uiState = MutableLiveData>() + val uiState: LiveData> + get() = _uiState + + override fun onCleared() { + Timber.d("onCleared()") + super.onCleared() + } + + fun requestFactoryReset(@StringRes messageResId: Int, isCancelable: Boolean) { + Timber.d("Hit") + viewModelScope.launch { _uiState.value = Event(UiState.Reset(messageResId, isCancelable)) } + } + + fun resetMatterAppServer() { + Timber.d("Hit") + viewModelScope.launch { + _uiState.value = Event(UiState.Waiting) + resetMatterAppUseCase() + delay(1500) + _uiState.value = Event(UiState.Exit) + } + } +} + +sealed class UiState { + data class Reset(@StringRes val messageResId: Int, val isCancelable: Boolean) : UiState() + + object Waiting : UiState() + + object Exit : UiState() +} From b3cdfb66da24fcd0bab0ec7bc1e5dac73857cf48 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:37:21 +0900 Subject: [PATCH 21/29] virtual-device-app: Implement main view scenario - go to commissioned device view - reset abnormal state - start commissioning Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../device/app/core/common/DeepLink.kt | 14 +++ .../android/App/feature/main/build.gradle.kts | 1 + .../device/app/feature/main/MainFragment.kt | 98 +++++++++++++------ .../device/app/feature/main/MainViewModel.kt | 78 +++++++++++++++ .../main/src/main/res/values/strings.xml | 2 + 5 files changed, 165 insertions(+), 28 deletions(-) create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainViewModel.kt diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt index 78e6649de44b43..2e24a9246888b5 100644 --- a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt +++ b/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/DeepLink.kt @@ -2,6 +2,7 @@ package com.matter.virtual.device.app.core.common import androidx.core.net.toUri import androidx.navigation.NavDeepLinkRequest +import timber.log.Timber object DeepLink { fun getDeepLinkRequestForQrcodeFragment(setting: String): NavDeepLinkRequest { @@ -26,4 +27,17 @@ object DeepLink { ) .build() } + + fun getDeepLinkRequestFromDevice(device: Device, setting: String): NavDeepLinkRequest { + Timber.d("setting:$setting") + val uri = + when (device) { + Device.OnOffSwitch -> + "android-app://com.matter.virtual.device.app.feature.control/onOffSwitchFragment/${setting}" + .toUri() + Device.Unknown -> throw UnsupportedOperationException("Unsupported device") + } + + return NavDeepLinkRequest.Builder.fromUri(uri).build() + } } diff --git a/examples/virtual-device-app/android/App/feature/main/build.gradle.kts b/examples/virtual-device-app/android/App/feature/main/build.gradle.kts index c9931cf58938e4..500ac8d758212f 100644 --- a/examples/virtual-device-app/android/App/feature/main/build.gradle.kts +++ b/examples/virtual-device-app/android/App/feature/main/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(project(":core:common")) implementation(project(":core:domain")) implementation(project(":core:model")) + implementation(project(":core:ui")) implementation(Deps.AndroidX.core) implementation(Deps.AndroidX.appcompat) diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt index 55ebdace76a00e..861bf01b257817 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainFragment.kt @@ -9,10 +9,14 @@ import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.navigation.NavOptions import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.matter.virtual.device.app.core.common.DeepLink import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.ui.SharedViewModel import com.matter.virtual.device.app.feature.main.databinding.FragmentMainBinding import com.matter.virtual.device.app.feature.main.model.Menu import dagger.hilt.android.AndroidEntryPoint @@ -26,6 +30,9 @@ import timber.log.Timber class MainFragment : Fragment() { private lateinit var binding: FragmentMainBinding + private val viewModel by viewModels() + private val sharedViewModel by activityViewModels() + private lateinit var onBackPressedCallback: OnBackPressedCallback override fun onCreateView( @@ -33,7 +40,7 @@ class MainFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View { - Timber.d("Hit") + Timber.d("onCreateView()") binding = DataBindingUtil.inflate(inflater, R.layout.fragment_main, container, false) binding.lifecycleOwner = viewLifecycleOwner @@ -42,7 +49,7 @@ class MainFragment : Fragment() { @OptIn(ExperimentalSerializationApi::class) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - Timber.d("Hit") + Timber.d("onViewCreated()") super.onViewCreated(view, savedInstanceState) (activity as AppCompatActivity).setSupportActionBar(binding.toolbar) @@ -58,34 +65,69 @@ class MainFragment : Fragment() { binding.toolbarTitle.alpha = (ratio - 0.5f) * 2f + 0.1f } - val itemList = arrayListOf(Menu.ON_OFF_SWITCH) - - val menuAdapter = - MenuAdapter( - object : MenuAdapter.ItemHandler { - override fun onClick(item: Menu) { - val matterSettings = MatterSettings(device = item.device) - val jsonSettings = Json.encodeToString(matterSettings) - try { - findNavController() - .navigate(DeepLink.getDeepLinkRequestForSetupFragment(jsonSettings)) - } catch (e: Exception) { - Timber.e(e, "navigate failure") - } + viewModel.uiState.observe(viewLifecycleOwner) { uiState -> + Timber.d("uiState:$uiState") + when (uiState) { + MainUiState.Loading -> {} + is MainUiState.CommissioningCompleted -> { + try { + val navOptions = + NavOptions.Builder() + .setPopUpTo(destinationId = R.id.mainFragment, inclusive = true) + .build() + + findNavController() + .navigate( + DeepLink.getDeepLinkRequestFromDevice( + uiState.device, + Json.encodeToString(MatterSettings(device = uiState.device)) + ), + navOptions + ) + } catch (e: Exception) { + Timber.e("navigate failure") + } + } + is MainUiState.Reset -> { + sharedViewModel.requestFactoryReset( + messageResId = uiState.messageResId, + isCancelable = uiState.isCancelable + ) + } + MainUiState.Start -> { + val itemList = arrayListOf(Menu.ON_OFF_SWITCH) + + val menuAdapter = + MenuAdapter( + object : MenuAdapter.ItemHandler { + override fun onClick(item: Menu) { + viewModel.consumeUiState() + + val matterSettings = MatterSettings(device = item.device) + val jsonSettings = Json.encodeToString(matterSettings) + try { + findNavController() + .navigate(DeepLink.getDeepLinkRequestForSetupFragment(jsonSettings)) + } catch (e: Exception) { + Timber.e(e, "navigate failure") + } + } + } + ) + .apply { submitList(itemList) } + + val sideSpace = resources.getDimension(R.dimen.menu_item_side_space).toInt() + val bottomSpace = resources.getDimension(R.dimen.menu_item_bottom_space).toInt() + + binding.recyclerView.apply { + layoutManager = LinearLayoutManager(requireContext()) + if (itemDecorationCount == 0) { + addItemDecoration(VerticalSpaceItemDecoration(sideSpace, bottomSpace)) } + adapter = menuAdapter } - ) - .apply { submitList(itemList) } - - val sideSpace = resources.getDimension(R.dimen.menu_item_side_space).toInt() - val bottomSpace = resources.getDimension(R.dimen.menu_item_bottom_space).toInt() - - binding.recyclerView.apply { - layoutManager = LinearLayoutManager(requireContext()) - if (itemDecorationCount == 0) { - addItemDecoration(VerticalSpaceItemDecoration(sideSpace, bottomSpace)) + } } - adapter = menuAdapter } } @@ -95,7 +137,7 @@ class MainFragment : Fragment() { } override fun onAttach(context: Context) { - Timber.d("Hit") + Timber.d("onAttach()") super.onAttach(context) onBackPressedCallback = diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainViewModel.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainViewModel.kt new file mode 100644 index 00000000000000..c776b2468de3f6 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/MainViewModel.kt @@ -0,0 +1,78 @@ +package com.matter.virtual.device.app.feature.main + +import androidx.annotation.StringRes +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.matter.virtual.device.app.core.common.Device +import com.matter.virtual.device.app.core.common.successOr +import com.matter.virtual.device.app.core.domain.usecase.sharedpreferences.GetCommissionedDeviceUseCase +import com.matter.virtual.device.app.core.domain.usecase.sharedpreferences.IsCommissioningDeviceCompletedUseCase +import com.matter.virtual.device.app.core.domain.usecase.sharedpreferences.IsCommissioningSequenceUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import timber.log.Timber + +@HiltViewModel +class MainViewModel +@Inject +constructor( + private val isCommissioningDeviceCompletedUseCase: IsCommissioningDeviceCompletedUseCase, + private val getCommissionedDeviceUseCase: GetCommissionedDeviceUseCase, + private val isCommissioningSequenceUseCase: IsCommissioningSequenceUseCase, +) : ViewModel() { + + private val _uiState = MutableLiveData(MainUiState.Loading) + val uiState: LiveData + get() = _uiState + + init { + viewModelScope.launch { + val isCommissioningSequence = isCommissioningSequenceUseCase().successOr(false) + if (isCommissioningSequence) { + Timber.e("Need factory reset") + _uiState.value = + MainUiState.Reset( + messageResId = R.string.dialog_force_factory_reset_message, + isCancelable = false + ) + this.cancel() + return@launch + } + + val isCommissioningDeviceCompleted = isCommissioningDeviceCompletedUseCase().successOr(false) + val commissionedDevice = getCommissionedDeviceUseCase().successOr(Device.Unknown) + + if (isCommissioningDeviceCompleted) { + Timber.d("Go to commissioned device") + _uiState.value = MainUiState.CommissioningCompleted(commissionedDevice) + } else { + Timber.d("Start commissioning") + _uiState.value = MainUiState.Start + } + } + } + + override fun onCleared() { + Timber.d("onCleared()") + super.onCleared() + } + + fun consumeUiState() { + Timber.d("consumeUiState()") + viewModelScope.launch { _uiState.value = MainUiState.Start } + } +} + +sealed class MainUiState { + object Loading : MainUiState() + + object Start : MainUiState() + + data class CommissioningCompleted(val device: Device) : MainUiState() + + data class Reset(@StringRes val messageResId: Int, val isCancelable: Boolean) : MainUiState() +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml index 23e5916e74f482..c253068a8e9e68 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml @@ -3,4 +3,6 @@ Matter Virtual Device Loading Commissioning in process. + + "The last commissioning was not completed. The Matter device app will be reset and closed." \ No newline at end of file From 058bace65ad507511b1d95a722d0eb64ea6c6cc8 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 00:45:42 +0900 Subject: [PATCH 22/29] virtual-device-app: Implement qrcode view scenario - start MatterAppService - monitoring establishment started event Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../core}/ui/DisableAppBarLayoutBehavior.kt | 2 +- .../core/ui/src/main/res/values/strings.xml | 4 + .../src/main/res/layout/fragment_loading.xml | 2 +- .../App/feature/qrcode/build.gradle.kts | 1 + .../app/feature/qrcode/QrcodeFragment.kt | 128 ++++++++++-------- .../app/feature/qrcode/QrcodeViewModel.kt | 23 +++- .../src/main/res/layout/fragment_qrcode.xml | 2 +- 7 files changed, 100 insertions(+), 62 deletions(-) rename examples/virtual-device-app/android/App/core/{common/src/main/java/com/matter/virtual/device/app/core/common => ui/src/main/java/com/matter/virtual/device/app/core}/ui/DisableAppBarLayoutBehavior.kt (93%) create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml diff --git a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/DisableAppBarLayoutBehavior.kt similarity index 93% rename from examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt rename to examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/DisableAppBarLayoutBehavior.kt index 929306fbdc92f8..6818a549b441e7 100644 --- a/examples/virtual-device-app/android/App/core/common/src/main/java/com/matter/virtual/device/app/core/common/ui/DisableAppBarLayoutBehavior.kt +++ b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/DisableAppBarLayoutBehavior.kt @@ -1,4 +1,4 @@ -package com.matter.virtual.device.app.core.common.ui +package com.matter.virtual.device.app.core.ui import android.content.Context import android.util.AttributeSet diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml new file mode 100644 index 00000000000000..2ce8c78fcd7df6 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + "The commissioning was not completed. The Matter device app will be reset and closed. Continue?" + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml index 852207c49e1b6f..a76061ed6ca8e4 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/layout/fragment_loading.xml @@ -15,7 +15,7 @@ android:fitsSystemWindows="true" app:elevation="0dp" app:expanded="false" - app:layout_behavior="com.matter.virtual.device.app.core.common.ui.DisableAppBarLayoutBehavior"> + app:layout_behavior="com.matter.virtual.device.app.core.ui.DisableAppBarLayoutBehavior"> () + private val sharedViewModel by activityViewModels() private lateinit var onBackPressedCallback: OnBackPressedCallback @@ -66,59 +68,72 @@ class QrcodeFragment : Fragment() { val args: QrcodeFragmentArgs by navArgs() val matterSettings = Json.decodeFromString(args.setting) - viewModel.uiState.observe(viewLifecycleOwner) { - when (it) { - QrcodeUiState.Loading -> { - binding.progressBar.visibility = View.VISIBLE + viewModel.uiState.observe( + viewLifecycleOwner, + EventObserver { + when (it) { + QrcodeUiState.Loading -> { + binding.progressBar.visibility = View.VISIBLE + } + is QrcodeUiState.Qrcode -> { + binding.progressBar.visibility = View.GONE + + binding.qrTypeImage.setImageResource(matterSettings.device.deviceIconResId) + binding.qrTypeTitle.text = getString(matterSettings.device.deviceNameResId) + + val qrCodeBitmap: Bitmap? = + QrcodeUtil.createQrCodeBitmap(it.qrCode, QR_WIDTH, QR_HEIGHT) + binding.qrImage.setImageBitmap(qrCodeBitmap) + + binding.qrText.text = getString(R.string.qrcode_qr_text, it.qrCode) + binding.manualCodeText.text = + getString(R.string.qrcode_manual_code_text, it.manualPairingCode) + binding.versionText.text = + getString(R.string.qrcode_version_text, MatterConstants.DEFAULT_VERSION.toString()) + binding.vendorIdText.text = + getString( + R.string.qrcode_vendor_id_text, + MatterConstants.DEFAULT_VENDOR_ID.toString(), + MatterConstants.DEFAULT_VENDOR_ID + ) + binding.productIdText.text = + getString( + R.string.qrcode_product_id_text, + MatterConstants.DEFAULT_PRODUCT_ID.toString(), + MatterConstants.DEFAULT_PRODUCT_ID + ) + binding.commissioningFlowText.text = + getString( + R.string.qrcode_commissioning_flow_text, + MatterConstants.DEFAULT_COMMISSIONING_FLOW.toString() + ) + binding.onboardingTypeText.text = + getString(R.string.qrcode_onboarding_type_text, matterSettings.onboardingType) + binding.setupPinCodeText.text = + getString( + R.string.qrcode_setup_pin_code_text, + MatterConstants.DEFAULT_SETUP_PINCODE.toString() + ) + binding.discriminatorText.text = + getString( + R.string.qrcode_discriminator_text, + matterSettings.discriminator.toString(), + matterSettings.discriminator + ) + } + QrcodeUiState.SessionEstablishmentStarted -> { + try { + findNavController() + .navigate( + DeepLink.getDeepLinkRequestForLoadingFragment(Json.encodeToString(matterSettings)) + ) + } catch (e: Exception) { + Timber.e(e, "navigate failure") + } + } } - is QrcodeUiState.Qrcode -> { - binding.progressBar.visibility = View.GONE - - binding.qrTypeImage.setImageResource(matterSettings.device.deviceIconResId) - binding.qrTypeTitle.text = getString(matterSettings.device.deviceNameResId) - - val qrCodeBitmap: Bitmap? = QrcodeUtil.createQrCodeBitmap(it.qrCode, QR_WIDTH, QR_HEIGHT) - binding.qrImage.setImageBitmap(qrCodeBitmap) - - binding.qrText.text = getString(R.string.qrcode_qr_text, it.qrCode) - binding.manualCodeText.text = - getString(R.string.qrcode_manual_code_text, it.manualPairingCode) - binding.versionText.text = - getString(R.string.qrcode_version_text, MatterConstants.DEFAULT_VERSION.toString()) - binding.vendorIdText.text = - getString( - R.string.qrcode_vendor_id_text, - MatterConstants.DEFAULT_VENDOR_ID.toString(), - MatterConstants.DEFAULT_VENDOR_ID - ) - binding.productIdText.text = - getString( - R.string.qrcode_product_id_text, - MatterConstants.DEFAULT_PRODUCT_ID.toString(), - MatterConstants.DEFAULT_PRODUCT_ID - ) - binding.commissioningFlowText.text = - getString( - R.string.qrcode_commissioning_flow_text, - MatterConstants.DEFAULT_COMMISSIONING_FLOW.toString() - ) - binding.onboardingTypeText.text = - getString(R.string.qrcode_onboarding_type_text, matterSettings.onboardingType) - binding.setupPinCodeText.text = - getString( - R.string.qrcode_setup_pin_code_text, - MatterConstants.DEFAULT_SETUP_PINCODE.toString() - ) - binding.discriminatorText.text = - getString( - R.string.qrcode_discriminator_text, - matterSettings.discriminator.toString(), - matterSettings.discriminator - ) - } - else -> {} } - } + ) } override fun onResume() { @@ -134,7 +149,10 @@ class QrcodeFragment : Fragment() { object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { Timber.d("handleOnBackPressed()") - findNavController().popBackStack() + sharedViewModel.requestFactoryReset( + messageResId = R.string.dialog_user_factory_reset_message, + isCancelable = true + ) } } diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt b/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt index 3505f33eef6e78..7cb138258479aa 100644 --- a/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/java/com/matter/virtual/device/app/feature/qrcode/QrcodeViewModel.kt @@ -1,10 +1,13 @@ package com.matter.virtual.device.app.feature.qrcode import androidx.lifecycle.* +import com.matter.virtual.device.app.core.common.Event import com.matter.virtual.device.app.core.common.MatterSettings import com.matter.virtual.device.app.core.common.successOr import com.matter.virtual.device.app.core.domain.usecase.matter.GetManualPairingCodeStringUseCase import com.matter.virtual.device.app.core.domain.usecase.matter.GetQrcodeStringUseCase +import com.matter.virtual.device.app.core.domain.usecase.matter.IsCommissioningSessionEstablishmentStarted +import com.matter.virtual.device.app.core.domain.usecase.matter.StartMatterAppServiceUseCase import com.matter.virtual.device.app.core.model.Payload import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -22,11 +25,14 @@ class QrcodeViewModel constructor( private val getQrcodeStringUseCase: GetQrcodeStringUseCase, private val getManualPairingCodeStringUseCase: GetManualPairingCodeStringUseCase, + private val isCommissioningSessionEstablishmentStarted: + IsCommissioningSessionEstablishmentStarted, + private val startMatterAppServiceUseCase: StartMatterAppServiceUseCase, savedStateHandle: SavedStateHandle ) : ViewModel() { - private val _uiState = MutableLiveData(QrcodeUiState.Loading) - val uiState: LiveData + private val _uiState = MutableLiveData>(Event(QrcodeUiState.Loading)) + val uiState: LiveData> get() = _uiState init { @@ -35,7 +41,7 @@ constructor( jsonSettings?.let { val matterSettings = Json.decodeFromString(it) - // TODO : start service + startMatterAppServiceUseCase(matterSettings) delay(500) val payload = @@ -47,7 +53,14 @@ constructor( val qrCode = getQrcodeStringUseCase(payload).successOr("") val manualPairingCode = getManualPairingCodeStringUseCase(payload).successOr("") - _uiState.value = QrcodeUiState.Qrcode(qrCode, manualPairingCode) + _uiState.value = Event(QrcodeUiState.Qrcode(qrCode, manualPairingCode)) + + val isCommissioningSessionEstablishmentStarted = + isCommissioningSessionEstablishmentStarted().successOr(false) + if (isCommissioningSessionEstablishmentStarted) { + Timber.d("Session Establishment Started") + _uiState.value = Event(QrcodeUiState.SessionEstablishmentStarted) + } } } } @@ -62,4 +75,6 @@ sealed interface QrcodeUiState { object Loading : QrcodeUiState data class Qrcode(val qrCode: String, val manualPairingCode: String) : QrcodeUiState + + object SessionEstablishmentStarted : QrcodeUiState } diff --git a/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml index 997f74826654a0..5bd72ce74776d5 100644 --- a/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml +++ b/examples/virtual-device-app/android/App/feature/qrcode/src/main/res/layout/fragment_qrcode.xml @@ -22,7 +22,7 @@ android:fitsSystemWindows="true" app:elevation="0dp" app:expanded="false" - app:layout_behavior="com.matter.virtual.device.app.core.common.ui.DisableAppBarLayoutBehavior"> + app:layout_behavior="com.matter.virtual.device.app.core.ui.DisableAppBarLayoutBehavior"> Date: Mon, 7 Aug 2023 00:49:43 +0900 Subject: [PATCH 23/29] virtual-device-app: Implement loading view scenario - monitoring commissioning complete event Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../app/feature/main/LoadingFragment.kt | 48 ++++++++++++- .../app/feature/main/LoadingViewModel.kt | 70 +++++++++++++++++++ .../main/src/main/res/values/strings.xml | 1 + 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingViewModel.kt diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt index 8c81bd26429433..e5d768c3e790b7 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingFragment.kt @@ -9,14 +9,21 @@ import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.navigation.NavOptions import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs +import com.matter.virtual.device.app.core.common.DeepLink +import com.matter.virtual.device.app.core.common.EventObserver import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.ui.SharedViewModel import com.matter.virtual.device.app.feature.main.databinding.FragmentLoadingBinding import dagger.hilt.android.AndroidEntryPoint import kotlin.math.abs import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import timber.log.Timber @@ -24,6 +31,8 @@ import timber.log.Timber class LoadingFragment : Fragment() { private lateinit var binding: FragmentLoadingBinding + private val viewModel by viewModels() + private val sharedViewModel by activityViewModels() private lateinit var matterSettings: MatterSettings private lateinit var onBackPressedCallback: OnBackPressedCallback @@ -60,6 +69,40 @@ class LoadingFragment : Fragment() { val args: LoadingFragmentArgs by navArgs() this.matterSettings = Json.decodeFromString(args.setting) + + viewModel.uiState.observe( + viewLifecycleOwner, + EventObserver { uiStete -> + when (uiStete) { + is LoadingUiState.Complete -> { + matterSettings.device = uiStete.device + + try { + val navOptions = NavOptions.Builder().setPopUpTo(R.id.mainFragment, true).build() + + findNavController() + .navigate( + DeepLink.getDeepLinkRequestFromDevice( + uiStete.device, + Json.encodeToString(matterSettings) + ), + navOptions + ) + } catch (e: Exception) { + Timber.e(e, "navigate failure") + } + } + LoadingUiState.Failure -> { + Timber.e("Failure or Timeout") + sharedViewModel.requestFactoryReset( + messageResId = R.string.dialog_timeout_factory_reset_message, + isCancelable = false + ) + } + LoadingUiState.Loading -> {} + } + } + ) } override fun onResume() { @@ -75,7 +118,10 @@ class LoadingFragment : Fragment() { object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { Timber.d("handleOnBackPressed()") - findNavController().popBackStack() + sharedViewModel.requestFactoryReset( + messageResId = R.string.dialog_user_factory_reset_message, + isCancelable = true + ) } } diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingViewModel.kt b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingViewModel.kt new file mode 100644 index 00000000000000..5017bc04fc1ec1 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/main/src/main/java/com/matter/virtual/device/app/feature/main/LoadingViewModel.kt @@ -0,0 +1,70 @@ +package com.matter.virtual.device.app.feature.main + +import androidx.lifecycle.* +import com.matter.virtual.device.app.core.common.Device +import com.matter.virtual.device.app.core.common.Event +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.common.successOr +import com.matter.virtual.device.app.core.domain.usecase.matter.IsCommissioningCompletedUseCase +import com.matter.virtual.device.app.core.domain.usecase.sharedpreferences.SetCommissionedDeviceUseCase +import com.matter.virtual.device.app.core.domain.usecase.sharedpreferences.SetCommissioningDeviceCompletedUseCase +import com.matter.virtual.device.app.core.domain.usecase.sharedpreferences.SetCommissioningSequenceFlagUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.launch +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import timber.log.Timber + +@OptIn(ExperimentalSerializationApi::class) +@HiltViewModel +class LoadingViewModel +@Inject +constructor( + private val isCommissioningCompletedUseCase: IsCommissioningCompletedUseCase, + private val setCommissioningDeviceCompletedUseCase: SetCommissioningDeviceCompletedUseCase, + private val setCommissionedDeviceUseCase: SetCommissionedDeviceUseCase, + private val setCommissioningSequenceFlagUseCase: SetCommissioningSequenceFlagUseCase, + savedStateHandle: SavedStateHandle +) : ViewModel() { + + private val _uiState = MutableLiveData>(Event(LoadingUiState.Loading)) + val uiState: LiveData> + get() = _uiState + + init { + viewModelScope.launch { + val jsonSettings = savedStateHandle.get("setting") + jsonSettings?.let { + val matterSettings = Json.decodeFromString(it) + Timber.d("device:${matterSettings.device.title}") + + val isCommissioningCompleted = isCommissioningCompletedUseCase().successOr(false) + if (isCommissioningCompleted) { + Timber.d("Commissioning Completed") + setCommissioningDeviceCompletedUseCase(true) + setCommissioningSequenceFlagUseCase(false) + setCommissionedDeviceUseCase(matterSettings.device) + _uiState.value = Event(LoadingUiState.Complete(matterSettings.device)) + } else { + Timber.e("Commissioning Failure or Timeout") + _uiState.value = Event(LoadingUiState.Failure) + } + } + } + } + + override fun onCleared() { + Timber.d("onCleared()") + super.onCleared() + } +} + +sealed class LoadingUiState { + object Loading : LoadingUiState() + + data class Complete(val device: Device) : LoadingUiState() + + object Failure : LoadingUiState() +} diff --git a/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml index c253068a8e9e68..93269fec1ce722 100644 --- a/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml +++ b/examples/virtual-device-app/android/App/feature/main/src/main/res/values/strings.xml @@ -5,4 +5,5 @@ Commissioning in process. "The last commissioning was not completed. The Matter device app will be reset and closed." + "The commissioning timed out. The Matter device app will be reset and closed." \ No newline at end of file From 82ce4f84043810996e05be0244cf93e7d57178d0 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 01:01:27 +0900 Subject: [PATCH 24/29] virtual-device-app: Implement base fragment/viewmodel for device detail view - fabric removed event - common reset menu/popup - abstract setup functions Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../device/app/core/ui/BaseFragment.kt | 130 ++++++++++++++++++ .../device/app/core/ui/BaseViewModel.kt | 37 +++++ .../main/res/drawable/menu_popup_round.xml | 10 ++ .../main/res/drawable/round_more_vert_24.xml | 5 + .../ui/src/main/res/layout/layout_appbar.xml | 79 +++++++++++ .../App/core/ui/src/main/res/menu/more.xml | 6 + .../ui/src/main/res/values-night/colors.xml | 4 + .../core/ui/src/main/res/values/colors.xml | 4 + .../core/ui/src/main/res/values/dimens.xml | 4 + .../core/ui/src/main/res/values/strings.xml | 4 + .../core/ui/src/main/res/values/themes.xml | 6 + 11 files changed, 289 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseViewModel.kt create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/menu_popup_round.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_more_vert_24.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/menu/more.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/values/themes.xml diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt new file mode 100644 index 00000000000000..9a254643c1c0a2 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseFragment.kt @@ -0,0 +1,130 @@ +package com.matter.virtual.device.app.core.ui + +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.PopupMenu +import androidx.annotation.LayoutRes +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import com.matter.virtual.device.app.core.common.EventObserver +import com.matter.virtual.device.app.core.common.MatterSettings +import com.matter.virtual.device.app.core.ui.databinding.LayoutAppbarBinding +import kotlin.math.abs +import timber.log.Timber + +abstract class BaseFragment( + @LayoutRes val layoutResId: Int +) : Fragment() { + + private var _binding: T? = null + protected val binding + get() = _binding!! + + protected abstract val viewModel: V + private val sharedViewModel by activityViewModels() + protected lateinit var matterSettings: MatterSettings + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = DataBindingUtil.inflate(inflater, layoutResId, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + Timber.d("onViewCreated()") + + binding.lifecycleOwner = viewLifecycleOwner + + /** Appbar */ + val layoutAppBarBinding = setupAppbar() + (activity as AppCompatActivity).setSupportActionBar(layoutAppBarBinding.toolbar) + (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true) + + layoutAppBarBinding.appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> + var ratio = 0F + if (abs(verticalOffset) != 0) { + ratio = abs(verticalOffset).toFloat() / appBarLayout.totalScrollRange.toFloat() + } + + layoutAppBarBinding.collapseTitle.alpha = 1f - ratio * 2f + 0.1f + layoutAppBarBinding.toolbarTitle.alpha = (ratio - 0.5f) * 2f + 0.1f + } + + layoutAppBarBinding.toolbarMoreMenuButton.setOnClickListener { + Timber.d("More") + showMoreMenuPopup(it) + } + + setupNavArgs() + setupUi() + setupObservers() + + viewModel.onFabricRemoved.observe( + viewLifecycleOwner, + EventObserver { onFrabricRemoved -> + if (onFrabricRemoved) { + sharedViewModel.requestFactoryReset( + messageResId = R.string.dialog_fabric_removed_factory_reset_message, + isCancelable = false + ) + } + } + ) + } + + protected abstract fun setupAppbar(): LayoutAppbarBinding + + protected abstract fun setupNavArgs() + + protected abstract fun setupUi() + + protected abstract fun setupObservers() + + override fun onDestroyView() { + super.onDestroyView() + Timber.d("onDestroyView()") + _binding = null + } + + private fun showMoreMenuPopup(anchor: View) { + val morePopupMenu = + PopupMenu( + requireContext(), + anchor, + Gravity.TOP or Gravity.END, + 0, + R.style.CustomMenuPopupRound + ) + .apply { + menuInflater.inflate(R.menu.more, this.menu) + + setOnMenuItemClickListener { menuItem -> + return@setOnMenuItemClickListener when (menuItem.itemId) { + R.id.action_reset -> { + Timber.d("reset") + sharedViewModel.requestFactoryReset( + messageResId = R.string.dialog_factory_reset_message, + isCancelable = true + ) + false + } + else -> { + false + } + } + } + } + + morePopupMenu.show() + } +} diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseViewModel.kt b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseViewModel.kt new file mode 100644 index 00000000000000..b613ed4de24988 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/java/com/matter/virtual/device/app/core/ui/BaseViewModel.kt @@ -0,0 +1,37 @@ +package com.matter.virtual.device.app.core.ui + +import androidx.lifecycle.* +import com.matter.virtual.device.app.core.common.Event +import com.matter.virtual.device.app.core.common.MatterSettings +import kotlinx.coroutines.launch +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import timber.log.Timber + +@OptIn(ExperimentalSerializationApi::class) +abstract class BaseViewModel constructor(savedStateHandle: SavedStateHandle) : ViewModel() { + + private val _onFabricRemoved = MutableLiveData>() + val onFabricRemoved: LiveData> + get() = _onFabricRemoved + + protected lateinit var matterSettings: MatterSettings + + init { + viewModelScope.launch { + val jsonSettings = savedStateHandle.get("setting") + jsonSettings?.let { matterSettings = Json.decodeFromString(it) } + } + } + + override fun onCleared() { + super.onCleared() + Timber.d("onCleared()") + } + + protected fun onFabricRemoved() { + Timber.d("onFabricRemoved()") + _onFabricRemoved.value = Event(true) + } +} diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/menu_popup_round.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/menu_popup_round.xml new file mode 100644 index 00000000000000..3060692ad462c2 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/menu_popup_round.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_more_vert_24.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_more_vert_24.xml new file mode 100644 index 00000000000000..39fbab5f7806cc --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_more_vert_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml new file mode 100644 index 00000000000000..b612ae66d543d2 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_appbar.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/menu/more.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/menu/more.xml new file mode 100644 index 00000000000000..8bec4877b12122 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/menu/more.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml new file mode 100644 index 00000000000000..5211c43805bf9c --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml @@ -0,0 +1,4 @@ + + + #666666 + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml new file mode 100644 index 00000000000000..a3a257a263bafa --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml @@ -0,0 +1,4 @@ + + + #fcfcfc + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml new file mode 100644 index 00000000000000..0939d8d001e4e5 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml @@ -0,0 +1,4 @@ + + + 20dp + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml index 2ce8c78fcd7df6..90783b77608c1e 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml @@ -1,4 +1,8 @@ + Reset + + "The Matter device app will be reset and closed. Continue?" "The commissioning was not completed. The Matter device app will be reset and closed. Continue?" + "The fabric was removed. The Matter device app will be reset and closed." \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/themes.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/themes.xml new file mode 100644 index 00000000000000..aaa0ee6a970053 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/themes.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file From 98ec3390b8c755166f491a699680291964c6f723 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 01:11:13 +0900 Subject: [PATCH 25/29] virtual-device-app: Implement common layout - on/off button layout - radio button layout - common space Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/core/model/build.gradle.kts | 3 ++ .../app/core/model/databinding/ButtonData.kt | 10 +++++ .../res/drawable/device_title_icon_bg.xml | 10 +++++ .../main/res/drawable/round_toggle_off_24.xml | 5 +++ .../main/res/drawable/round_toggle_on_24.xml | 5 +++ .../layout_item_value_on_off_button.xml | 45 +++++++++++++++++++ .../layout/layout_item_value_radio_button.xml | 36 +++++++++++++++ .../main/res/layout/layout_space_bottom.xml | 4 ++ .../src/main/res/layout/layout_space_top.xml | 4 ++ .../ui/src/main/res/layout/layout_title.xml | 39 ++++++++++++++++ .../ui/src/main/res/values-night/colors.xml | 1 + .../core/ui/src/main/res/values/colors.xml | 1 + .../core/ui/src/main/res/values/dimens.xml | 21 +++++++++ .../core/ui/src/main/res/values/strings.xml | 1 + 14 files changed, 185 insertions(+) create mode 100644 examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/databinding/ButtonData.kt create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/device_title_icon_bg.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_off_24.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_on_off_button.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_radio_button.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_bottom.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml create mode 100644 examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml diff --git a/examples/virtual-device-app/android/App/core/model/build.gradle.kts b/examples/virtual-device-app/android/App/core/model/build.gradle.kts index d51ec3d4154ea2..73ee82705c56a4 100644 --- a/examples/virtual-device-app/android/App/core/model/build.gradle.kts +++ b/examples/virtual-device-app/android/App/core/model/build.gradle.kts @@ -38,6 +38,9 @@ android { dependencies { + implementation(Deps.AndroidX.core) + implementation(Deps.AndroidX.Lifecycle.livedata) + testImplementation(Deps.Test.junit) androidTestImplementation(Deps.Test.junitExt) androidTestImplementation(Deps.Test.espresso) diff --git a/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/databinding/ButtonData.kt b/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/databinding/ButtonData.kt new file mode 100644 index 00000000000000..5101ea8c05534f --- /dev/null +++ b/examples/virtual-device-app/android/App/core/model/src/main/java/com/matter/virtual/device/app/core/model/databinding/ButtonData.kt @@ -0,0 +1,10 @@ +package com.matter.virtual.device.app.core.model.databinding + +import androidx.annotation.StringRes +import androidx.lifecycle.LiveData + +data class ButtonData( + val onOff: LiveData, + @StringRes val onText: Int, + @StringRes val offText: Int +) diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/device_title_icon_bg.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/device_title_icon_bg.xml new file mode 100644 index 00000000000000..efdaea92a3f153 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/device_title_icon_bg.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_off_24.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_off_24.xml new file mode 100644 index 00000000000000..8349d993c3b0a5 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_off_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml new file mode 100644 index 00000000000000..d42714cc7696e0 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/drawable/round_toggle_on_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_on_off_button.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_on_off_button.xml new file mode 100644 index 00000000000000..2cc3c1bd19948e --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_on_off_button.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_radio_button.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_radio_button.xml new file mode 100644 index 00000000000000..ad3ca0a131ce43 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_item_value_radio_button.xml @@ -0,0 +1,36 @@ + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_bottom.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_bottom.xml new file mode 100644 index 00000000000000..2aeb588ac270d4 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_bottom.xml @@ -0,0 +1,4 @@ + + diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml new file mode 100644 index 00000000000000..47421036d7f28c --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_space_top.xml @@ -0,0 +1,4 @@ + + diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml new file mode 100644 index 00000000000000..7ad14914499681 --- /dev/null +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/layout/layout_title.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml index 5211c43805bf9c..84b136dbfb181b 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values-night/colors.xml @@ -1,4 +1,5 @@ #666666 + @android:color/white \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml index a3a257a263bafa..9dccb8060e7ff1 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/colors.xml @@ -1,4 +1,5 @@ #fcfcfc + @android:color/black \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml index 0939d8d001e4e5..40812937855eac 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml @@ -1,4 +1,25 @@ 20dp + + 60dp + 60dp + 20dp + 10sp + 24sp + + 44dp + 12dp + 25dp + 20dp + 20dp + 20dp + 20dp + 12dp + 36dp + 36dp + 20sp + 75dp + 0dp + 36dp \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml index 90783b77608c1e..9d801480dd9d17 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ + button Reset "The Matter device app will be reset and closed. Continue?" From b74c05541ce9a22086c08f37ab7d53619004052d Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 01:20:57 +0900 Subject: [PATCH 26/29] virtual-device-app: Implement onoff switch scenario - set onoff attribute - show onoff status Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../common/src/main/res/values/dimens.xml | 4 -- .../core/ui/src/main/res/values/dimens.xml | 3 + .../core/ui/src/main/res/values/strings.xml | 3 + .../App/feature/control/build.gradle.kts | 9 +++ .../feature/control/OnOffSwitchFragment.kt | 56 ++++++++++------ .../feature/control/OnOffSwitchViewModel.kt | 65 +++++++++++++++++++ .../res/layout/fragment_on_off_switch.xml | 47 +++++++++++++- 7 files changed, 161 insertions(+), 26 deletions(-) create mode 100644 examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchViewModel.kt diff --git a/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml b/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml index 755c53609e9b3f..f39212668f9003 100644 --- a/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml +++ b/examples/virtual-device-app/android/App/core/common/src/main/res/values/dimens.xml @@ -1,9 +1,5 @@ - 350dp - 25sp - 17sp - 10dp 48dp 48dp diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml index 40812937855eac..24bd23b54f6de7 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/dimens.xml @@ -1,5 +1,8 @@ + 350dp + 25sp + 17sp 20dp 60dp diff --git a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml index 9d801480dd9d17..70fd88fd75a365 100644 --- a/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml +++ b/examples/virtual-device-app/android/App/core/ui/src/main/res/values/strings.xml @@ -6,4 +6,7 @@ "The Matter device app will be reset and closed. Continue?" "The commissioning was not completed. The Matter device app will be reset and closed. Continue?" "The fabric was removed. The Matter device app will be reset and closed." + + On + Off \ No newline at end of file diff --git a/examples/virtual-device-app/android/App/feature/control/build.gradle.kts b/examples/virtual-device-app/android/App/feature/control/build.gradle.kts index a9315f089d25ed..c96bf15592d636 100644 --- a/examples/virtual-device-app/android/App/feature/control/build.gradle.kts +++ b/examples/virtual-device-app/android/App/feature/control/build.gradle.kts @@ -45,9 +45,18 @@ android { dependencies { + implementation(project(":core:common")) + implementation(project(":core:domain")) + implementation(project(":core:model")) + implementation(project(":core:ui")) + implementation(Deps.AndroidX.core) implementation(Deps.AndroidX.appcompat) implementation(Deps.AndroidX.fragment) + implementation(Deps.AndroidX.Lifecycle.viewmodel) + implementation(Deps.AndroidX.Lifecycle.livedata) + + implementation(Deps.Kotlin.serialization) implementation(Deps.Navigation.fragment) implementation(Deps.Navigation.ui) diff --git a/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt b/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt index 5f89d07467ed5f..3b13eb0898e123 100644 --- a/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt +++ b/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchFragment.kt @@ -1,37 +1,51 @@ package com.matter.virtual.device.app.feature.control -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.databinding.DataBindingUtil -import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.navArgs +import com.matter.virtual.device.app.core.model.databinding.ButtonData +import com.matter.virtual.device.app.core.ui.BaseFragment +import com.matter.virtual.device.app.core.ui.databinding.LayoutAppbarBinding import com.matter.virtual.device.app.feature.control.databinding.FragmentOnOffSwitchBinding import dagger.hilt.android.AndroidEntryPoint +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json import timber.log.Timber @AndroidEntryPoint -class OnOffSwitchFragment : Fragment() { +class OnOffSwitchFragment : + BaseFragment(R.layout.fragment_on_off_switch) { - private lateinit var binding: FragmentOnOffSwitchBinding + override val viewModel: OnOffSwitchViewModel by viewModels() - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - Timber.d("onCreateView()") - binding = DataBindingUtil.inflate(inflater, R.layout.fragment_on_off_switch, container, false) - binding.lifecycleOwner = viewLifecycleOwner - - return binding.root + @OptIn(ExperimentalSerializationApi::class) + override fun setupNavArgs() { + val args: OnOffSwitchFragmentArgs by navArgs() + matterSettings = Json.decodeFromString(args.setting) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - Timber.d("onViewCreated()") - super.onViewCreated(view, savedInstanceState) + override fun setupAppbar(): LayoutAppbarBinding = binding.appbar + + override fun setupUi() { + /** title icon */ + binding.onOffSwitchTitleLayout.titleIcon.setImageResource(matterSettings.device.deviceIconResId) + + /** title text */ + binding.onOffSwitchTitleLayout.titleText.text = getString(matterSettings.device.deviceNameResId) + + /** OnOff layout */ + binding.onOffSwitchOnOffLayout.buttonData = + ButtonData( + onOff = viewModel.onOff, + onText = R.string.on_off_switch_power_on, + offText = R.string.on_off_switch_power_off + ) + + binding.onOffSwitchOnOffLayout.button.setOnClickListener { viewModel.onClickButton() } } + override fun setupObservers() {} + override fun onResume() { Timber.d("onResume()") super.onResume() diff --git a/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchViewModel.kt b/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchViewModel.kt new file mode 100644 index 00000000000000..bae5e8c88f8be7 --- /dev/null +++ b/examples/virtual-device-app/android/App/feature/control/src/main/java/com/matter/virtual/device/app/feature/control/OnOffSwitchViewModel.kt @@ -0,0 +1,65 @@ +package com.matter.virtual.device.app.feature.control + +import androidx.lifecycle.LiveData +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope +import com.matter.virtual.device.app.core.common.successOr +import com.matter.virtual.device.app.core.domain.usecase.matter.IsFabricRemovedUseCase +import com.matter.virtual.device.app.core.domain.usecase.matter.StartMatterAppServiceUseCase +import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.GetOnOffFlowUseCase +import com.matter.virtual.device.app.core.domain.usecase.matter.cluster.SetOnOffUseCase +import com.matter.virtual.device.app.core.ui.BaseViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import timber.log.Timber + +@HiltViewModel +class OnOffSwitchViewModel +@Inject +constructor( + getOnOffFlowUseCase: GetOnOffFlowUseCase, + private val setOnOffUseCase: SetOnOffUseCase, + private val startMatterAppServiceUseCase: StartMatterAppServiceUseCase, + private val isFabricRemovedUseCase: IsFabricRemovedUseCase, + savedStateHandle: SavedStateHandle +) : BaseViewModel(savedStateHandle) { + + private val _onOff: StateFlow = getOnOffFlowUseCase() + val onOff: LiveData + get() = _onOff.asLiveData() + + init { + Timber.d("init()") + viewModelScope.launch { startMatterAppServiceUseCase(matterSettings) } + + viewModelScope.launch { + val isFabricRemoved = isFabricRemovedUseCase().successOr(false) + if (isFabricRemoved) { + Timber.d("Fabric Removed") + onFabricRemoved() + } + } + } + + override fun onCleared() { + Timber.d("onCleared()") + super.onCleared() + } + + fun onClickButton() { + Timber.d("Hit") + viewModelScope.launch { + Timber.d("current value = ${_onOff.value}") + if (_onOff.value) { + Timber.d("set value = false") + setOnOffUseCase(false) + } else { + Timber.d("set value = true") + setOnOffUseCase(true) + } + } + } +} diff --git a/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml b/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml index 35d548cddf3cc8..1978e7c383f3d0 100644 --- a/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml +++ b/examples/virtual-device-app/android/App/feature/control/src/main/res/layout/fragment_on_off_switch.xml @@ -1,10 +1,55 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 87b7c6b50e137449d48c7f49e4974b7ee80bc3d0 Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 01:24:57 +0900 Subject: [PATCH 27/29] virtual-device-app: Apply feature:control navGraph Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- examples/virtual-device-app/android/App/app/build.gradle.kts | 1 + .../android/App/app/src/main/res/navigation/nav_graph.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/virtual-device-app/android/App/app/build.gradle.kts b/examples/virtual-device-app/android/App/app/build.gradle.kts index dbc45d07e0694a..e5998ddc554d6d 100644 --- a/examples/virtual-device-app/android/App/app/build.gradle.kts +++ b/examples/virtual-device-app/android/App/app/build.gradle.kts @@ -77,6 +77,7 @@ dependencies { implementation(project(":core:domain")) implementation(project(":core:model")) implementation(project(":core:ui")) + implementation(project(":feature:control")) implementation(project(":feature:main")) implementation(project(":feature:qrcode")) implementation(project(":feature:setup")) diff --git a/examples/virtual-device-app/android/App/app/src/main/res/navigation/nav_graph.xml b/examples/virtual-device-app/android/App/app/src/main/res/navigation/nav_graph.xml index da2e60563663e2..a5e06ead94b64c 100644 --- a/examples/virtual-device-app/android/App/app/src/main/res/navigation/nav_graph.xml +++ b/examples/virtual-device-app/android/App/app/src/main/res/navigation/nav_graph.xml @@ -7,4 +7,5 @@ + \ No newline at end of file From 34ebb6938cd1543f4c3a2b7ca3e40fa1f9cfa97c Mon Sep 17 00:00:00 2001 From: Jaehoon You Date: Mon, 7 Aug 2023 01:28:59 +0900 Subject: [PATCH 28/29] virtual-device-app: Add permissions about stack related Signed-off-by: Jaehoon You Signed-off-by: Charles Kim --- .../android/App/app/src/main/AndroidManifest.xml | 10 ++++++++++ .../java/com/matter/virtual/device/app/MainActivity.kt | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml index ba892cba76bd9e..b80ba26d85db89 100644 --- a/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml +++ b/examples/virtual-device-app/android/App/app/src/main/AndroidManifest.xml @@ -1,6 +1,16 @@ + + + + + + diff --git a/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt b/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt index 26ba166cb00866..cc8702bf19bde5 100644 --- a/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt +++ b/examples/virtual-device-app/android/App/app/src/main/java/com/matter/virtual/device/app/MainActivity.kt @@ -29,7 +29,13 @@ class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private val viewModel by viewModels() - private val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION) + private val permissions = + arrayOf( + Manifest.permission.BLUETOOTH_SCAN, + Manifest.permission.BLUETOOTH_ADVERTISE, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.ACCESS_FINE_LOCATION + ) private val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> From 366f42dff7f75ece90e764bdeb24aaf8cdea570a Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 7 Aug 2023 05:07:10 +0000 Subject: [PATCH 29/29] Restyled by google-java-format Signed-off-by: Charles Kim --- .../matter/virtual/device/app/Clusters.java | 234 +++++++++--------- .../matter/virtual/device/app/DeviceApp.java | 58 ++--- .../virtual/device/app/DeviceAppCallback.java | 4 +- .../virtual/device/app/DeviceEventType.java | 56 ++--- .../virtual/device/app/OnOffManager.java | 21 +- 5 files changed, 185 insertions(+), 188 deletions(-) diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java index 98a95ea8c37a0e..47e1dd0f5192a4 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/Clusters.java @@ -18,121 +18,121 @@ public class Clusters { - public static final long ClusterId_PowerConfiguration = 0x00000001; - public static final long ClusterId_DeviceTemperatureConfiguration = 0x00000002; - public static final long ClusterId_Identify = 0x00000003; - public static final long ClusterId_Groups = 0x00000004; - public static final long ClusterId_Scenes = 0x00000005; - public static final long ClusterId_OnOff = 0x00000006; - public static final long ClusterId_OnOffSwitchConfiguration = 0x00000007; - public static final long ClusterId_LevelControl = 0x00000008; - public static final long ClusterId_Alarms = 0x00000009; - public static final long ClusterId_Time = 0x0000000A; - public static final long ClusterId_BinaryInputBasic = 0x0000000F; - public static final long ClusterId_PowerProfile = 0x0000001A; - public static final long ClusterId_ApplianceControl = 0x0000001B; - public static final long ClusterId_PulseWidthModulation = 0x0000001C; - public static final long ClusterId_Descriptor = 0x0000001D; - public static final long ClusterId_Binding = 0x0000001E; - public static final long ClusterId_AccessControl = 0x0000001F; - public static final long ClusterId_PollControl = 0x00000020; - public static final long ClusterId_Actions = 0x00000025; - public static final long ClusterId_Basic = 0x00000028; - public static final long ClusterId_OtaSoftwareUpdateProvider = 0x00000029; - public static final long ClusterId_OtaSoftwareUpdateRequestor = 0x0000002A; - public static final long ClusterId_LocalizationConfiguration = 0x0000002B; - public static final long ClusterId_LocalizationTimeFormat = 0x0000002C; - public static final long ClusterId_LocalizationUnit = 0x0000002D; - public static final long ClusterId_PowerSourceConfiguration = 0x0000002E; - public static final long ClusterId_PowerSource = 0x0000002F; - public static final long ClusterId_GeneralCommissioning = 0x00000030; - public static final long ClusterId_NetworkCommissioning = 0x00000031; - public static final long ClusterId_DiagnosticLogs = 0x00000032; - public static final long ClusterId_GeneralDiagnostics = 0x00000033; - public static final long ClusterId_SoftwareDiagnostics = 0x00000034; - public static final long ClusterId_ThreadNetworkDiagnostics = 0x00000035; - public static final long ClusterId_WiFiNetworkDiagnostics = 0x00000036; - public static final long ClusterId_EthernetNetworkDiagnostics = 0x00000037; - public static final long ClusterId_TimeSynchronization = 0x00000038; - public static final long ClusterId_BridgedDeviceBasic = 0x00000039; - public static final long ClusterId_Switch = 0x0000003B; - public static final long ClusterId_AdministratorCommissioning = 0x0000003C; - public static final long ClusterId_OperationalCredentials = 0x0000003E; - public static final long ClusterId_GroupKeyManagement = 0x0000003F; - public static final long ClusterId_FixedLabel = 0x00000040; - public static final long ClusterId_UserLabel = 0x00000041; - public static final long ClusterId_ProxyConfiguration = 0x00000042; - public static final long ClusterId_ProxyDiscovery = 0x00000043; - public static final long ClusterId_ProxyValid = 0x00000044; - public static final long ClusterId_BooleanState = 0x00000045; - public static final long ClusterId_ModeSelect = 0x00000050; - public static final long ClusterId_ShadeConfiguration = 0x00000100; - public static final long ClusterId_DoorLock = 0x00000101; - public static final long ClusterId_WindowCovering = 0x00000102; - public static final long ClusterId_BarrierControl = 0x00000103; - public static final long ClusterId_PumpConfigurationAndControl = 0x00000200; - public static final long ClusterId_Thermostat = 0x00000201; - public static final long ClusterId_FanControl = 0x00000202; - public static final long ClusterId_DehumidificationControl = 0x00000203; - public static final long ClusterId_ThermostatUserInterfaceConfiguration = 0x00000204; - public static final long ClusterId_ColorControl = 0x00000300; - public static final long ClusterId_BallastConfiguration = 0x00000301; - public static final long ClusterId_IlluminanceMeasurement = 0x00000400; - public static final long ClusterId_TemperatureMeasurement = 0x00000402; - public static final long ClusterId_PressureMeasurement = 0x00000403; - public static final long ClusterId_FlowMeasurement = 0x00000404; - public static final long ClusterId_RelativeHumidityMeasurement = 0x00000405; - public static final long ClusterId_OccupancySensing = 0x00000406; - public static final long ClusterId_CarbonMonoxideConcentrationMeasurement = 0x0000040C; - public static final long ClusterId_CarbonDioxideConcentrationMeasurement = 0x0000040D; - public static final long ClusterId_EthyleneConcentrationMeasurement = 0x0000040E; - public static final long ClusterId_EthyleneOxideConcentrationMeasurement = 0x0000040F; - public static final long ClusterId_HydrogenConcentrationMeasurement = 0x00000410; - public static final long ClusterId_HydrogenSulphideConcentrationMeasurement = 0x00000411; - public static final long ClusterId_NitricOxideConcentrationMeasurement = 0x00000412; - public static final long ClusterId_NitrogenDioxideConcentrationMeasurement = 0x00000413; - public static final long ClusterId_OxygenConcentrationMeasurement = 0x00000414; - public static final long ClusterId_OzoneConcentrationMeasurement = 0x00000415; - public static final long ClusterId_SulfurDioxideConcentrationMeasurement = 0x00000416; - public static final long ClusterId_DissolvedOxygenConcentrationMeasurement = 0x00000417; - public static final long ClusterId_BromateConcentrationMeasurement = 0x00000418; - public static final long ClusterId_ChloraminesConcentrationMeasurement = 0x00000419; - public static final long ClusterId_ChlorineConcentrationMeasurement = 0x0000041A; - public static final long ClusterId_FecalColiformAndEColiConcentrationMeasurement = 0x0000041B; - public static final long ClusterId_FluorideConcentrationMeasurement = 0x0000041C; - public static final long ClusterId_HaloaceticAcidsConcentrationMeasurement = 0x0000041D; - public static final long ClusterId_TotalTrihalomethanesConcentrationMeasurement = 0x0000041E; - public static final long ClusterId_TotalColiformBacteriaConcentrationMeasurement = 0x0000041F; - public static final long ClusterId_TurbidityConcentrationMeasurement = 0x00000420; - public static final long ClusterId_CopperConcentrationMeasurement = 0x00000421; - public static final long ClusterId_LeadConcentrationMeasurement = 0x00000422; - public static final long ClusterId_ManganeseConcentrationMeasurement = 0x00000423; - public static final long ClusterId_SulfateConcentrationMeasurement = 0x00000424; - public static final long ClusterId_BromodichloromethaneConcentrationMeasurement = 0x00000425; - public static final long ClusterId_BromoformConcentrationMeasurement = 0x00000426; - public static final long ClusterId_ChlorodibromomethaneConcentrationMeasurement = 0x00000427; - public static final long ClusterId_ChloroformConcentrationMeasurement = 0x00000428; - public static final long ClusterId_SodiumConcentrationMeasurement = 0x00000429; - public static final long ClusterId_IasZone = 0x00000500; - public static final long ClusterId_IasAce = 0x00000501; - public static final long ClusterId_IasWd = 0x00000502; - public static final long ClusterId_WakeOnLan = 0x00000503; - public static final long ClusterId_Channel = 0x00000504; - public static final long ClusterId_TargetNavigator = 0x00000505; - public static final long ClusterId_MediaPlayback = 0x00000506; - public static final long ClusterId_MediaInput = 0x00000507; - public static final long ClusterId_LowPower = 0x00000508; - public static final long ClusterId_KeypadInput = 0x00000509; - public static final long ClusterId_ContentLauncher = 0x0000050A; - public static final long ClusterId_AudioOutput = 0x0000050B; - public static final long ClusterId_ApplicationLauncher = 0x0000050C; - public static final long ClusterId_ApplicationBasic = 0x0000050D; - public static final long ClusterId_AccountLogin = 0x0000050E; - public static final long ClusterId_TestCluster = 0xFFF1FC05; - public static final long ClusterId_Messaging = 0x00000703; - public static final long ClusterId_ApplianceIdentification = 0x00000B00; - public static final long ClusterId_MeterIdentification = 0x00000B01; - public static final long ClusterId_ApplianceEventsAndAlert = 0x00000B02; - public static final long ClusterId_ApplianceStatistics = 0x00000B03; - public static final long ClusterId_ElectricalMeasurement = 0x00000B04; + public static final long ClusterId_PowerConfiguration = 0x00000001; + public static final long ClusterId_DeviceTemperatureConfiguration = 0x00000002; + public static final long ClusterId_Identify = 0x00000003; + public static final long ClusterId_Groups = 0x00000004; + public static final long ClusterId_Scenes = 0x00000005; + public static final long ClusterId_OnOff = 0x00000006; + public static final long ClusterId_OnOffSwitchConfiguration = 0x00000007; + public static final long ClusterId_LevelControl = 0x00000008; + public static final long ClusterId_Alarms = 0x00000009; + public static final long ClusterId_Time = 0x0000000A; + public static final long ClusterId_BinaryInputBasic = 0x0000000F; + public static final long ClusterId_PowerProfile = 0x0000001A; + public static final long ClusterId_ApplianceControl = 0x0000001B; + public static final long ClusterId_PulseWidthModulation = 0x0000001C; + public static final long ClusterId_Descriptor = 0x0000001D; + public static final long ClusterId_Binding = 0x0000001E; + public static final long ClusterId_AccessControl = 0x0000001F; + public static final long ClusterId_PollControl = 0x00000020; + public static final long ClusterId_Actions = 0x00000025; + public static final long ClusterId_Basic = 0x00000028; + public static final long ClusterId_OtaSoftwareUpdateProvider = 0x00000029; + public static final long ClusterId_OtaSoftwareUpdateRequestor = 0x0000002A; + public static final long ClusterId_LocalizationConfiguration = 0x0000002B; + public static final long ClusterId_LocalizationTimeFormat = 0x0000002C; + public static final long ClusterId_LocalizationUnit = 0x0000002D; + public static final long ClusterId_PowerSourceConfiguration = 0x0000002E; + public static final long ClusterId_PowerSource = 0x0000002F; + public static final long ClusterId_GeneralCommissioning = 0x00000030; + public static final long ClusterId_NetworkCommissioning = 0x00000031; + public static final long ClusterId_DiagnosticLogs = 0x00000032; + public static final long ClusterId_GeneralDiagnostics = 0x00000033; + public static final long ClusterId_SoftwareDiagnostics = 0x00000034; + public static final long ClusterId_ThreadNetworkDiagnostics = 0x00000035; + public static final long ClusterId_WiFiNetworkDiagnostics = 0x00000036; + public static final long ClusterId_EthernetNetworkDiagnostics = 0x00000037; + public static final long ClusterId_TimeSynchronization = 0x00000038; + public static final long ClusterId_BridgedDeviceBasic = 0x00000039; + public static final long ClusterId_Switch = 0x0000003B; + public static final long ClusterId_AdministratorCommissioning = 0x0000003C; + public static final long ClusterId_OperationalCredentials = 0x0000003E; + public static final long ClusterId_GroupKeyManagement = 0x0000003F; + public static final long ClusterId_FixedLabel = 0x00000040; + public static final long ClusterId_UserLabel = 0x00000041; + public static final long ClusterId_ProxyConfiguration = 0x00000042; + public static final long ClusterId_ProxyDiscovery = 0x00000043; + public static final long ClusterId_ProxyValid = 0x00000044; + public static final long ClusterId_BooleanState = 0x00000045; + public static final long ClusterId_ModeSelect = 0x00000050; + public static final long ClusterId_ShadeConfiguration = 0x00000100; + public static final long ClusterId_DoorLock = 0x00000101; + public static final long ClusterId_WindowCovering = 0x00000102; + public static final long ClusterId_BarrierControl = 0x00000103; + public static final long ClusterId_PumpConfigurationAndControl = 0x00000200; + public static final long ClusterId_Thermostat = 0x00000201; + public static final long ClusterId_FanControl = 0x00000202; + public static final long ClusterId_DehumidificationControl = 0x00000203; + public static final long ClusterId_ThermostatUserInterfaceConfiguration = 0x00000204; + public static final long ClusterId_ColorControl = 0x00000300; + public static final long ClusterId_BallastConfiguration = 0x00000301; + public static final long ClusterId_IlluminanceMeasurement = 0x00000400; + public static final long ClusterId_TemperatureMeasurement = 0x00000402; + public static final long ClusterId_PressureMeasurement = 0x00000403; + public static final long ClusterId_FlowMeasurement = 0x00000404; + public static final long ClusterId_RelativeHumidityMeasurement = 0x00000405; + public static final long ClusterId_OccupancySensing = 0x00000406; + public static final long ClusterId_CarbonMonoxideConcentrationMeasurement = 0x0000040C; + public static final long ClusterId_CarbonDioxideConcentrationMeasurement = 0x0000040D; + public static final long ClusterId_EthyleneConcentrationMeasurement = 0x0000040E; + public static final long ClusterId_EthyleneOxideConcentrationMeasurement = 0x0000040F; + public static final long ClusterId_HydrogenConcentrationMeasurement = 0x00000410; + public static final long ClusterId_HydrogenSulphideConcentrationMeasurement = 0x00000411; + public static final long ClusterId_NitricOxideConcentrationMeasurement = 0x00000412; + public static final long ClusterId_NitrogenDioxideConcentrationMeasurement = 0x00000413; + public static final long ClusterId_OxygenConcentrationMeasurement = 0x00000414; + public static final long ClusterId_OzoneConcentrationMeasurement = 0x00000415; + public static final long ClusterId_SulfurDioxideConcentrationMeasurement = 0x00000416; + public static final long ClusterId_DissolvedOxygenConcentrationMeasurement = 0x00000417; + public static final long ClusterId_BromateConcentrationMeasurement = 0x00000418; + public static final long ClusterId_ChloraminesConcentrationMeasurement = 0x00000419; + public static final long ClusterId_ChlorineConcentrationMeasurement = 0x0000041A; + public static final long ClusterId_FecalColiformAndEColiConcentrationMeasurement = 0x0000041B; + public static final long ClusterId_FluorideConcentrationMeasurement = 0x0000041C; + public static final long ClusterId_HaloaceticAcidsConcentrationMeasurement = 0x0000041D; + public static final long ClusterId_TotalTrihalomethanesConcentrationMeasurement = 0x0000041E; + public static final long ClusterId_TotalColiformBacteriaConcentrationMeasurement = 0x0000041F; + public static final long ClusterId_TurbidityConcentrationMeasurement = 0x00000420; + public static final long ClusterId_CopperConcentrationMeasurement = 0x00000421; + public static final long ClusterId_LeadConcentrationMeasurement = 0x00000422; + public static final long ClusterId_ManganeseConcentrationMeasurement = 0x00000423; + public static final long ClusterId_SulfateConcentrationMeasurement = 0x00000424; + public static final long ClusterId_BromodichloromethaneConcentrationMeasurement = 0x00000425; + public static final long ClusterId_BromoformConcentrationMeasurement = 0x00000426; + public static final long ClusterId_ChlorodibromomethaneConcentrationMeasurement = 0x00000427; + public static final long ClusterId_ChloroformConcentrationMeasurement = 0x00000428; + public static final long ClusterId_SodiumConcentrationMeasurement = 0x00000429; + public static final long ClusterId_IasZone = 0x00000500; + public static final long ClusterId_IasAce = 0x00000501; + public static final long ClusterId_IasWd = 0x00000502; + public static final long ClusterId_WakeOnLan = 0x00000503; + public static final long ClusterId_Channel = 0x00000504; + public static final long ClusterId_TargetNavigator = 0x00000505; + public static final long ClusterId_MediaPlayback = 0x00000506; + public static final long ClusterId_MediaInput = 0x00000507; + public static final long ClusterId_LowPower = 0x00000508; + public static final long ClusterId_KeypadInput = 0x00000509; + public static final long ClusterId_ContentLauncher = 0x0000050A; + public static final long ClusterId_AudioOutput = 0x0000050B; + public static final long ClusterId_ApplicationLauncher = 0x0000050C; + public static final long ClusterId_ApplicationBasic = 0x0000050D; + public static final long ClusterId_AccountLogin = 0x0000050E; + public static final long ClusterId_TestCluster = 0xFFF1FC05; + public static final long ClusterId_Messaging = 0x00000703; + public static final long ClusterId_ApplianceIdentification = 0x00000B00; + public static final long ClusterId_MeterIdentification = 0x00000B01; + public static final long ClusterId_ApplianceEventsAndAlert = 0x00000B02; + public static final long ClusterId_ApplianceStatistics = 0x00000B03; + public static final long ClusterId_ElectricalMeasurement = 0x00000B04; } diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java index b70adf9e811a78..3df52b020487e1 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceApp.java @@ -20,46 +20,46 @@ import android.util.Log; public class DeviceApp { - private DeviceAppCallback mCallback = null; - private static final String TAG = "DeviceApp"; + private DeviceAppCallback mCallback = null; + private static final String TAG = "DeviceApp"; - public DeviceApp() { - nativeInit(); - } + public DeviceApp() { + nativeInit(); + } - public void setCallback(DeviceAppCallback callback) { - mCallback = callback; - } + public void setCallback(DeviceAppCallback callback) { + mCallback = callback; + } - private void postClusterInit(long clusterId, int endpoint) { - Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); - if (mCallback != null) { - mCallback.onClusterInit(this, clusterId, endpoint); - } + private void postClusterInit(long clusterId, int endpoint) { + Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); + if (mCallback != null) { + mCallback.onClusterInit(this, clusterId, endpoint); } + } - private void postEvent(long event) { - Log.d(TAG, "postEvent : " + event); - if (mCallback != null) { - mCallback.onEvent(event); - } + private void postEvent(long event) { + Log.d(TAG, "postEvent : " + event); + if (mCallback != null) { + mCallback.onEvent(event); } + } - public native void nativeInit(); + public native void nativeInit(); - // called before Matter server is initiated - public native void preServerInit(); + // called before Matter server is initiated + public native void preServerInit(); - // called after Matter server is initiated - public native void postServerInit(int deviceTypeId); + // called after Matter server is initiated + public native void postServerInit(int deviceTypeId); - public native void setOnOffManager(int endpoint, OnOffManager manager); + public native void setOnOffManager(int endpoint, OnOffManager manager); - public native boolean setOnOff(int endpoint, boolean value); + public native boolean setOnOff(int endpoint, boolean value); - public native void setDACProvider(DACProvider provider); + public native void setDACProvider(DACProvider provider); - static { - System.loadLibrary("DeviceApp"); - } + static { + System.loadLibrary("DeviceApp"); + } } diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java index a627dbcb82a158..6b417c24f41f08 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceAppCallback.java @@ -17,7 +17,7 @@ package com.matter.virtual.device.app; public interface DeviceAppCallback { - void onClusterInit(DeviceApp app, long clusterId, int endpoint); + void onClusterInit(DeviceApp app, long clusterId, int endpoint); - void onEvent(long event); + void onEvent(long event); } diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java index 019bb79d4fd314..07b0f0e6219343 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/DeviceEventType.java @@ -17,33 +17,33 @@ package com.matter.virtual.device.app; public class DeviceEventType { - public static final long EventId_WiFiConnectivityChange = 0x8000; - public static final long EventId_ThreadConnectivityChange = 0x8001; - public static final long EventId_InternetConnectivityChange = 0x8002; - public static final long EventId_ServiceConnectivityChange = 0x8003; - public static final long EventId_ServiceProvisioningChange = 0x8004; - public static final long EventId_TimeSyncChange = 0x8005; - public static final long EventId_ICDPollingIntervalChang = 0x8006; - public static final long EventId_CHIPoBLEConnectionEstablished = 0x8007; - public static final long EventId_CHIPoBLEConnectionClosed = 0x8008; - public static final long EventId_ThreadStateChange = 0x8009; - public static final long EventId_ThreadInterfaceStateChange = 0x800A; - public static final long EventId_CHIPoBLEAdvertisingChange = 0x800B; - public static final long EventId_InterfaceIpAddressChanged = 0x800C; - public static final long EventId_CommissioningWindowStatusChanged = 0x800D; - public static final long EventId_CommissioningComplete = 0x800E; - public static final long EventId_FailSafeTimerExpired = 0x800F; - public static final long EventId_FailSafeStateChanged = 0x8010; - public static final long EventId_OperationalNetworkEnabled = 0x8011; - public static final long EventId_DnssdInitialized = 0x8012; - public static final long EventId_DnssdRestartNeeded = 0x8013; - public static final long EventId_BindingsChangedViaCluster = 0x8014; - public static final long EventId_OtaStateChanged = 0x8015; - public static final long EventId_ServerReady = 0x8016; - public static final long EventId_ChipMsgSentEvent = 0x8017; - public static final long EventId_ChipMsgRxEventHandled = 0x8018; - public static final long EventId_AppWakeUpEvent = 0x8018; + public static final long EventId_WiFiConnectivityChange = 0x8000; + public static final long EventId_ThreadConnectivityChange = 0x8001; + public static final long EventId_InternetConnectivityChange = 0x8002; + public static final long EventId_ServiceConnectivityChange = 0x8003; + public static final long EventId_ServiceProvisioningChange = 0x8004; + public static final long EventId_TimeSyncChange = 0x8005; + public static final long EventId_ICDPollingIntervalChang = 0x8006; + public static final long EventId_CHIPoBLEConnectionEstablished = 0x8007; + public static final long EventId_CHIPoBLEConnectionClosed = 0x8008; + public static final long EventId_ThreadStateChange = 0x8009; + public static final long EventId_ThreadInterfaceStateChange = 0x800A; + public static final long EventId_CHIPoBLEAdvertisingChange = 0x800B; + public static final long EventId_InterfaceIpAddressChanged = 0x800C; + public static final long EventId_CommissioningWindowStatusChanged = 0x800D; + public static final long EventId_CommissioningComplete = 0x800E; + public static final long EventId_FailSafeTimerExpired = 0x800F; + public static final long EventId_FailSafeStateChanged = 0x8010; + public static final long EventId_OperationalNetworkEnabled = 0x8011; + public static final long EventId_DnssdInitialized = 0x8012; + public static final long EventId_DnssdRestartNeeded = 0x8013; + public static final long EventId_BindingsChangedViaCluster = 0x8014; + public static final long EventId_OtaStateChanged = 0x8015; + public static final long EventId_ServerReady = 0x8016; + public static final long EventId_ChipMsgSentEvent = 0x8017; + public static final long EventId_ChipMsgRxEventHandled = 0x8018; + public static final long EventId_AppWakeUpEvent = 0x8018; - // out of public event range (0x8000) - public static final long EventId_FabricRemoved = 0x9FFF; + // out of public event range (0x8000) + public static final long EventId_FabricRemoved = 0x9FFF; } diff --git a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java index faa12f221e2909..5a6182e86afbd9 100644 --- a/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java +++ b/examples/virtual-device-app/android/java/src/com/matter/virtual/device/app/OnOffManager.java @@ -2,17 +2,14 @@ public interface OnOffManager { - /** - * initialize OnOff value by DeviceApp - */ - void initAttributeValue(); + /** initialize OnOff value by DeviceApp */ + void initAttributeValue(); - /** - * Notify that the OnOff value be changed by matter and should effect it. Note, - * set by DeviceApp will - * also trigger this function, so must check if value is same - * - * @param value - */ - void handleOnOffChanged(boolean value); + /** + * Notify that the OnOff value be changed by matter and should effect it. Note, set by DeviceApp + * will also trigger this function, so must check if value is same + * + * @param value + */ + void handleOnOffChanged(boolean value); }