diff --git a/examples/tv-app/android/App/platform-app/src/main/AndroidManifest.xml b/examples/tv-app/android/App/platform-app/src/main/AndroidManifest.xml index b6e00cd75d0365..476faa2030c7a2 100644 --- a/examples/tv-app/android/App/platform-app/src/main/AndroidManifest.xml +++ b/examples/tv-app/android/App/platform-app/src/main/AndroidManifest.xml @@ -26,6 +26,9 @@ tools:ignore="QueryAllPackagesPermission" /> + + + tasks = activityManager.getRunningTasks(1); + if (tasks != null && !tasks.isEmpty()) { + ActivityManager.RunningTaskInfo taskInfo = tasks.get(0); + String packageName = + taskInfo.topActivity != null ? taskInfo.topActivity.getPackageName() : ""; + return packageName.equals(contentAppPackageName); + } + return false; + } + public String sendCommand(int endpointId, long clusterId, long commandId, String commandPayload) { Log.d(TAG, "Received a command for endpointId " + endpointId + ". Message " + commandPayload); @@ -26,6 +55,17 @@ public String sendCommand(int endpointId, long clusterId, long commandId, String ContentAppDiscoveryService.getReceiverInstance().getDiscoveredContentApps().values(), endpointId); if (discoveredApp != null) { + // Intercept NavigateTarget and LaunchContent commands and launch content app if necessary + if (isForegroundCommand(clusterId, commandId)) { + // Check if contentapp main/launch activity is already in foreground before launching. + if (!isAppInForeground(discoveredApp.getAppName())) { + Intent launchIntent = + context.getPackageManager().getLaunchIntentForPackage(discoveredApp.getAppName()); + if (launchIntent != null) { + context.startActivity(launchIntent); + } + } + } Log.d(TAG, "Sending a command for endpointId " + endpointId + ". Message " + commandPayload); return ContentAppAgentService.sendCommand( context, discoveredApp.getAppName(), clusterId, commandId, commandPayload); diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/model/ContentApp.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/model/ContentApp.java index e30a75a00d98b2..0cd12b404d6fcf 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/model/ContentApp.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/model/ContentApp.java @@ -25,6 +25,7 @@ public ContentApp( this.vendorId = vendorId; this.productId = productId; this.version = version; + this.supportedClusters = Collections.EMPTY_SET; } public ContentApp( @@ -67,9 +68,7 @@ public void setEndpointId(int endpoint) { } public Set getSupportedClusters() { - return supportedClusters != null - ? Collections.unmodifiableSet(supportedClusters) - : Collections.EMPTY_SET; + return Collections.unmodifiableSet(supportedClusters); } public String getVersion() { diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/EndpointsDataStore.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/EndpointsDataStore.java index f587905fb09145..227ea9326be538 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/EndpointsDataStore.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/EndpointsDataStore.java @@ -4,13 +4,18 @@ import android.content.SharedPreferences; import android.util.JsonReader; import android.util.JsonWriter; +import com.matter.tv.app.api.SupportedCluster; import com.matter.tv.server.model.ContentApp; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; public class EndpointsDataStore { @@ -21,6 +26,11 @@ public class EndpointsDataStore { private static final String KEY_PRODUCTID = "PID"; private static final String KEY_VERSION = "VER"; private static final String KEY_ENDPOINTID = "EPID"; + private static final String KEY_SUPPORTED_CLUSTERS = "supportedClusters"; + private static final String KEY_CLUSTER_IDENTIFIER = "clusterIdentifier"; + private static final String KEY_FEATURES = "features"; + private static final String KEY_OPTIONAL_COMMAND_IDENTIFIERS = "optionalCommandIdentifiers"; + private static final String KEY_OPTIONAL_ATTRIBUTES_IDENTIFIERS = "optionalAttributesIdentifiers"; private static EndpointsDataStore instance; private final SharedPreferences discoveredEndpoints; Map persistedContentApps = new HashMap<>(); @@ -57,19 +67,20 @@ private String serializeContentApp(ContentApp app) { StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); try { - jsonWriter - .beginObject() - .name(KEY_VENDORID) - .value(app.getVendorId()) - .name(KEY_VENDORNAME) - .value(app.getVendorName()) - .name(KEY_PRODUCTID) - .value(app.getProductId()) - .name(KEY_VERSION) - .value(app.getVersion()) - .name(KEY_ENDPOINTID) - .value(app.getEndpointId()) - .endObject(); + jsonWriter.beginObject(); + jsonWriter.name(KEY_VENDORID); + jsonWriter.value(app.getVendorId()); + jsonWriter.name(KEY_VENDORNAME); + jsonWriter.value(app.getVendorName()); + jsonWriter.name(KEY_PRODUCTID); + jsonWriter.value(app.getProductId()); + jsonWriter.name(KEY_VERSION); + jsonWriter.value(app.getVersion()); + jsonWriter.name(KEY_ENDPOINTID); + jsonWriter.value(app.getEndpointId()); + jsonWriter.name(KEY_SUPPORTED_CLUSTERS); + serializeSupportedClusters(jsonWriter, app.getSupportedClusters()); + jsonWriter.endObject(); jsonWriter.flush(); jsonWriter.close(); } catch (IOException e) { @@ -88,6 +99,7 @@ private ContentApp deserializeContentApp(String appName, String appMetadata) { int vendorId = 0; int productId = 0; int endpoint = ContentApp.INVALID_ENDPOINTID; + Set supportedClusters = new HashSet<>(); while (jsonReader.hasNext()) { String name = jsonReader.nextName(); switch (name) { @@ -106,9 +118,12 @@ private ContentApp deserializeContentApp(String appName, String appMetadata) { case KEY_ENDPOINTID: endpoint = jsonReader.nextInt(); break; + case KEY_SUPPORTED_CLUSTERS: + supportedClusters = deserializeSupportedClusters(jsonReader); + break; } } - app = new ContentApp(appName, vendorName, vendorId, productId, version); + app = new ContentApp(appName, vendorName, vendorId, productId, version, supportedClusters); jsonReader.endObject(); jsonReader.close(); } catch (IOException e) { @@ -116,4 +131,86 @@ private ContentApp deserializeContentApp(String appName, String appMetadata) { } return app; } + + private void serializeSupportedClusters( + JsonWriter jsonWriter, Set supportedClusters) throws IOException { + if (supportedClusters != null) { + jsonWriter.beginArray(); + for (SupportedCluster supportedCluster : supportedClusters) { + if (supportedCluster != null) { + serializeSupportedCluster(jsonWriter, supportedCluster); + } + } + jsonWriter.endArray(); + } + } + + private Set deserializeSupportedClusters(JsonReader jsonReader) + throws IOException { + Set supportedClusters = new HashSet<>(); + jsonReader.beginArray(); + while (jsonReader.hasNext()) { + supportedClusters.add(deserializeSupportedCluster(jsonReader)); + } + jsonReader.endArray(); + return supportedClusters; + } + + private void serializeSupportedCluster(JsonWriter jsonWriter, SupportedCluster supportedCluster) + throws IOException { + jsonWriter.beginObject(); + jsonWriter.name(KEY_CLUSTER_IDENTIFIER); + jsonWriter.value(supportedCluster.clusterIdentifier); + jsonWriter.name(KEY_FEATURES); + jsonWriter.value(supportedCluster.features); + jsonWriter.name(KEY_OPTIONAL_COMMAND_IDENTIFIERS); + serializeIntArray(jsonWriter, supportedCluster.optionalCommandIdentifiers); + jsonWriter.name(KEY_OPTIONAL_ATTRIBUTES_IDENTIFIERS); + serializeIntArray(jsonWriter, supportedCluster.optionalAttributesIdentifiers); + jsonWriter.endObject(); + } + + private SupportedCluster deserializeSupportedCluster(JsonReader jsonReader) throws IOException { + SupportedCluster supportedCluster = new SupportedCluster(); + jsonReader.beginObject(); + while (jsonReader.hasNext()) { + String name = jsonReader.nextName(); + switch (name) { + case KEY_CLUSTER_IDENTIFIER: + supportedCluster.clusterIdentifier = jsonReader.nextInt(); + break; + case KEY_FEATURES: + supportedCluster.features = jsonReader.nextInt(); + break; + case KEY_OPTIONAL_COMMAND_IDENTIFIERS: + supportedCluster.optionalCommandIdentifiers = deserializeIntArray(jsonReader); + break; + case KEY_OPTIONAL_ATTRIBUTES_IDENTIFIERS: + supportedCluster.optionalAttributesIdentifiers = deserializeIntArray(jsonReader); + break; + } + } + jsonReader.endObject(); + return supportedCluster; + } + + private void serializeIntArray(JsonWriter jsonWriter, int[] array) throws IOException { + jsonWriter.beginArray(); + if (array != null) { + for (int value : array) { + jsonWriter.value(value); + } + } + jsonWriter.endArray(); + } + + private int[] deserializeIntArray(JsonReader jsonReader) throws IOException { + List dynamicArray = new ArrayList<>(); + jsonReader.beginArray(); + while (jsonReader.hasNext()) { + dynamicArray.add(jsonReader.nextInt()); + } + jsonReader.endArray(); + return dynamicArray.stream().mapToInt(Integer::intValue).toArray(); + } }