Skip to content

Commit 8f1fe4f

Browse files
lazarkovrestyled-commits
authored andcommitted
Re-Implement App Install flow (project-chip#34141)
* Add install things * Update the code * Restyled by whitespace * Restyled by google-java-format * Restyled by clang-format * Restyled by gn * Revert the unecessary changes * Remove uncessary files * Update comment * Restyled by google-java-format * Fix get catalog list * Added option to log the content apps * Restyled by google-java-format * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent a7416a6 commit 8f1fe4f

File tree

32 files changed

+878
-121
lines changed

32 files changed

+878
-121
lines changed

examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter

+3
Original file line numberDiff line numberDiff line change
@@ -5583,6 +5583,9 @@ cluster ApplicationLauncher = 1292 {
55835583
kSuccess = 0;
55845584
kAppNotAvailable = 1;
55855585
kSystemBusy = 2;
5586+
kPendingUserApproval = 3;
5587+
kDownloading = 4;
5588+
kInstalling = 5;
55865589
}
55875590

55885591
bitmap Feature : bitmap32 {

examples/placeholder/linux/apps/app1/config.matter

+6
Original file line numberDiff line numberDiff line change
@@ -8236,6 +8236,9 @@ cluster ApplicationLauncher = 1292 {
82368236
kSuccess = 0;
82378237
kAppNotAvailable = 1;
82388238
kSystemBusy = 2;
8239+
kPendingUserApproval = 3;
8240+
kDownloading = 4;
8241+
kInstalling = 5;
82398242
}
82408243

82418244
bitmap Feature : bitmap32 {
@@ -8295,6 +8298,9 @@ cluster ApplicationLauncher = 1292 {
82958298
kSuccess = 0;
82968299
kAppNotAvailable = 1;
82978300
kSystemBusy = 2;
8301+
kPendingUserApproval = 3;
8302+
kDownloading = 4;
8303+
kInstalling = 5;
82988304
}
82998305

83008306
bitmap Feature : bitmap32 {

examples/placeholder/linux/apps/app2/config.matter

+6
Original file line numberDiff line numberDiff line change
@@ -8193,6 +8193,9 @@ cluster ApplicationLauncher = 1292 {
81938193
kSuccess = 0;
81948194
kAppNotAvailable = 1;
81958195
kSystemBusy = 2;
8196+
kPendingUserApproval = 3;
8197+
kDownloading = 4;
8198+
kInstalling = 5;
81968199
}
81978200

81988201
bitmap Feature : bitmap32 {
@@ -8252,6 +8255,9 @@ cluster ApplicationLauncher = 1292 {
82528255
kSuccess = 0;
82538256
kAppNotAvailable = 1;
82548257
kSystemBusy = 2;
8258+
kPendingUserApproval = 3;
8259+
kDownloading = 4;
8260+
kInstalling = 5;
82558261
}
82568262

82578263
bitmap Feature : bitmap32 {

examples/tv-app/android/App/platform-app/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ dependencies {
7272
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
7373
implementation 'com.google.zxing:core:3.3.0'
7474
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
75-
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package com.matter.tv.server.handlers;
2+
3+
import android.content.Context;
4+
import android.content.pm.PackageManager;
5+
import android.util.Log;
6+
import androidx.lifecycle.LiveData;
7+
import androidx.lifecycle.Observer;
8+
import com.matter.tv.server.tvapp.Application;
9+
import com.matter.tv.server.tvapp.ApplicationLauncherManager;
10+
import com.matter.tv.server.tvapp.LauncherResponse;
11+
import com.matter.tv.server.utils.EndpointsDataStore;
12+
import com.matter.tv.server.utils.InstallationObserver;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
import java.util.Objects;
16+
17+
public class ApplicationLauncherManagerImpl implements ApplicationLauncherManager {
18+
19+
private static final String TAG = "ApplicationLauncherService";
20+
21+
private volatile boolean registered = false;
22+
private PackageManager packageManager;
23+
private EndpointsDataStore endpointsDataStore;
24+
25+
/** Hash Map of packageName & Install Status */
26+
private Map<String, InstallationObserver.InstallStatus> lastReceivedInstallationStatus =
27+
new HashMap<>();
28+
29+
private LiveData<InstallationObserver.InstallState> installStateLiveData;
30+
31+
public ApplicationLauncherManagerImpl(Context context) {
32+
packageManager = context.getPackageManager();
33+
endpointsDataStore = EndpointsDataStore.getInstance(context);
34+
registerSelf(context);
35+
}
36+
37+
private final Observer<InstallationObserver.InstallState> installStateObserver =
38+
state -> {
39+
lastReceivedInstallationStatus.put(state.getAppPackageName(), state.getStatus());
40+
switch (state.getStatus()) {
41+
case IN_PROGRESS:
42+
// Installation is in progress
43+
Log.d(TAG, "Installation of " + state.getAppPackageName() + " in progress");
44+
break;
45+
case SUCCEEDED:
46+
// Installation succeeded
47+
Log.d(TAG, "Installation of " + state.getAppPackageName() + " succeeded");
48+
break;
49+
case FAILED:
50+
// Installation failed
51+
Log.d(TAG, "Installation of " + state.getAppPackageName() + " failed");
52+
break;
53+
}
54+
};
55+
56+
private void stopObservingInstallations() {
57+
if (installStateLiveData != null) {
58+
Log.d("InstallationObserver", "Stopped Observing");
59+
installStateLiveData.removeObserver(installStateObserver);
60+
}
61+
}
62+
63+
public void unregister() {
64+
stopObservingInstallations();
65+
}
66+
67+
private void registerSelf(Context context) {
68+
if (registered) {
69+
Log.i(TAG, "Package update receiver for matter already registered");
70+
return;
71+
} else {
72+
registered = true;
73+
}
74+
Log.i(TAG, "Registered the matter package updates receiver");
75+
76+
installStateLiveData = InstallationObserver.installationStates(context);
77+
installStateLiveData.observeForever(installStateObserver);
78+
Log.d(TAG, "Started Observing package installations");
79+
}
80+
81+
@Override
82+
public int[] getCatalogList() {
83+
Log.i(TAG, "Get Catalog List");
84+
return new int[] {123, 456, 89010};
85+
}
86+
87+
@Override
88+
public LauncherResponse launchApp(Application app, String data) {
89+
Log.i(
90+
TAG,
91+
"Launch app id:" + app.applicationId + " cid:" + app.catalogVendorId + " data:" + data);
92+
93+
int status = 0;
94+
String responseData = "";
95+
96+
// Installed Apps that have declared CSA product id & vendor id in their manifes
97+
boolean matterEnabledAppdIsInstalled =
98+
endpointsDataStore.getAllPersistedContentApps().containsKey(app.applicationId);
99+
// Installed App
100+
boolean appIsInstalled =
101+
InstallationObserver.getInstalledPackages(packageManager).contains(app.applicationId);
102+
boolean isAppInstalling =
103+
Objects.equals(
104+
lastReceivedInstallationStatus.get(app.applicationId),
105+
InstallationObserver.InstallStatus.IN_PROGRESS);
106+
boolean appInstallFailed =
107+
Objects.equals(
108+
lastReceivedInstallationStatus.get(app.applicationId),
109+
InstallationObserver.InstallStatus.FAILED);
110+
111+
// This use-case can happen if app is installed
112+
// but it does not support Matter
113+
if (!matterEnabledAppdIsInstalled && appIsInstalled) {
114+
Log.i(
115+
TAG,
116+
"Matter enabled app is not installed, but app is installed. Launching app's install page");
117+
status = LauncherResponse.STATUS_PENDING_USER_APPROVAL;
118+
responseData = "App is installed, try updating";
119+
120+
//
121+
// Add code to launch App Install Page
122+
//
123+
124+
} else if (!matterEnabledAppdIsInstalled && !appIsInstalled) {
125+
Log.i(
126+
TAG,
127+
"Matter enabled app is not installed and app is not installed. Launching app's install page");
128+
if (isAppInstalling) {
129+
Log.i(TAG, "App is installing");
130+
status = LauncherResponse.STATUS_INSTALLING;
131+
} else {
132+
status = LauncherResponse.STATUS_PENDING_USER_APPROVAL;
133+
if (appInstallFailed) {
134+
responseData = "App install failed. Try again";
135+
}
136+
}
137+
138+
//
139+
// Add code to launch App Install Page
140+
//
141+
142+
} else if (matterEnabledAppdIsInstalled && appIsInstalled) {
143+
Log.i(TAG, "Launching the app");
144+
status = LauncherResponse.STATUS_SUCCESS;
145+
146+
//
147+
// Add code to launch an app
148+
//
149+
}
150+
151+
return new LauncherResponse(status, responseData);
152+
}
153+
154+
@Override
155+
public LauncherResponse stopApp(Application app) {
156+
Log.i(TAG, "Stop app id:" + app.applicationId + " cid:" + app.catalogVendorId);
157+
return new LauncherResponse(LauncherResponse.STATUS_SUCCESS, "");
158+
}
159+
160+
@Override
161+
public LauncherResponse hideApp(Application app) {
162+
Log.i(TAG, "Hide app id:" + app.applicationId + " cid:" + app.catalogVendorId);
163+
return new LauncherResponse(LauncherResponse.STATUS_SUCCESS, "");
164+
}
165+
}

examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java

+12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import chip.platform.PreferencesConfigurationManager;
3131
import chip.platform.PreferencesKeyValueStoreManager;
3232
import com.matter.tv.server.MatterCommissioningPrompter;
33+
import com.matter.tv.server.handlers.ApplicationLauncherManagerImpl;
34+
import com.matter.tv.server.tvapp.ApplicationLauncherManager;
3335
import com.matter.tv.server.tvapp.ChannelManagerStub;
3436
import com.matter.tv.server.tvapp.Clusters;
3537
import com.matter.tv.server.tvapp.ContentLaunchManagerStub;
@@ -55,6 +57,8 @@ public class MatterServant {
5557
private boolean mIsOn = true;
5658
private int mOnOffEndpoint;
5759
private int mLevelEndpoint;
60+
private MatterCommissioningPrompter matterCommissioningPrompter;
61+
private ApplicationLauncherManager applicationLauncherManager;
5862

5963
private MatterServant() {}
6064

@@ -72,17 +76,25 @@ public void init(@NonNull Context context) {
7276

7377
this.context = context;
7478

79+
this.applicationLauncherManager = new ApplicationLauncherManagerImpl(context);
80+
7581
// The order is important, must
7682
// first new TvApp to load dynamic library
7783
// then chipPlatform to prepare platform
7884
// then TvApp.preServerInit to initialize any server configuration
7985
// then start ChipAppServer
8086
// then TvApp.postServerInit to init app platform
87+
//
88+
// TODO: Move all of the bellow KeypadInputManager...LevelManagerStub to
89+
// PlatformAppCommandDelegate
90+
// There is no need for this complicated logic
8191
mTvApp =
8292
new TvApp(
8393
(app, clusterId, endpoint) -> {
8494
if (clusterId == Clusters.ClusterId_KeypadInput) {
8595
app.setKeypadInputManager(endpoint, new KeypadInputManagerStub(endpoint));
96+
} else if (clusterId == Clusters.ClusterId_ApplicationLauncher) {
97+
app.setApplicationLauncherManager(endpoint, applicationLauncherManager);
8698
} else if (clusterId == Clusters.ClusterId_WakeOnLan) {
8799
app.setWakeOnLanManager(endpoint, new WakeOnLanManagerStub(endpoint));
88100
} else if (clusterId == Clusters.ClusterId_MediaInput) {

examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/EndpointsDataStore.java

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import android.content.SharedPreferences;
55
import android.util.JsonReader;
66
import android.util.JsonWriter;
7+
import android.util.Log;
78
import com.matter.tv.app.api.SupportedCluster;
89
import com.matter.tv.server.model.ContentApp;
910
import java.io.IOException;
@@ -59,6 +60,7 @@ public Map<String, ContentApp> getAllPersistedContentApps() {
5960
}
6061

6162
public void persistContentAppEndpoint(ContentApp app) {
63+
Log.i(EndpointsDataStore.class.toString(), "Persist Content App Endpoint " + app.getAppName());
6264
persistedContentApps.put(app.getAppName(), app);
6365
discoveredEndpoints.edit().putString(app.getAppName(), serializeContentApp(app)).apply();
6466
}

0 commit comments

Comments
 (0)