From da61aaed0832995098ea48b925550be04dd0c8b7 Mon Sep 17 00:00:00 2001 From: Sharad Binjola <31142146+sharadb-amazon@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:55:22 -0700 Subject: [PATCH] Android tv-casting-app: refactored Initialization (#28875) * Android tv-casting-app: refactored Initialization --- .../com/chip/casting/app/MainActivity.java | 9 +- .../casting/util/GlobalCastingConstants.java | 2 + .../com/matter/casting/DACProviderStub.java | 99 +++++++++++ .../matter/casting/InitializationExample.java | 102 +++++++++++ .../com/matter/casting/core/CastingApp.java | 163 ++++++++++++++++++ .../matter/casting/core/CastingAppState.java | 8 + .../matter/casting/support/AppParameters.java | 81 +++++++++ .../casting/support/CommissionableData.java | 71 ++++++++ .../matter/casting/support/DACProvider.java | 39 +++++ .../matter/casting/support/DataProvider.java | 36 ++++ .../matter/casting/support/MatterError.java | 76 ++++++++ .../src/main/jni/cpp/core/CastingApp-JNI.cpp | 132 ++++++++++++++ .../src/main/jni/cpp/core/CastingApp-JNI.h | 41 +++++ .../jni/cpp/support/ErrorConverter-JNI.cpp | 43 +++++ .../main/jni/cpp/support/ErrorConverter-JNI.h | 31 ++++ .../RotatingDeviceIdUniqueIdProvider-JNI.cpp | 94 ++++++++++ .../RotatingDeviceIdUniqueIdProvider-JNI.h | 44 +++++ examples/tv-casting-app/android/BUILD.gn | 21 +++ .../tv-casting-common/core/CastingApp.cpp | 2 +- .../tv-casting-common/core/CastingApp.h | 16 +- .../tv-casting-common/core/Types.h | 4 +- 21 files changed, 1100 insertions(+), 14 deletions(-) create mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DACProviderStub.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingApp.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingAppState.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionableData.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DACProvider.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/MatterError.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.cpp create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.h create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.cpp create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.h create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.cpp create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.h diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java index 864f993544c760..de1b547f929dd5 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java @@ -8,9 +8,9 @@ import com.chip.casting.AppParameters; import com.chip.casting.DiscoveredNodeData; import com.chip.casting.TvCastingApp; -import com.chip.casting.util.DACProviderStub; import com.chip.casting.util.GlobalCastingConstants; import com.chip.casting.util.PreferencesConfigurationManager; +import com.matter.casting.InitializationExample; import java.util.Random; public class MainActivity extends AppCompatActivity @@ -27,7 +27,10 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - boolean ret = initJni(); + boolean ret = + GlobalCastingConstants.ChipCastingSimplified + ? InitializationExample.initAndStart(this.getApplicationContext()).hasNoError() + : initJni(); if (!ret) { Log.e(TAG, "Failed to initialize Matter TV casting library"); return; @@ -78,7 +81,7 @@ public void handleDisconnect() { private boolean initJni() { tvCastingApp = TvCastingApp.getInstance(); - tvCastingApp.setDACProvider(new DACProviderStub()); + tvCastingApp.setDACProvider(new com.chip.casting.util.DACProviderStub()); AppParameters appParameters = new AppParameters(); appParameters.setConfigurationManager( diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java index 4bd6d25a08364c..d063cc7e6f78c5 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java @@ -5,4 +5,6 @@ public class GlobalCastingConstants { public static final int CommissioningWindowDurationSecs = 3 * 60; public static final int SetupPasscode = 20202021; public static final int Discriminator = 0xF00; + public static final boolean ChipCastingSimplified = + false; // set this flag to true to demo simplified casting APIs } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DACProviderStub.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DACProviderStub.java new file mode 100644 index 00000000000000..37bc17dd59ca6f --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DACProviderStub.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting; + +import android.util.Base64; +import com.matter.casting.support.DACProvider; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPrivateKeySpec; + +public class DACProviderStub implements DACProvider { + + private String kDevelopmentDAC_Cert_FFF1_8001 = + "MIIB5zCCAY6gAwIBAgIIac3xDenlTtEwCgYIKoZIzj0EAwIwPTElMCMGA1UEAwwcTWF0dGVyIERldiBQQUkgMHhGRkYxIG5vIFBJRDEUMBIGCisGAQQBgqJ8AgEMBEZGRjEwIBcNMjIwMjA1MDAwMDAwWhgPOTk5OTEyMzEyMzU5NTlaMFMxJTAjBgNVBAMMHE1hdHRlciBEZXYgREFDIDB4RkZGMS8weDgwMDExFDASBgorBgEEAYKifAIBDARGRkYxMRQwEgYKKwYBBAGConwCAgwEODAwMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEY6xpNCkQoOVYj8b/Vrtj5i7M7LFI99TrA+5VJgFBV2fRalxmP3k+SRIyYLgpenzX58/HsxaznZjpDSk3dzjoKjYDBeMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSI3eezADgpMs/3NMBGJIEPRBaKbzAfBgNVHSMEGDAWgBRjVA5H9kscONE4hKRi0WwZXY/7PDAKBggqhkjOPQQDAgNHADBEAiABJ6J7S0RhDuL83E0reIVWNmC8D3bxchntagjfsrPBzQIga1ngr0Xz6yqFuRnTVzFSjGAoxBUjlUXhCOTlTnCXE1M="; + + private String kDevelopmentDAC_PrivateKey_FFF1_8001 = + "qrYAroroqrfXNifCF7fCBHCcppRq9fL3UwgzpStE+/8="; + + private String kDevelopmentDAC_PublicKey_FFF1_8001 = + "BEY6xpNCkQoOVYj8b/Vrtj5i7M7LFI99TrA+5VJgFBV2fRalxmP3k+SRIyYLgpenzX58/HsxaznZjpDSk3dzjoI="; + + private String KPAI_FFF1_8000_Cert_Array = + "MIIByzCCAXGgAwIBAgIIVq2CIq2UW2QwCgYIKoZIzj0EAwIwMDEYMBYGA1UEAwwPTWF0dGVyIFRlc3QgUEFBMRQwEgYKKwYBBAGConwCAQwERkZGMTAgFw0yMjAyMDUwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowPTElMCMGA1UEAwwcTWF0dGVyIERldiBQQUkgMHhGRkYxIG5vIFBJRDEUMBIGCisGAQQBgqJ8AgEMBEZGRjEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARBmpMVwhc+DIyHbQPM/JRIUmR/f+xeUIL0BZko7KiUxZQVEwmsYx5MsDOSr2hLC6+35ls7gWLC9Sv5MbjneqqCo2YwZDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUY1QOR/ZLHDjROISkYtFsGV2P+zwwHwYDVR0jBBgwFoAUav0idx9RH+y/FkGXZxDc3DGhcX4wCgYIKoZIzj0EAwIDSAAwRQIhALLvJ/Sa6bUPuR7qyUxNC9u415KcbLiPrOUpNo0SBUwMAiBlXckrhr2QmIKmxiF3uCXX0F7b58Ivn+pxIg5+pwP4kQ=="; + + /** + * format_version = 1 vendor_id = 0xFFF1 product_id_array = [ 0x8000,0x8001...0x8063] + * device_type_id = 0x1234 certificate_id = "ZIG20141ZB330001-24" security_level = 0 + * security_information = 0 version_number = 0x2694 certification_type = 0 dac_origin_vendor_id is + * not present dac_origin_product_id is not present + */ + private String kCertificationDeclaration = + "MIICGQYJKoZIhvcNAQcCoIICCjCCAgYCAQMxDTALBglghkgBZQMEAgEwggFxBgkqhkiG9w0BBwGgggFiBIIBXhUkAAElAfH/NgIFAIAFAYAFAoAFA4AFBIAFBYAFBoAFB4AFCIAFCYAFCoAFC4AFDIAFDYAFDoAFD4AFEIAFEYAFEoAFE4AFFIAFFYAFFoAFF4AFGIAFGYAFGoAFG4AFHIAFHYAFHoAFH4AFIIAFIYAFIoAFI4AFJIAFJYAFJoAFJ4AFKIAFKYAFKoAFK4AFLIAFLYAFLoAFL4AFMIAFMYAFMoAFM4AFNIAFNYAFNoAFN4AFOIAFOYAFOoAFO4AFPIAFPYAFPoAFP4AFQIAFQYAFQoAFQ4AFRIAFRYAFRoAFR4AFSIAFSYAFSoAFS4AFTIAFTYAFToAFT4AFUIAFUYAFUoAFU4AFVIAFVYAFVoAFV4AFWIAFWYAFWoAFW4AFXIAFXYAFXoAFX4AFYIAFYYAFYoAFY4AYJAMWLAQTWklHMjAxNDJaQjMzMDAwMy0yNCQFACQGACUHlCYkCAAYMX0wewIBA4AUYvqCM1ms+qmWPhz6FArd9QTzcWAwCwYJYIZIAWUDBAIBMAoGCCqGSM49BAMCBEcwRQIgJOXR9Hp9ew0gaibvaZt8l1e3LUaQid4xkuZ4x0Xn9gwCIQD4qi+nEfy3m5fjl87aZnuuRk4r0//fw8zteqjKX0wafA=="; + + @Override + public byte[] GetCertificationDeclaration() { + return Base64.decode(kCertificationDeclaration, Base64.DEFAULT); + } + + @Override + public byte[] GetFirmwareInformation() { + return new byte[0]; + } + + @Override + public byte[] GetDeviceAttestationCert() { + return Base64.decode(kDevelopmentDAC_Cert_FFF1_8001, Base64.DEFAULT); + } + + @Override + public byte[] GetProductAttestationIntermediateCert() { + return Base64.decode(KPAI_FFF1_8000_Cert_Array, Base64.DEFAULT); + } + + @Override + public byte[] SignWithDeviceAttestationKey(byte[] message) { + + try { + byte[] privateKeyBytes = Base64.decode(kDevelopmentDAC_PrivateKey_FFF1_8001, Base64.DEFAULT); + + AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("EC"); + algorithmParameters.init(new ECGenParameterSpec("secp256r1")); + ECParameterSpec parameterSpec = algorithmParameters.getParameterSpec(ECParameterSpec.class); + ECPrivateKeySpec ecPrivateKeySpec = + new ECPrivateKeySpec(new BigInteger(1, privateKeyBytes), parameterSpec); + + KeyFactory keyFactory = KeyFactory.getInstance("EC"); + PrivateKey privateKey = keyFactory.generatePrivate(ecPrivateKeySpec); + + Signature signature = Signature.getInstance("SHA256withECDSA"); + signature.initSign(privateKey); + + signature.update(message); + + return signature.sign(); + + } catch (Exception e) { + return null; + } + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java new file mode 100644 index 00000000000000..0d2135e1a7bc66 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/InitializationExample.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting; + +import android.content.Context; +import android.util.Log; +import chip.platform.ConfigurationManager; +import com.chip.casting.util.PreferencesConfigurationManager; +import com.matter.casting.core.CastingApp; +import com.matter.casting.support.AppParameters; +import com.matter.casting.support.CommissionableData; +import com.matter.casting.support.DACProvider; +import com.matter.casting.support.DataProvider; +import com.matter.casting.support.MatterError; + +public class InitializationExample { + private static final String TAG = InitializationExample.class.getSimpleName(); + + /** + * DataProvider implementation for the Unique ID that is used by the SDK to generate the Rotating + * Device ID + */ + private static final DataProvider rotatingDeviceIdUniqueIdProvider = + new DataProvider() { + private static final String ROTATING_DEVICE_ID_UNIQUE_ID = + "EXAMPLE_ID"; // dummy value for demonstration only + + @Override + public byte[] get() { + return ROTATING_DEVICE_ID_UNIQUE_ID.getBytes(); + } + }; + + /** + * DataProvider implementation for the Commissioning Data used by the SDK when the CastingApp goes + * through commissioning + */ + private static final DataProvider commissionableDataProvider = + new DataProvider() { + @Override + public CommissionableData get() { + // dummy values for demonstration only + return new CommissionableData(20202021, 3874); + } + }; + + /** + * DACProvider implementation for the Device Attestation Credentials required at the time of + * commissioning + * + *

Using the DACProviderStub which provides dummy values for demonstration only + */ + private static final DACProvider dacProvider = new DACProviderStub(); + + /** + * @param applicationContext Given android.content.Context, initialize and start the CastingApp + */ + public static MatterError initAndStart(Context applicationContext) { + // Create an AppParameters object to pass in global casting parameters to the SDK + final AppParameters appParameters = + new AppParameters( + applicationContext, + new DataProvider() { + @Override + public ConfigurationManager get() { + return new PreferencesConfigurationManager( + applicationContext, "chip.platform.ConfigurationManager"); + } + }, + rotatingDeviceIdUniqueIdProvider, + commissionableDataProvider, + dacProvider); + + // Initialize the SDK using the appParameters and check if it returns successfully + MatterError err = CastingApp.getInstance().initialize(appParameters); + if (err.hasError()) { + Log.e(TAG, "Failed to initialize Matter CastingApp"); + return err; + } + + err = CastingApp.getInstance().start(); + if (err.hasError()) { + Log.e(TAG, "Failed to start Matter CastingApp"); + return err; + } + return err; + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingApp.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingApp.java new file mode 100644 index 00000000000000..0823920503d9db --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingApp.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting.core; + +import android.content.Context; +import android.util.Log; +import chip.appserver.ChipAppServer; +import chip.platform.AndroidBleManager; +import chip.platform.AndroidChipPlatform; +import chip.platform.ChipMdnsCallbackImpl; +import chip.platform.DiagnosticDataProviderImpl; +import chip.platform.NsdManagerServiceBrowser; +import chip.platform.NsdManagerServiceResolver; +import chip.platform.PreferencesKeyValueStoreManager; +import com.matter.casting.support.AppParameters; +import com.matter.casting.support.CommissionableData; +import com.matter.casting.support.MatterError; + +/** + * CastingApp represents an app that can cast content to a Casting Player. This class is a + * singleton. + */ +public final class CastingApp { + private static final String TAG = CastingApp.class.getSimpleName(); + + private static CastingApp sInstance; + + private CastingAppState mState = CastingAppState.UNINITIALIZED; + private AppParameters appParameters; + private NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState; + private ChipAppServer chipAppServer; + + private CastingApp() {} + + public static CastingApp getInstance() { + if (sInstance == null) { + sInstance = new CastingApp(); + } + return sInstance; + } + + /** + * Initializes the CastingApp with appParameters + * + * @param appParameters + */ + public MatterError initialize(AppParameters appParameters) { + Log.i(TAG, "CastingApp.initialize called"); + if (mState != CastingAppState.UNINITIALIZED) { + return MatterError.CHIP_ERROR_INCORRECT_STATE; + } + + this.appParameters = appParameters; + this.nsdManagerResolverAvailState = + new NsdManagerServiceResolver.NsdManagerResolverAvailState(); + + Context applicationContext = appParameters.getApplicationContext(); + AndroidChipPlatform chipPlatform = + new AndroidChipPlatform( + new AndroidBleManager(), + new PreferencesKeyValueStoreManager(appParameters.getApplicationContext()), + appParameters.getConfigurationManagerProvider().get(), + new NsdManagerServiceResolver(applicationContext, nsdManagerResolverAvailState), + new NsdManagerServiceBrowser(applicationContext), + new ChipMdnsCallbackImpl(), + new DiagnosticDataProviderImpl(applicationContext)); + + CommissionableData commissionableData = appParameters.getCommissionableDataProvider().get(); + boolean updated = + chipPlatform.updateCommissionableDataProviderData( + commissionableData.getSpake2pVerifierBase64(), + commissionableData.getSpake2pSaltBase64(), + commissionableData.getSpake2pIterationCount(), + commissionableData.getSetupPasscode(), + commissionableData.getDiscriminator()); + if (!updated) { + Log.e( + TAG, "CastingApp.initApp failed to updateCommissionableDataProviderData on chipPlatform"); + return MatterError.CHIP_ERROR_INVALID_ARGUMENT; + } + + MatterError err = finishInitialization(appParameters); + + if (err.hasNoError()) { + chipAppServer = new ChipAppServer(); // get a reference to the Matter server now + mState = CastingAppState.NOT_RUNNING; // initialization done, set state to NOT_RUNNING + } + return err; + } + + /** + * Starts the Matter server that the CastingApp runs on and registers all the necessary delegates + */ + public MatterError start() { + Log.i(TAG, "CastingApp.start called"); + if (mState != CastingAppState.NOT_RUNNING) { + return MatterError.CHIP_ERROR_INCORRECT_STATE; + } + + boolean serverStarted = chipAppServer.startApp(); + if (!serverStarted) { + Log.e(TAG, "CastingApp.start failed to start Matter server"); + return MatterError.CHIP_ERROR_INCORRECT_STATE; + } + + MatterError err = finishStartup(); + if (err.hasNoError()) { + mState = CastingAppState.RUNNING; // CastingApp started successfully, set state to RUNNING + } + return err; + } + + /** + * Stops the Matter server that the CastingApp runs on + * + * @return + */ + public MatterError stop() { + Log.i(TAG, "CastingApp.stop called"); + if (mState != CastingAppState.RUNNING) { + return MatterError.CHIP_ERROR_INCORRECT_STATE; + } + + boolean serverStopped = chipAppServer.stopApp(); + if (!serverStopped) { + Log.e(TAG, "CastingApp.stop failed to stop Matter server"); + return MatterError.CHIP_ERROR_INCORRECT_STATE; + } + mState = + CastingAppState.NOT_RUNNING; // CastingApp stopped successfully, set state to NOT_RUNNING + + return MatterError.NO_ERROR; + } + + /** + * Sets DeviceAttestationCrdentials provider and RotatingDeviceIdUniqueId + * + * @param appParameters + */ + private native MatterError finishInitialization(AppParameters appParameters); + + /** Performs post Matter server startup registrations */ + private native MatterError finishStartup(); + + static { + System.loadLibrary("TvCastingApp"); + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingAppState.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingAppState.java new file mode 100644 index 00000000000000..89ddef7aa0dbf6 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/core/CastingAppState.java @@ -0,0 +1,8 @@ +package com.matter.casting.core; + +/** Represents the state of the CastingApp */ +enum CastingAppState { + UNINITIALIZED, // Before Initialize() success + NOT_RUNNING, // After Initialize() success before Start()ing, OR After stop() success + RUNNING, // After Start() success +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java new file mode 100644 index 00000000000000..0734271ca89b88 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/AppParameters.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting.support; + +import android.content.Context; +import androidx.annotation.NonNull; +import chip.platform.ConfigurationManager; + +public class AppParameters { + @NonNull private final Context applicationContext; + + @NonNull private final DataProvider configurationManagerProvider; + + @NonNull private final DataProvider rotatingDeviceIdUniqueIdProvider; + + @NonNull private final DataProvider commissionableDataProvider; + + @NonNull private final DACProvider dacProvider; + + /** + * @param applicationContext the Android app's android.content.Context + * @param configurationManagerProvider Implementation of chip.platform.ConfigurationManager + * @param rotatingDeviceIdUniqueIdProvider Provides values of the uniqueID used to generate the + * RotatingDeviceId of the CastingApp + * @param commissionableDataProvider Provides CommissionableData (such as setupPasscode, + * discriminator, etc) used to get the CastingApp commissioned + * @param dacProvider Provides DeviceAttestationCredentials of the CastingApp during commissioning + */ + public AppParameters( + @NonNull Context applicationContext, + @NonNull DataProvider configurationManagerProvider, + @NonNull DataProvider rotatingDeviceIdUniqueIdProvider, + @NonNull DataProvider commissionableDataProvider, + @NonNull DACProvider dacProvider) { + this.applicationContext = applicationContext; + this.configurationManagerProvider = configurationManagerProvider; + this.rotatingDeviceIdUniqueIdProvider = rotatingDeviceIdUniqueIdProvider; + this.commissionableDataProvider = commissionableDataProvider; + this.dacProvider = dacProvider; + } + + @NonNull + public Context getApplicationContext() { + return applicationContext; + } + + @NonNull + public DataProvider getConfigurationManagerProvider() { + return configurationManagerProvider; + } + + @NonNull + public DataProvider getRotatingDeviceIdUniqueIdProvider() { + return rotatingDeviceIdUniqueIdProvider; + } + + @NonNull + public DataProvider getCommissionableDataProvider() { + return commissionableDataProvider; + } + + @NonNull + public DACProvider getDacProvider() { + return dacProvider; + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionableData.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionableData.java new file mode 100644 index 00000000000000..b436c98c533786 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/CommissionableData.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting.support; + +import androidx.annotation.Nullable; + +public class CommissionableData { + private long setupPasscode; + + private int discriminator; + + @Nullable private String spake2pVerifierBase64; + + @Nullable private String spake2pSaltBase64; + + private int spake2pIterationCount; + + public CommissionableData(long setupPasscode, int discriminator) { + this.setupPasscode = setupPasscode; + this.discriminator = discriminator; + } + + public long getSetupPasscode() { + return setupPasscode; + } + + public int getDiscriminator() { + return discriminator; + } + + @Nullable + public String getSpake2pVerifierBase64() { + return spake2pVerifierBase64; + } + + public void setSpake2pVerifierBase64(@Nullable String spake2pVerifierBase64) { + this.spake2pVerifierBase64 = spake2pVerifierBase64; + } + + @Nullable + public String getSpake2pSaltBase64() { + return spake2pSaltBase64; + } + + public void setSpake2pSaltBase64(@Nullable String spake2pSaltBase64) { + this.spake2pSaltBase64 = spake2pSaltBase64; + } + + public int getSpake2pIterationCount() { + return spake2pIterationCount; + } + + public void setSpake2pIterationCount(int spake2pIterationCount) { + this.spake2pIterationCount = spake2pIterationCount; + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DACProvider.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DACProvider.java new file mode 100644 index 00000000000000..3fdca947e3b035 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DACProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting.support; + +public interface DACProvider { + byte[] GetCertificationDeclaration(); + + byte[] GetFirmwareInformation(); + + byte[] GetDeviceAttestationCert(); + + byte[] GetProductAttestationIntermediateCert(); + + /** + * Sign a mesage with the device attestation key. + * + *

The signature should be a SHA256withECDSA Signature that's returned in the ECDSA X9.62 Asn1 + * format. This is the default behavior when using java.security.Signature with an EC P-256 curve. + * + * @param message The message to sign + * @return The signature in ECDSA X9.62 Asn1 format. + */ + byte[] SignWithDeviceAttestationKey(byte[] message); +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java new file mode 100644 index 00000000000000..eb701413bcd477 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/DataProvider.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting.support; + +import android.util.Log; + +public abstract class DataProvider { + private static final String TAG = DataProvider.class.getSimpleName(); + + protected T _get() { + T val = null; + try { + val = get(); + } catch (Throwable t) { + Log.e(TAG, "DataProvider::Caught an unhandled Throwable from the client: " + t); + } + return val; + } + + public abstract T get(); +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/MatterError.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/MatterError.java new file mode 100644 index 00000000000000..c570cf60e7f70c --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/matter/casting/support/MatterError.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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.casting.support; + +import java.util.Objects; + +public class MatterError { + private long errorCode; + private String errorMessage; + + public static final MatterError NO_ERROR = new MatterError(0, null); + + public static final MatterError CHIP_ERROR_INVALID_ARGUMENT = + new MatterError(0x2f, "CHIP_ERROR_INVALID_ARGUMENT"); + + public static final MatterError CHIP_ERROR_INCORRECT_STATE = + new MatterError(0x03, "CHIP_ERROR_INCORRECT_STATE"); + + public MatterError(long errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public boolean hasError() { + return !this.equals(NO_ERROR); + } + + public boolean hasNoError() { + return this.equals(NO_ERROR); + } + + public long getErrorCode() { + return errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + @Override + public String toString() { + return "MatterError{" + + (hasNoError() + ? "No error" + : "errorCode=" + errorCode + ", errorMessage='" + errorMessage + '\'') + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MatterError matterError = (MatterError) o; + return errorCode == matterError.getErrorCode(); + } + + @Override + public int hashCode() { + return Objects.hash(errorCode); + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.cpp new file mode 100644 index 00000000000000..984287af8c30fd --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + * + */ + +#include "CastingApp-JNI.h" + +#include "../JNIDACProvider.h" +#include "../support/ErrorConverter-JNI.h" +#include "../support/RotatingDeviceIdUniqueIdProvider-JNI.h" +#include "core/CastingApp.h" // from tv-casting-common + +#include +#include +#include +#include +#include + +using namespace chip; + +#define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_com_matter_casting_core_CastingApp_##METHOD_NAME + +namespace matter { +namespace casting { +namespace core { + +CastingAppJNI CastingAppJNI::sInstance; + +jobject extractJAppParameter(jobject jAppParameters, const char * methodName, const char * methodSig); + +JNI_METHOD(jobject, finishInitialization)(JNIEnv *, jobject, jobject jAppParameters) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(AppServer, "JNI_METHOD CastingAppJNI.finishInitialization called"); + VerifyOrReturnValue(jAppParameters != nullptr, support::createJMatterError(CHIP_ERROR_INVALID_ARGUMENT)); + CHIP_ERROR err = CHIP_NO_ERROR; + + jobject jUniqueIdProvider = + extractJAppParameter(jAppParameters, "getRotatingDeviceIdUniqueIdProvider", "()Lcom/matter/casting/support/DataProvider;"); + VerifyOrReturnValue(jUniqueIdProvider != nullptr, support::createJMatterError(CHIP_ERROR_INCORRECT_STATE)); + support::RotatingDeviceIdUniqueIdProviderJNI * uniqueIdProvider = new support::RotatingDeviceIdUniqueIdProviderJNI(); + err = uniqueIdProvider->Initialize(jUniqueIdProvider); + VerifyOrReturnValue(err == CHIP_NO_ERROR, support::createJMatterError(CHIP_ERROR_INVALID_ARGUMENT)); + + // set the RotatingDeviceIdUniqueId +#if CHIP_ENABLE_ROTATING_DEVICE_ID + chip::MutableByteSpan * uniqueId = uniqueIdProvider->Get(); + if (uniqueId != nullptr) + { + chip::DeviceLayer::ConfigurationMgr().SetRotatingDeviceIdUniqueId(*uniqueId); + } +#endif // CHIP_ENABLE_ROTATING_DEVICE_ID + + // get the DACProvider + jobject jDACProvider = extractJAppParameter(jAppParameters, "getDacProvider", "()Lcom/matter/casting/support/DACProvider;"); + VerifyOrReturnValue(jDACProvider != nullptr, support::createJMatterError(CHIP_ERROR_INCORRECT_STATE)); + + // set the DACProvider + JNIDACProvider * dacProvider = new JNIDACProvider(jDACProvider); + chip::Credentials::SetDeviceAttestationCredentialsProvider(dacProvider); + + return support::createJMatterError(CHIP_NO_ERROR); +} + +JNI_METHOD(jobject, finishStartup)(JNIEnv *, jobject) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(AppServer, "JNI_METHOD CastingAppJNI.finishStartup called"); + auto & server = chip::Server::GetInstance(); + + // TODO: Set AppDelegate + // &server.GetCommissioningWindowManager().SetAppDelegate(??); + + // Initialize binding handlers + chip::BindingManager::GetInstance().Init( + { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() }); + + // TODO: Set FabricDelegate + // chip::Server::GetInstance().GetFabricTable().AddFabricDelegate(&mPersistenceManager); + + // TODO: Add DeviceEvent Handler + // ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().AddEventHandler(DeviceEventCallback, 0)); + + return support::createJMatterError(CHIP_NO_ERROR); +} + +jobject extractJAppParameter(jobject jAppParameters, const char * methodName, const char * methodSig) +{ + ChipLogProgress(AppServer, "JNI_METHOD extractJAppParameter called"); + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass jAppParametersClass; + CHIP_ERROR err = + chip::JniReferences::GetInstance().GetClassRef(env, "com/matter/casting/support/AppParameters", jAppParametersClass); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr); + + // get the RotatingDeviceIdUniqueIdProvider + jmethodID getMethod = env->GetMethodID(jAppParametersClass, methodName, methodSig); + if (env->ExceptionCheck()) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + return nullptr; + } + + jobject jParameter = (jobject) env->CallObjectMethod(jAppParameters, getMethod); + if (env->ExceptionCheck()) + { + env->ExceptionDescribe(); + env->ExceptionClear(); + return nullptr; + } + + return jParameter; +} + +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.h new file mode 100644 index 00000000000000..668ab78fdcfccd --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/CastingApp-JNI.h @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#pragma once + +#include + +namespace matter { +namespace casting { +namespace core { + +class CastingAppJNI +{ +public: +private: + friend CastingAppJNI & CastingAppJNIMgr(); + static CastingAppJNI sInstance; +}; + +inline class CastingAppJNI & CastingAppJNIMgr() +{ + return CastingAppJNI::sInstance; +} +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.cpp new file mode 100644 index 00000000000000..171a44dc793f9f --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + * + */ + +#include "ErrorConverter-JNI.h" +#include + +namespace matter { +namespace casting { +namespace support { + +using namespace chip; + +jobject createJMatterError(CHIP_ERROR inErr) +{ + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + jclass jMatterErrorClass; + CHIP_ERROR err = + chip::JniReferences::GetInstance().GetClassRef(env, "com/matter/casting/support/MatterError", jMatterErrorClass); + VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr); + + jmethodID jMatterErrorConstructor = env->GetMethodID(jMatterErrorClass, "", "(JLjava/lang/String;)V"); + + return env->NewObject(jMatterErrorClass, jMatterErrorConstructor, err.AsInteger(), nullptr); +} + +}; // namespace support +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.h new file mode 100644 index 00000000000000..e11523397db4f3 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/ErrorConverter-JNI.h @@ -0,0 +1,31 @@ +/* + * + * 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. + */ +#pragma once + +#include + +#include + +namespace matter { +namespace casting { +namespace support { + +jobject createJMatterError(CHIP_ERROR inErr); + +}; // namespace support +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.cpp new file mode 100644 index 00000000000000..e010b56da36b28 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.cpp @@ -0,0 +1,94 @@ +/* + * + * 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. + */ + +#include "RotatingDeviceIdUniqueIdProvider-JNI.h" +#include "lib/support/logging/CHIPLogging.h" +#include +#include +#include +#include +#include +#include + +using namespace chip; + +namespace matter { +namespace casting { +namespace support { + +CHIP_ERROR RotatingDeviceIdUniqueIdProviderJNI::Initialize(jobject provider) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnValue(env != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, "Failed to GetEnvForCurrentThread for RotatingDeviceIdUniqueIdProviderJNI")); + + mJNIProviderObject = env->NewGlobalRef(provider); + VerifyOrReturnValue(mJNIProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, "Failed to NewGlobalRef JNIProvider")); + + jclass JNIProviderClass = env->GetObjectClass(provider); + VerifyOrReturnValue(JNIProviderClass != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(AppServer, "Failed to get JNIProvider Java class")); + + mGetMethod = env->GetMethodID(JNIProviderClass, "_get", "()Ljava/lang/Object;"); + if (mGetMethod == nullptr) + { + ChipLogError(AppServer, "Failed to access JNIProvider '_get' method"); + env->ExceptionClear(); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR RotatingDeviceIdUniqueIdProviderJNI::GetJavaByteByMethod(jmethodID method, MutableByteSpan & out_buffer) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnLogError(mJNIProviderObject != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(method != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnLogError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); + + jbyteArray outArray = (jbyteArray) env->CallObjectMethod(mJNIProviderObject, method); + if (env->ExceptionCheck()) + { + ChipLogError(AppServer, "Java exception in get Method"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + if (outArray == nullptr || env->GetArrayLength(outArray) <= 0) + { + out_buffer.reduce_size(0); + return CHIP_NO_ERROR; + } + + JniByteArray JniOutArray(env, outArray); + return CopySpanToMutableSpan(JniOutArray.byteSpan(), out_buffer); +} + +MutableByteSpan * RotatingDeviceIdUniqueIdProviderJNI::Get() +{ + ChipLogProgress(AppServer, "RotatingDeviceIdUniqueIdProviderJNI.Get() called"); + mRotatingDeviceIdUniqueIdSpan = MutableByteSpan(mRotatingDeviceIdUniqueId); + CHIP_ERROR err = GetJavaByteByMethod(mGetMethod, mRotatingDeviceIdUniqueIdSpan); + VerifyOrReturnValue(err != CHIP_NO_ERROR, nullptr, + ChipLogError(AppServer, "Error calling GetJavaByteByMethod %" CHIP_ERROR_FORMAT, err.Format())); + return &mRotatingDeviceIdUniqueIdSpan; +} + +}; // namespace support +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.h new file mode 100644 index 00000000000000..fdec7744684834 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.h @@ -0,0 +1,44 @@ +/* + * + * 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. + */ +#pragma once + +#include "core/Types.h" + +#include + +namespace matter { +namespace casting { +namespace support { + +class RotatingDeviceIdUniqueIdProviderJNI : public MutableByteSpanDataProvider +{ +public: + CHIP_ERROR Initialize(jobject provider); + chip::MutableByteSpan * Get() override; + +private: + CHIP_ERROR GetJavaByteByMethod(jmethodID method, chip::MutableByteSpan & out_buffer); + jobject mJNIProviderObject = nullptr; + jmethodID mGetMethod = nullptr; + + chip::MutableByteSpan mRotatingDeviceIdUniqueIdSpan; + uint8_t mRotatingDeviceIdUniqueId[chip::DeviceLayer::ConfigurationManager::kRotatingDeviceIDUniqueIDLength]; +}; + +}; // namespace support +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/android/BUILD.gn b/examples/tv-casting-app/android/BUILD.gn index d072dd4c088e95..ae349bce337efe 100644 --- a/examples/tv-casting-app/android/BUILD.gn +++ b/examples/tv-casting-app/android/BUILD.gn @@ -34,6 +34,16 @@ shared_library("jni") { "App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp", ] + # add simplified casting API files here + sources += [ + "App/app/src/main/jni/cpp/core/CastingApp-JNI.cpp", + "App/app/src/main/jni/cpp/core/CastingApp-JNI.h", + "App/app/src/main/jni/cpp/support/ErrorConverter-JNI.cpp", + "App/app/src/main/jni/cpp/support/ErrorConverter-JNI.h", + "App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.cpp", + "App/app/src/main/jni/cpp/support/RotatingDeviceIdUniqueIdProvider-JNI.h", + ] + deps = [ "${chip_root}/examples/tv-casting-app/tv-casting-common", "${chip_root}/src/app/server/java:jni", @@ -83,6 +93,17 @@ android_library("java") { "App/app/src/main/jni/com/chip/casting/VideoPlayer.java", ] + # add simplified casting API files here + sources += [ + "App/app/src/main/jni/com/matter/casting/core/CastingApp.java", + "App/app/src/main/jni/com/matter/casting/core/CastingAppState.java", + "App/app/src/main/jni/com/matter/casting/support/AppParameters.java", + "App/app/src/main/jni/com/matter/casting/support/CommissionableData.java", + "App/app/src/main/jni/com/matter/casting/support/DACProvider.java", + "App/app/src/main/jni/com/matter/casting/support/DataProvider.java", + "App/app/src/main/jni/com/matter/casting/support/MatterError.java", + ] + javac_flags = [ "-Xlint:deprecation" ] # TODO: add classpath support (we likely need to add something like diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp index cc21c29c9b5f30..3dd42d91d293bb 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp @@ -118,7 +118,7 @@ CHIP_ERROR CastingApp::Stop() // Shutdown the Matter server chip::Server::GetInstance().Shutdown(); - mState = NOT_RUNNING; // CastingApp started successfully, set state to RUNNING + mState = NOT_RUNNING; // CastingApp stopped successfully, set state to NOT_RUNNING return CHIP_ERROR_NOT_IMPLEMENTED; } diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.h b/examples/tv-casting-app/tv-casting-common/core/CastingApp.h index 1f122e1153c3ab..eed69e728d4358 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.h +++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.h @@ -53,20 +53,13 @@ class CastingApp CHIP_ERROR Initialize(const matter::casting::support::AppParameters & appParameters); /** - * @brief Starts the Matter server that the CastingApp runs on and calls PostStartRegistrations() to finish starting up the + * @brief Starts the Matter server that the CastingApp runs on and registers all the necessary delegates * CastingApp. * * @return CHIP_ERROR - CHIP_NO_ERROR if Matter server started successfully, specific error code otherwise. */ CHIP_ERROR Start(); - /** - * @brief Perform post Matter server startup registrations - * - * @return CHIP_ERROR - CHIP_NO_ERROR if all registrations succeeded, specific error code otherwise - */ - CHIP_ERROR PostStartRegistrations(); - /** * @brief Stops the Matter server that the CastingApp runs on * @@ -81,6 +74,13 @@ class CastingApp CastingApp(CastingApp & other) = delete; void operator=(const CastingApp &) = delete; + /** + * @brief Perform post Matter server startup registrations + * + * @return CHIP_ERROR - CHIP_NO_ERROR if all registrations succeeded, specific error code otherwise + */ + CHIP_ERROR PostStartRegistrations(); + const matter::casting::support::AppParameters * mAppParameters; CastingAppState mState = UNINITIALIZED; diff --git a/examples/tv-casting-app/tv-casting-common/core/Types.h b/examples/tv-casting-app/tv-casting-common/core/Types.h index a5dce75d60d181..691fc3d2b36944 100644 --- a/examples/tv-casting-app/tv-casting-common/core/Types.h +++ b/examples/tv-casting-app/tv-casting-common/core/Types.h @@ -37,11 +37,11 @@ using Strong = std::shared_ptr; } // namespace memory -namespace app { +namespace core { class CastingApp; -}; +}; // namespace core namespace support {