| /* |
| * Copyright (c) 2021-2022 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.tv.server.service; |
| |
| import android.app.Activity; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.util.Log; |
| import androidx.annotation.NonNull; |
| 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 com.matter.tv.server.utils.EndpointsDataStore; |
| 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 AppPlatform mAppPlatform; |
| private BroadcastReceiver mBroadcastReceiver; |
| private EndpointsDataStore endpointsDataStore; |
| |
| private AppPlatformService() {} |
| |
| public void reportAttributeChange(int endpointId, int clusterId, int attributeId) { |
| mAppPlatform.reportAttributeChange(endpointId, clusterId, attributeId); |
| } |
| |
| private static class SingletonHolder { |
| static AppPlatformService instance = new AppPlatformService(); |
| } |
| |
| public static AppPlatformService get() { |
| return SingletonHolder.instance; |
| } |
| |
| private Context context; |
| private Activity activity; |
| |
| public void init(@NonNull Context context) { |
| this.context = context; |
| ContentAppDiscoveryService.getReceiverInstance().registerSelf(context.getApplicationContext()); |
| mAppPlatform = new AppPlatform(new ContentAppEndpointManagerImpl(context)); |
| endpointsDataStore = EndpointsDataStore.getInstance(context); |
| initializeContentAppEndpoints(); |
| registerContentAppUpdatesReceiver(); |
| } |
| |
| public void addSelfVendorAsAdmin() { |
| mAppPlatform.addSelfVendorAsAdmin(); |
| } |
| |
| private void initializeContentAppEndpoints() { |
| |
| // Read the metadada of previously discovered endpoints. |
| Map<String, ContentApp> previouslyPersistedEndpoints = |
| new HashMap((Map<String, ContentApp>) endpointsDataStore.getAllPersistedContentApps()); |
| |
| // Get the list of currently discovered content apps. |
| Map<String, ContentApp> discoveredContentApps = |
| new HashMap<>(ContentAppDiscoveryService.getReceiverInstance().getDiscoveredContentApps()); |
| |
| // Iterate through the previously discovered endpoints |
| for (ContentApp persistedContentApp : previouslyPersistedEndpoints.values()) { |
| ContentApp discoveredContentApp = |
| discoveredContentApps.remove(persistedContentApp.getAppName()); |
| if (discoveredContentApp != null) { |
| // If the content app for the persisted endpoint is present in currently discovered list, |
| // register endpoint with updated metadata and update the metadata in the persisted |
| // endpoints. |
| discoveredContentApp.setEndpointId(persistedContentApp.getEndpointId()); |
| addContentApp(discoveredContentApp); |
| } else { |
| // If the content app for the persisted endpoint is not present register the endpoint with |
| // previously persisted data. |
| addContentApp(persistedContentApp); |
| } |
| } |
| |
| // For newly discovered content apps register new endpoints and persist the metadata for future |
| // use |
| for (ContentApp discoveredContentApp : discoveredContentApps.values()) { |
| addContentApp(discoveredContentApp); |
| } |
| } |
| |
| private void registerContentAppUpdatesReceiver() { |
| mBroadcastReceiver = |
| new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| String action = intent.getAction(); |
| String packageName = |
| intent.getStringExtra( |
| ContentAppDiscoveryService.DISCOVERY_APPAGENT_EXTRA_PACKAGENAME); |
| if (action.equals(ContentAppDiscoveryService.DISCOVERY_APPAGENT_ACTION_ADD)) { |
| ContentApp app = |
| ContentAppDiscoveryService.getReceiverInstance() |
| .getDiscoveredContentApps() |
| .get(packageName); |
| // if this app was already added as endpoint remove and add so that the app metadata |
| // stored by the content app platform is also updated |
| ContentApp persistedContentApp = |
| endpointsDataStore.getAllPersistedContentApps().get(app.getAppName()); |
| if (persistedContentApp != null) { |
| mAppPlatform.removeContentApp(persistedContentApp.getEndpointId()); |
| app.setEndpointId(persistedContentApp.getEndpointId()); |
| } |
| addContentApp(app); |
| // } else if |
| // (action.equals(ContentAppDiscoveryService.DISCOVERY_APPAGENT_ACTION_REMOVE)) { |
| // int endpointId = |
| // intent.getIntExtra( |
| // |
| // ContentAppDiscoveryService.DISCOVERY_APPAGENT_EXTRA_ENDPOINTID, -1); |
| // if (endpointId != -1) { |
| // removeContentApp(endpointId, packageName); |
| // } |
| } |
| } |
| }; |
| context.registerReceiver( |
| mBroadcastReceiver, |
| new IntentFilter(ContentAppDiscoveryService.DISCOVERY_APPAGENT_ACTION_ADD)); |
| context.registerReceiver( |
| mBroadcastReceiver, |
| new IntentFilter(ContentAppDiscoveryService.DISCOVERY_APPAGENT_ACTION_REMOVE)); |
| } |
| |
| public void setActivity(Activity activity) { |
| this.activity = activity; |
| } |
| |
| public void addContentApp(ContentApp app) { |
| int retEndpointId = -1; |
| int desiredEndpointId = app.getEndpointId(); |
| if (desiredEndpointId > 0) { |
| retEndpointId = |
| mAppPlatform.addContentAppAtEndpoint( |
| app.getVendorName(), |
| app.getVendorId(), |
| app.getAppName(), |
| app.getProductId(), |
| app.getVersion(), |
| desiredEndpointId, |
| new ContentAppEndpointManagerImpl(context)); |
| } else { |
| retEndpointId = |
| mAppPlatform.addContentApp( |
| app.getVendorName(), |
| app.getVendorId(), |
| app.getAppName(), |
| app.getProductId(), |
| app.getVersion(), |
| new ContentAppEndpointManagerImpl(context)); |
| } |
| if (retEndpointId > 0) { |
| app.setEndpointId(retEndpointId); |
| endpointsDataStore.persistContentAppEndpoint(app); |
| } else { |
| Log.e(TAG, "Could not add content app as endpoint. App Name " + app.getAppName()); |
| } |
| } |
| } |