diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MainActivity.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MainActivity.java index 895685f03536c8..2fb375dbed5c93 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MainActivity.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/MainActivity.java @@ -7,7 +7,7 @@ import com.matter.tv.server.fragments.ContentAppFragment; import com.matter.tv.server.fragments.QrCodeFragment; import com.matter.tv.server.fragments.TerminalFragment; -import com.matter.tv.server.service.AppPlatformService; +import com.matter.tv.server.service.MatterServant; import java.util.LinkedHashMap; public class MainActivity extends AppCompatActivity { @@ -43,7 +43,7 @@ protected void onCreate(Bundle savedInstanceState) { // MainActivity is needed to launch dialog prompt // in UserPrompter - AppPlatformService.get().setActivity(this); + MatterServant.get().setActivity(this); BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation); bottomNavigationView.setOnItemSelectedListener(navListener); diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java index bb4ad37a1667c7..faaa3247320186 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/AppPlatformService.java @@ -22,17 +22,30 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.util.Log; import androidx.annotation.NonNull; -import com.matter.tv.server.MatterCommissioningPrompter; import com.matter.tv.server.handlers.ContentAppEndpointManagerImpl; import com.matter.tv.server.model.ContentApp; import com.matter.tv.server.receivers.ContentAppDiscoveryService; import com.matter.tv.server.tvapp.AppPlatform; +import java.util.HashMap; +import java.util.Map; +/** + * This class facilitates the communication with the ContentAppPlatform. It uses the JNI interface + * provided via the {@link AppPlatform} class to communicate with the linux layer of the + * platform-app. This class also manages the content app endpoints that get added via the + * ContentAppPlatform. It manages the persistence of the endpoints that were discovered to be able + * to reuse endpointIds after restart of the platform-app. + */ public class AppPlatformService { + private static final String TAG = "AppPlatformService"; + private static final String MATTER_APPPLATFORM_ENDPOINTS = "matter.appplatform.endpoints"; private AppPlatform mAppPlatform; private BroadcastReceiver mBroadcastReceiver; + private SharedPreferences discoveredEndpoints; private AppPlatformService() {} @@ -49,14 +62,23 @@ public static AppPlatformService get() { public void init(@NonNull Context context) { this.context = context; - mAppPlatform = - new AppPlatform( - new MatterCommissioningPrompter(activity), new ContentAppEndpointManagerImpl(context)); + discoveredEndpoints = + context.getSharedPreferences(MATTER_APPPLATFORM_ENDPOINTS, Context.MODE_PRIVATE); + mAppPlatform = new AppPlatform(new ContentAppEndpointManagerImpl(context)); ContentAppDiscoveryService.getReceiverInstance().registerSelf(context.getApplicationContext()); + Map previouslyPersistedEndpoints = new HashMap(); + previouslyPersistedEndpoints.putAll((Map) discoveredEndpoints.getAll()); for (ContentApp app : ContentAppDiscoveryService.getReceiverInstance().getDiscoveredContentApps().values()) { addContentApp(app); + previouslyPersistedEndpoints.remove(app.getAppName()); + } + SharedPreferences.Editor editor = discoveredEndpoints.edit(); + for (Map.Entry appEntry : previouslyPersistedEndpoints.entrySet()) { + editor.remove(appEntry.getKey()); + // TODO : Figure out how to cleanup ACLs } + editor.apply(); registerReceiver(); } @@ -80,7 +102,7 @@ public void onReceive(Context context, Intent intent) { intent.getIntExtra( ContentAppDiscoveryService.DISCOVERY_APPAGENT_EXTRA_ENDPOINTID, -1); if (endpointId != -1) { - removeContentApp(endpointId); + removeContentApp(endpointId, packageName); } } } @@ -98,17 +120,41 @@ public void setActivity(Activity activity) { } public void addContentApp(ContentApp app) { - app.setEndpointId( - mAppPlatform.addContentApp( - app.getVendorName(), - app.getVendorId(), - app.getAppName(), - app.getProductId(), - "1.0", - new ContentAppEndpointManagerImpl(context))); + int retEndpointId = -1; + int desiredEndpointId = discoveredEndpoints.getInt(app.getAppName(), -1); + if (desiredEndpointId > 0) { + retEndpointId = + mAppPlatform.addContentAppAtEndpoint( + app.getVendorName(), + app.getVendorId(), + app.getAppName(), + app.getProductId(), + "1.0", + desiredEndpointId, + new ContentAppEndpointManagerImpl(context)); + } else { + retEndpointId = + mAppPlatform.addContentApp( + app.getVendorName(), + app.getVendorId(), + app.getAppName(), + app.getProductId(), + "1.0", + new ContentAppEndpointManagerImpl(context)); + } + if (retEndpointId > 0) { + app.setEndpointId(retEndpointId); + discoveredEndpoints.edit().putInt(app.getAppName(), app.getEndpointId()).apply(); + } else { + Log.e(TAG, "Could not add content app as endpoint. App Name " + app.getAppName()); + } } - public int removeContentApp(int endpointID) { - return mAppPlatform.removeContentApp(endpointID); + public int removeContentApp(int endpointID, String appName) { + int retEndpointId = mAppPlatform.removeContentApp(endpointID); + if (endpointID == retEndpointId) { + discoveredEndpoints.edit().remove(appName).apply(); + } + return retEndpointId; } } diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java index 26ebb06f937ebe..a2d06c64ee07ce 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java @@ -17,6 +17,7 @@ */ package com.matter.tv.server.service; +import android.app.Activity; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; @@ -29,6 +30,7 @@ import chip.platform.NsdManagerServiceResolver; import chip.platform.PreferencesConfigurationManager; import chip.platform.PreferencesKeyValueStoreManager; +import com.matter.tv.server.MatterCommissioningPrompter; import com.matter.tv.server.tvapp.ChannelManagerStub; import com.matter.tv.server.tvapp.Clusters; import com.matter.tv.server.tvapp.ContentLaunchManagerStub; @@ -65,6 +67,7 @@ public static MatterServant get() { } private Context context; + private Activity activity; public void init(@NonNull Context context) { @@ -140,6 +143,10 @@ public void onCommissioningComplete() { chipAppServer.startApp(); } + public void initCommissioner() { + mTvApp.initializeCommissioner(new MatterCommissioningPrompter(activity)); + } + public void restart() { chipAppServer.stopApp(); chipAppServer.startApp(); @@ -150,6 +157,10 @@ public void toggleOnOff() { mIsOn = !mIsOn; } + public void setActivity(Activity activity) { + this.activity = activity; + } + public void sendCustomCommand(String customCommand) { Log.i(MatterServant.class.getName(), customCommand); // TODO: insert logic ot send custom command here diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java index 2965ff4d6bc5c8..978ce7dfd039ef 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServantService.java @@ -21,6 +21,7 @@ public void onCreate() { super.onCreate(); // Start Matter Server MatterServant.get().init(this.getApplicationContext()); + MatterServant.get().initCommissioner(); AppPlatformService.get().init(this.getApplicationContext()); } diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index d68700655df04e..9ec4f866429765 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -40,7 +40,6 @@ shared_library("jni") { "java/AppImpl.cpp", "java/AppImpl.h", "java/AppPlatform-JNI.cpp", - "java/AppPlatform-JNI.h", "java/AppPlatformShellCommands-JNI.cpp", "java/AppPlatformShellCommands-JNI.h", "java/ChannelManager.cpp", diff --git a/examples/tv-app/android/java/AppImpl.cpp b/examples/tv-app/android/java/AppImpl.cpp index f099c624163349..9c9ed3c9d67a9f 100644 --- a/examples/tv-app/android/java/AppImpl.cpp +++ b/examples/tv-app/android/java/AppImpl.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -49,49 +48,6 @@ using namespace chip; using namespace chip::AppPlatform; #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED -class MyPincodeService : public PincodeService -{ - uint32_t FetchCommissionPincodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId) override - { - return ContentAppPlatform::GetInstance().GetPincodeFromContentApp(vendorId, productId, rotatingId); - } -}; -MyPincodeService gMyPincodeService; - -class MyPostCommissioningListener : public PostCommissioningListener -{ - void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr, - SessionHandle & sessionHandle) override - { - - ContentAppPlatform::GetInstance().ManageClientAccess( - exchangeMgr, sessionHandle, vendorId, GetDeviceCommissioner()->GetNodeId(), OnSuccessResponse, OnFailureResponse); - } - - /* Callback when command results in success */ - static void OnSuccessResponse(void * context) - { - ChipLogProgress(Controller, "OnSuccessResponse - Binding Add Successfully"); - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr) - { - cdc->PostCommissioningSucceeded(); - } - } - - /* Callback when command results in failure */ - static void OnFailureResponse(void * context, CHIP_ERROR error) - { - ChipLogProgress(Controller, "OnFailureResponse - Binding Add Failed"); - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr) - { - cdc->PostCommissioningFailed(error); - } - } -}; - -MyPostCommissioningListener gMyPostCommissioningListener; ContentAppFactoryImpl gFactory; ContentAppFactoryImpl * GetContentAppFactoryImpl() @@ -363,14 +319,36 @@ ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vend return nullptr; } -EndpointId ContentAppFactoryImpl::AddContentApp(ContentAppImpl * app, jobject contentAppEndpointManager) +EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, + uint16_t productId, const char * szApplicationVersion, jobject manager) +{ + DataVersion * dataVersionBuf = new DataVersion[ArraySize(contentAppClusters)]; + ContentAppImpl * app = + new ContentAppImpl(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, "20202021", manager); + EndpointId epId = ContentAppPlatform::GetInstance().AddContentApp( + app, &contentAppEndpoint, Span(dataVersionBuf, ArraySize(contentAppClusters)), + Span(gContentAppDeviceType)); + ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl AddContentApp endpoint returned %d. Endpoint set %d", epId, + app->GetEndpointId()); + mContentApps.push_back(app); + mDataVersions.push_back(dataVersionBuf); + return epId; +} + +EndpointId ContentAppFactoryImpl::AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, + uint16_t productId, const char * szApplicationVersion, jobject manager, + EndpointId desiredEndpointId) { - DataVersion dataVersionBuf[ArraySize(contentAppClusters)]; - EndpointId epId = ContentAppPlatform::GetInstance().AddContentApp(app, &contentAppEndpoint, Span(dataVersionBuf), - Span(gContentAppDeviceType)); + DataVersion * dataVersionBuf = new DataVersion[ArraySize(contentAppClusters)]; + ContentAppImpl * app = + new ContentAppImpl(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, "20202021", manager); + EndpointId epId = ContentAppPlatform::GetInstance().AddContentApp( + app, &contentAppEndpoint, Span(dataVersionBuf, ArraySize(contentAppClusters)), + Span(gContentAppDeviceType), desiredEndpointId); ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl AddContentApp endpoint returned %d. Endpoint set %d", epId, app->GetEndpointId()); mContentApps.push_back(app); + mDataVersions.push_back(dataVersionBuf); return epId; } @@ -383,14 +361,21 @@ EndpointId ContentAppFactoryImpl::RemoveContentApp(EndpointId epId) { ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl RemoveContentApp endpointId %d", epId); EndpointId removedEndpointID = ContentAppPlatform::GetInstance().RemoveContentApp(app); - if (removedEndpointID != 0) + // Only remove the app from the set of content apps if they were dynamically added and not part of the static list of + // apps + if (removedEndpointID != 0 && i > APP_LIBRARY_SIZE) { mContentApps.erase(mContentApps.begin() + static_cast(i)); + DataVersion * dataVersionBuf = mDataVersions.at(i - APP_LIBRARY_SIZE); + mDataVersions.erase(mDataVersions.begin() + static_cast(i - APP_LIBRARY_SIZE)); + // deallocate memory for objects that were created when adding the content app dynamically. + delete[] dataVersionBuf; + delete app; } return removedEndpointID; } } - return 0; + return kInvalidEndpointId; } void ContentAppFactoryImpl::AddAdminVendorId(uint16_t vendorId) @@ -416,7 +401,7 @@ Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId) #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED -CHIP_ERROR InitVideoPlayerPlatform(JNIMyUserPrompter * userPrompter, jobject contentAppEndpointManager) +CHIP_ERROR InitVideoPlayerPlatform(jobject contentAppEndpointManager) { #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED ContentAppPlatform::GetInstance().SetupAppPlatform(); @@ -433,21 +418,6 @@ CHIP_ERROR InitVideoPlayerPlatform(JNIMyUserPrompter * userPrompter, jobject con #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED -#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr && userPrompter != nullptr) - { - cdc->SetPincodeService(&gMyPincodeService); - cdc->SetUserPrompter(userPrompter); - cdc->SetPostCommissioningListener(&gMyPostCommissioningListener); - } - - ChipLogProgress(AppServer, "Starting commissioner"); - ReturnErrorOnFailure(InitCommissioner(CHIP_PORT + 2 + 10, CHIP_UDC_PORT)); - ChipLogProgress(AppServer, "Started commissioner"); - -#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE - // Disable last fixed endpoint, which is used as a placeholder for all of the // supported clusters so that ZAP will generated the requisite code. ChipLogDetail(DeviceLayer, "TV App: Disabling Fixed Content App Endpoints"); @@ -459,12 +429,20 @@ EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const cha const char * szApplicationVersion, jobject manager) { #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - ContentAppImpl * app = - new ContentAppImpl(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, "20202021", manager); ChipLogProgress(DeviceLayer, "AppImpl: AddContentApp vendorId=%d applicationName=%s ", vendorId, szApplicationName); - return gFactory.AddContentApp(app, manager); + return gFactory.AddContentApp(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, manager); +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + return kInvalidEndpointId; +} + +EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, + const char * szApplicationVersion, EndpointId endpointId, jobject manager) +{ +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ChipLogProgress(DeviceLayer, "AppImpl: AddContentApp vendorId=%d applicationName=%s ", vendorId, szApplicationName); + return gFactory.AddContentApp(szVendorName, vendorId, szApplicationName, productId, szApplicationVersion, manager, endpointId); #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - return 0; + return kInvalidEndpointId; } EndpointId RemoveContentApp(EndpointId epId) @@ -473,5 +451,5 @@ EndpointId RemoveContentApp(EndpointId epId) ChipLogProgress(DeviceLayer, "AppImpl: RemoveContentApp endpointId=%d ", epId); return gFactory.RemoveContentApp(epId); #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - return 0; + return kInvalidEndpointId; } diff --git a/examples/tv-app/android/java/AppImpl.h b/examples/tv-app/android/java/AppImpl.h index 2ead65e2625553..d49ff78f622c54 100644 --- a/examples/tv-app/android/java/AppImpl.h +++ b/examples/tv-app/android/java/AppImpl.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -52,9 +53,11 @@ #include #include -CHIP_ERROR InitVideoPlayerPlatform(JNIMyUserPrompter * userPrompter, jobject contentAppEndpointManager); +CHIP_ERROR InitVideoPlayerPlatform(jobject contentAppEndpointManager); EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, const char * szApplicationVersion, jobject manager); +EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, + const char * szApplicationVersion, EndpointId endpointId, jobject manager); EndpointId RemoveContentApp(EndpointId epId); #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED @@ -130,7 +133,11 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory // Lookup ContentApp for this catalog id / app id and load it ContentApp * LoadContentApp(const CatalogVendorApp & vendorApp) override; - EndpointId AddContentApp(ContentAppImpl * app, jobject contentAppEndpointManager); + EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, + const char * szApplicationVersion, jobject manager); + + EndpointId AddContentApp(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, + const char * szApplicationVersion, jobject manager, EndpointId desiredEndpointId); EndpointId RemoveContentApp(EndpointId epId); @@ -156,6 +163,7 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory new ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3", "20202021", nullptr), new ContentAppImpl("TestSuiteVendor", 1111, "applicationId", 22, "v2", "20202021", nullptr) }; + std::vector mDataVersions{}; std::vector mAdminVendorIds{}; }; diff --git a/examples/tv-app/android/java/AppPlatform-JNI.cpp b/examples/tv-app/android/java/AppPlatform-JNI.cpp index 5e8c84a79c3740..06bf01133e8f5d 100644 --- a/examples/tv-app/android/java/AppPlatform-JNI.cpp +++ b/examples/tv-app/android/java/AppPlatform-JNI.cpp @@ -16,7 +16,6 @@ * */ -#include "AppPlatform-JNI.h" #include "AppImpl.h" #include "MyUserPrompter-JNI.h" @@ -32,15 +31,18 @@ using namespace chip::app; using namespace chip::AppPlatform; using namespace chip::Credentials; +/* + * This file provides the native implementation of methods of the + * com.matter.tv.server.tvapp.AppPlatform class. + */ + #define JNI_METHOD(RETURN, METHOD_NAME) \ extern "C" JNIEXPORT RETURN JNICALL Java_com_matter_tv_server_tvapp_AppPlatform_##METHOD_NAME -AppPlatformJNI AppPlatformJNI::sInstance; - -JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app, jobject prompter, jobject contentAppEndpointManager) +JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app, jobject contentAppEndpointManager) { chip::DeviceLayer::StackLock lock; - InitVideoPlayerPlatform(new JNIMyUserPrompter(prompter), contentAppEndpointManager); + InitVideoPlayerPlatform(contentAppEndpointManager); } JNI_METHOD(jint, addContentApp) @@ -57,6 +59,21 @@ JNI_METHOD(jint, addContentApp) return static_cast(epId); } +JNI_METHOD(jint, addContentAppAtEndpoint) +(JNIEnv *, jobject, jstring vendorName, jint vendorId, jstring appName, jint productId, jstring appVersion, jint endpointId, + jobject manager) +{ + chip::DeviceLayer::StackLock lock; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + JniUtfString vName(env, vendorName); + JniUtfString aName(env, appName); + JniUtfString aVersion(env, appVersion); + EndpointId epId = AddContentApp(vName.c_str(), static_cast(vendorId), aName.c_str(), static_cast(productId), + aVersion.c_str(), static_cast(endpointId), manager); + return static_cast(epId); +} + JNI_METHOD(jint, removeContentApp) (JNIEnv *, jobject, jint endpointId) { diff --git a/examples/tv-app/android/java/AppPlatform-JNI.h b/examples/tv-app/android/java/AppPlatform-JNI.h deleted file mode 100644 index 3a6e6fa28233fd..00000000000000 --- a/examples/tv-app/android/java/AppPlatform-JNI.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * - * Copyright (c) 2021 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 - -class AppPlatformJNI -{ - -private: - friend AppPlatformJNI & AppPlatformJNIMgr(); - - static AppPlatformJNI sInstance; -}; - -inline class AppPlatformJNI & AppPlatformJNIMgr() -{ - return AppPlatformJNI::sInstance; -} diff --git a/examples/tv-app/android/java/ContentAppAttributeDelegate.h b/examples/tv-app/android/java/ContentAppAttributeDelegate.h index 592971de5ee60a..b12312068fd132 100644 --- a/examples/tv-app/android/java/ContentAppAttributeDelegate.h +++ b/examples/tv-app/android/java/ContentAppAttributeDelegate.h @@ -44,6 +44,13 @@ class ContentAppAttributeDelegate InitializeJNIObjects(manager); } + ~ContentAppAttributeDelegate() + { + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for ContentAppEndpointManager")); + env->DeleteGlobalRef(mContentAppEndpointManager); + } + const char * Read(const chip::app::ConcreteReadAttributePath & aPath); private: diff --git a/examples/tv-app/android/java/ContentAppCommandDelegate.h b/examples/tv-app/android/java/ContentAppCommandDelegate.h index bc607e6254d651..23a7f8e1b82180 100644 --- a/examples/tv-app/android/java/ContentAppCommandDelegate.h +++ b/examples/tv-app/android/java/ContentAppCommandDelegate.h @@ -57,6 +57,13 @@ class ContentAppCommandDelegate : public CommandHandlerInterface InitializeJNIObjects(manager); }; + ~ContentAppCommandDelegate() + { + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for ContentAppEndpointManager")); + env->DeleteGlobalRef(mContentAppEndpointManager); + } + void InvokeCommand(CommandHandlerInterface::HandlerContext & handlerContext) override; private: diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index d2d0897a57e4d5..c59893106a8554 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -18,6 +18,7 @@ #include "TvApp-JNI.h" #include "ChannelManager.h" +#include "CommissionerMain.h" #include "ContentLauncherManager.h" #include "DeviceCallbacks.h" #include "JNIDACProvider.h" @@ -30,6 +31,7 @@ #include "OnOffManager.h" #include "WakeOnLanManager.h" #include "credentials/DeviceAttestationCredsProvider.h" +#include #include #include #include @@ -42,12 +44,12 @@ using namespace chip; using namespace chip::app; +using namespace chip::AppPlatform; using namespace chip::Credentials; #define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_com_matter_tv_server_tvapp_TvApp_##METHOD_NAME TvAppJNI TvAppJNI::sInstance; -JNIMyUserPrompter * userPrompter = nullptr; void TvAppJNI::InitializeWithObjects(jobject app) { @@ -98,6 +100,11 @@ JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app) TvAppJNIMgr().InitializeWithObjects(app); } +JNI_METHOD(void, initializeCommissioner)(JNIEnv *, jobject app, jobject prompter) +{ + TvAppJNIMgr().InitializeCommissioner(new JNIMyUserPrompter(prompter)); +} + JNI_METHOD(void, setKeypadInputManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { KeypadInputManager::NewManager(endpoint, manager); @@ -133,11 +140,6 @@ JNI_METHOD(void, setChannelManager)(JNIEnv *, jobject, jint endpoint, jobject ma ChannelManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setUserPrompter)(JNIEnv *, jobject, jobject prompter) -{ - userPrompter = new JNIMyUserPrompter(prompter); -} - JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) { if (!chip::Credentials::IsDeviceAttestationCredentialsProviderSet()) @@ -183,3 +185,68 @@ JNI_METHOD(void, setChipDeviceEventProvider)(JNIEnv *, jobject, jobject provider { DeviceCallbacks::NewManager(provider); } + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED +class MyPincodeService : public PincodeService +{ + uint32_t FetchCommissionPincodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId) override + { + return ContentAppPlatform::GetInstance().GetPincodeFromContentApp(vendorId, productId, rotatingId); + } +}; +MyPincodeService gMyPincodeService; + +class MyPostCommissioningListener : public PostCommissioningListener +{ + void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr, + SessionHandle & sessionHandle) override + { + + ContentAppPlatform::GetInstance().ManageClientAccess( + exchangeMgr, sessionHandle, vendorId, GetDeviceCommissioner()->GetNodeId(), OnSuccessResponse, OnFailureResponse); + } + + /* Callback when command results in success */ + static void OnSuccessResponse(void * context) + { + ChipLogProgress(Controller, "OnSuccessResponse - Binding Add Successfully"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->PostCommissioningSucceeded(); + } + } + + /* Callback when command results in failure */ + static void OnFailureResponse(void * context, CHIP_ERROR error) + { + ChipLogProgress(Controller, "OnFailureResponse - Binding Add Failed"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->PostCommissioningFailed(error); + } + } +}; + +MyPostCommissioningListener gMyPostCommissioningListener; + +void TvAppJNI::InitializeCommissioner(JNIMyUserPrompter * userPrompter) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + chip::DeviceLayer::StackLock lock; + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr && userPrompter != nullptr) + { + cdc->SetPincodeService(&gMyPincodeService); + cdc->SetUserPrompter(userPrompter); + cdc->SetPostCommissioningListener(&gMyPostCommissioningListener); + } + + ChipLogProgress(AppServer, "Starting commissioner"); + InitCommissioner(CHIP_PORT + 2 + 10, CHIP_UDC_PORT); + ChipLogProgress(AppServer, "Started commissioner"); + +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE +} +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED diff --git a/examples/tv-app/android/java/TvApp-JNI.h b/examples/tv-app/android/java/TvApp-JNI.h index 36033727a42817..4f710299a7be21 100644 --- a/examples/tv-app/android/java/TvApp-JNI.h +++ b/examples/tv-app/android/java/TvApp-JNI.h @@ -18,6 +18,7 @@ #pragma once +#include "MyUserPrompter-JNI.h" #include class TvAppJNI @@ -25,6 +26,7 @@ class TvAppJNI public: void InitializeWithObjects(jobject app); void PostClusterInit(int clusterId, int endpoint); + void InitializeCommissioner(JNIMyUserPrompter * userPrompter); private: friend TvAppJNI & TvAppJNIMgr(); diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java index ca6dbd0c74c729..74bc5d14f2f9d5 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/AppPlatform.java @@ -17,15 +17,20 @@ */ package com.matter.tv.server.tvapp; +/* + * This class is provides the JNI interface to the linux layer of the ContentAppPlatform + */ public class AppPlatform { private static final String TAG = "AppPlatform"; - public AppPlatform(UserPrompter userPrompter, ContentAppEndpointManager manager) { - nativeInit(userPrompter, manager); + public AppPlatform(ContentAppEndpointManager manager) { + nativeInit(manager); } - public native void nativeInit(UserPrompter userPrompter, ContentAppEndpointManager manager); + // Initializes the ContentAppPlatform on startup + public native void nativeInit(ContentAppEndpointManager manager); + // Method to add a content app as a new endpoint public native int addContentApp( String vendorName, int vendorId, @@ -34,6 +39,17 @@ public native int addContentApp( String appVersion, ContentAppEndpointManager manager); + // Method to add a content app at an existing endpoint after restart of the matter server + public native int addContentAppAtEndpoint( + String vendorName, + int vendorId, + String appName, + int productId, + String appVersion, + int endpointId, + ContentAppEndpointManager manager); + + // Method to remove content app as endpoint (happens when the app is uninstalled) public native int removeContentApp(int endpointId); static { diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java index ec45db1c8d747c..92c41fdebc7e6f 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java @@ -37,6 +37,8 @@ private void postClusterInit(int clusterId, int endpoint) { public native void nativeInit(); + public native void initializeCommissioner(UserPrompter userPrompter); + // called before Matter server is inited public native void preServerInit();