Skip to content

Commit

Permalink
Re-Implement App Install flow (project-chip#34141)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
2 people authored and austina-csa committed Aug 12, 2024
1 parent a7416a6 commit 8f1fe4f
Show file tree
Hide file tree
Showing 32 changed files with 878 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5583,6 +5583,9 @@ cluster ApplicationLauncher = 1292 {
kSuccess = 0;
kAppNotAvailable = 1;
kSystemBusy = 2;
kPendingUserApproval = 3;
kDownloading = 4;
kInstalling = 5;
}

bitmap Feature : bitmap32 {
Expand Down
6 changes: 6 additions & 0 deletions examples/placeholder/linux/apps/app1/config.matter
Original file line number Diff line number Diff line change
Expand Up @@ -8236,6 +8236,9 @@ cluster ApplicationLauncher = 1292 {
kSuccess = 0;
kAppNotAvailable = 1;
kSystemBusy = 2;
kPendingUserApproval = 3;
kDownloading = 4;
kInstalling = 5;
}

bitmap Feature : bitmap32 {
Expand Down Expand Up @@ -8295,6 +8298,9 @@ cluster ApplicationLauncher = 1292 {
kSuccess = 0;
kAppNotAvailable = 1;
kSystemBusy = 2;
kPendingUserApproval = 3;
kDownloading = 4;
kInstalling = 5;
}

bitmap Feature : bitmap32 {
Expand Down
6 changes: 6 additions & 0 deletions examples/placeholder/linux/apps/app2/config.matter
Original file line number Diff line number Diff line change
Expand Up @@ -8193,6 +8193,9 @@ cluster ApplicationLauncher = 1292 {
kSuccess = 0;
kAppNotAvailable = 1;
kSystemBusy = 2;
kPendingUserApproval = 3;
kDownloading = 4;
kInstalling = 5;
}

bitmap Feature : bitmap32 {
Expand Down Expand Up @@ -8252,6 +8255,9 @@ cluster ApplicationLauncher = 1292 {
kSuccess = 0;
kAppNotAvailable = 1;
kSystemBusy = 2;
kPendingUserApproval = 3;
kDownloading = 4;
kInstalling = 5;
}

bitmap Feature : bitmap32 {
Expand Down
2 changes: 1 addition & 1 deletion examples/tv-app/android/App/platform-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.google.zxing:core:3.3.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.matter.tv.server.handlers;

import android.content.Context;
import android.content.pm.PackageManager;
import android.util.Log;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import com.matter.tv.server.tvapp.Application;
import com.matter.tv.server.tvapp.ApplicationLauncherManager;
import com.matter.tv.server.tvapp.LauncherResponse;
import com.matter.tv.server.utils.EndpointsDataStore;
import com.matter.tv.server.utils.InstallationObserver;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class ApplicationLauncherManagerImpl implements ApplicationLauncherManager {

private static final String TAG = "ApplicationLauncherService";

private volatile boolean registered = false;
private PackageManager packageManager;
private EndpointsDataStore endpointsDataStore;

/** Hash Map of packageName & Install Status */
private Map<String, InstallationObserver.InstallStatus> lastReceivedInstallationStatus =
new HashMap<>();

private LiveData<InstallationObserver.InstallState> installStateLiveData;

public ApplicationLauncherManagerImpl(Context context) {
packageManager = context.getPackageManager();
endpointsDataStore = EndpointsDataStore.getInstance(context);
registerSelf(context);
}

private final Observer<InstallationObserver.InstallState> installStateObserver =
state -> {
lastReceivedInstallationStatus.put(state.getAppPackageName(), state.getStatus());
switch (state.getStatus()) {
case IN_PROGRESS:
// Installation is in progress
Log.d(TAG, "Installation of " + state.getAppPackageName() + " in progress");
break;
case SUCCEEDED:
// Installation succeeded
Log.d(TAG, "Installation of " + state.getAppPackageName() + " succeeded");
break;
case FAILED:
// Installation failed
Log.d(TAG, "Installation of " + state.getAppPackageName() + " failed");
break;
}
};

private void stopObservingInstallations() {
if (installStateLiveData != null) {
Log.d("InstallationObserver", "Stopped Observing");
installStateLiveData.removeObserver(installStateObserver);
}
}

public void unregister() {
stopObservingInstallations();
}

private void registerSelf(Context context) {
if (registered) {
Log.i(TAG, "Package update receiver for matter already registered");
return;
} else {
registered = true;
}
Log.i(TAG, "Registered the matter package updates receiver");

installStateLiveData = InstallationObserver.installationStates(context);
installStateLiveData.observeForever(installStateObserver);
Log.d(TAG, "Started Observing package installations");
}

@Override
public int[] getCatalogList() {
Log.i(TAG, "Get Catalog List");
return new int[] {123, 456, 89010};
}

@Override
public LauncherResponse launchApp(Application app, String data) {
Log.i(
TAG,
"Launch app id:" + app.applicationId + " cid:" + app.catalogVendorId + " data:" + data);

int status = 0;
String responseData = "";

// Installed Apps that have declared CSA product id & vendor id in their manifes
boolean matterEnabledAppdIsInstalled =
endpointsDataStore.getAllPersistedContentApps().containsKey(app.applicationId);
// Installed App
boolean appIsInstalled =
InstallationObserver.getInstalledPackages(packageManager).contains(app.applicationId);
boolean isAppInstalling =
Objects.equals(
lastReceivedInstallationStatus.get(app.applicationId),
InstallationObserver.InstallStatus.IN_PROGRESS);
boolean appInstallFailed =
Objects.equals(
lastReceivedInstallationStatus.get(app.applicationId),
InstallationObserver.InstallStatus.FAILED);

// This use-case can happen if app is installed
// but it does not support Matter
if (!matterEnabledAppdIsInstalled && appIsInstalled) {
Log.i(
TAG,
"Matter enabled app is not installed, but app is installed. Launching app's install page");
status = LauncherResponse.STATUS_PENDING_USER_APPROVAL;
responseData = "App is installed, try updating";

//
// Add code to launch App Install Page
//

} else if (!matterEnabledAppdIsInstalled && !appIsInstalled) {
Log.i(
TAG,
"Matter enabled app is not installed and app is not installed. Launching app's install page");
if (isAppInstalling) {
Log.i(TAG, "App is installing");
status = LauncherResponse.STATUS_INSTALLING;
} else {
status = LauncherResponse.STATUS_PENDING_USER_APPROVAL;
if (appInstallFailed) {
responseData = "App install failed. Try again";
}
}

//
// Add code to launch App Install Page
//

} else if (matterEnabledAppdIsInstalled && appIsInstalled) {
Log.i(TAG, "Launching the app");
status = LauncherResponse.STATUS_SUCCESS;

//
// Add code to launch an app
//
}

return new LauncherResponse(status, responseData);
}

@Override
public LauncherResponse stopApp(Application app) {
Log.i(TAG, "Stop app id:" + app.applicationId + " cid:" + app.catalogVendorId);
return new LauncherResponse(LauncherResponse.STATUS_SUCCESS, "");
}

@Override
public LauncherResponse hideApp(Application app) {
Log.i(TAG, "Hide app id:" + app.applicationId + " cid:" + app.catalogVendorId);
return new LauncherResponse(LauncherResponse.STATUS_SUCCESS, "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import chip.platform.PreferencesConfigurationManager;
import chip.platform.PreferencesKeyValueStoreManager;
import com.matter.tv.server.MatterCommissioningPrompter;
import com.matter.tv.server.handlers.ApplicationLauncherManagerImpl;
import com.matter.tv.server.tvapp.ApplicationLauncherManager;
import com.matter.tv.server.tvapp.ChannelManagerStub;
import com.matter.tv.server.tvapp.Clusters;
import com.matter.tv.server.tvapp.ContentLaunchManagerStub;
Expand All @@ -55,6 +57,8 @@ public class MatterServant {
private boolean mIsOn = true;
private int mOnOffEndpoint;
private int mLevelEndpoint;
private MatterCommissioningPrompter matterCommissioningPrompter;
private ApplicationLauncherManager applicationLauncherManager;

private MatterServant() {}

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

this.context = context;

this.applicationLauncherManager = new ApplicationLauncherManagerImpl(context);

// The order is important, must
// first new TvApp to load dynamic library
// then chipPlatform to prepare platform
// then TvApp.preServerInit to initialize any server configuration
// then start ChipAppServer
// then TvApp.postServerInit to init app platform
//
// TODO: Move all of the bellow KeypadInputManager...LevelManagerStub to
// PlatformAppCommandDelegate
// There is no need for this complicated logic
mTvApp =
new TvApp(
(app, clusterId, endpoint) -> {
if (clusterId == Clusters.ClusterId_KeypadInput) {
app.setKeypadInputManager(endpoint, new KeypadInputManagerStub(endpoint));
} else if (clusterId == Clusters.ClusterId_ApplicationLauncher) {
app.setApplicationLauncherManager(endpoint, applicationLauncherManager);
} else if (clusterId == Clusters.ClusterId_WakeOnLan) {
app.setWakeOnLanManager(endpoint, new WakeOnLanManagerStub(endpoint));
} else if (clusterId == Clusters.ClusterId_MediaInput) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import android.content.SharedPreferences;
import android.util.JsonReader;
import android.util.JsonWriter;
import android.util.Log;
import com.matter.tv.app.api.SupportedCluster;
import com.matter.tv.server.model.ContentApp;
import java.io.IOException;
Expand Down Expand Up @@ -59,6 +60,7 @@ public Map<String, ContentApp> getAllPersistedContentApps() {
}

public void persistContentAppEndpoint(ContentApp app) {
Log.i(EndpointsDataStore.class.toString(), "Persist Content App Endpoint " + app.getAppName());
persistedContentApps.put(app.getAppName(), app);
discoveredEndpoints.edit().putString(app.getAppName(), serializeContentApp(app)).apply();
}
Expand Down
Loading

0 comments on commit 8f1fe4f

Please sign in to comment.