Skip to content

Commit

Permalink
Improve AppHelperNodeStatus to make nodeType only available when app …
Browse files Browse the repository at this point in the history
…is installed (#1827)
  • Loading branch information
luizgrp authored Nov 22, 2023
1 parent 1aa843a commit 4bbd268
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 40 deletions.
46 changes: 31 additions & 15 deletions datalayer/core/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -93,31 +93,47 @@ package com.google.android.horologist.data {
package com.google.android.horologist.data.apphelper {

public final class AppHelperNodeStatus {
ctor public AppHelperNodeStatus(String id, String displayName, boolean isAppInstalled, com.google.android.horologist.data.apphelper.AppHelperNodeType nodeType, optional error.NonExistentClass surfacesInfo);
ctor public AppHelperNodeStatus(String id, String displayName, com.google.android.horologist.data.apphelper.AppInstallationStatus appInstallationStatus, optional error.NonExistentClass surfacesInfo);
method public String component1();
method public String component2();
method public boolean component3();
method public com.google.android.horologist.data.apphelper.AppHelperNodeType component4();
method public error.NonExistentClass! component5();
method public com.google.android.horologist.data.apphelper.AppHelperNodeStatus copy(String id, String displayName, boolean isAppInstalled, com.google.android.horologist.data.apphelper.AppHelperNodeType nodeType, error.NonExistentClass! surfacesInfo);
method public com.google.android.horologist.data.apphelper.AppInstallationStatus component3();
method public error.NonExistentClass! component4();
method public com.google.android.horologist.data.apphelper.AppHelperNodeStatus copy(String id, String displayName, com.google.android.horologist.data.apphelper.AppInstallationStatus appInstallationStatus, error.NonExistentClass! surfacesInfo);
method public com.google.android.horologist.data.apphelper.AppInstallationStatus getAppInstallationStatus();
method public String getDisplayName();
method public String getId();
method public com.google.android.horologist.data.apphelper.AppHelperNodeType getNodeType();
method public error.NonExistentClass! getSurfacesInfo();
method public boolean isAppInstalled();
property public final com.google.android.horologist.data.apphelper.AppInstallationStatus appInstallationStatus;
property public final String displayName;
property public final String id;
property public final boolean isAppInstalled;
property public final com.google.android.horologist.data.apphelper.AppHelperNodeType nodeType;
property public final error.NonExistentClass! surfacesInfo;
}

public enum AppHelperNodeType {
method public static com.google.android.horologist.data.apphelper.AppHelperNodeType valueOf(String name) throws java.lang.IllegalArgumentException;
method public static com.google.android.horologist.data.apphelper.AppHelperNodeType[] values();
enum_constant public static final com.google.android.horologist.data.apphelper.AppHelperNodeType PHONE;
enum_constant public static final com.google.android.horologist.data.apphelper.AppHelperNodeType UNKNOWN;
enum_constant public static final com.google.android.horologist.data.apphelper.AppHelperNodeType WATCH;
public final class AppHelperNodeStatusKt {
method public static boolean getAppInstalled(com.google.android.horologist.data.apphelper.AppHelperNodeStatus);
}

public abstract sealed class AppInstallationStatus {
}

public static final class AppInstallationStatus.Installed extends com.google.android.horologist.data.apphelper.AppInstallationStatus {
ctor public AppInstallationStatus.Installed(com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType nodeType);
method public com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType component1();
method public com.google.android.horologist.data.apphelper.AppInstallationStatus.Installed copy(com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType nodeType);
method public com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType getNodeType();
property public final com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType nodeType;
}

public static final class AppInstallationStatus.NotInstalled extends com.google.android.horologist.data.apphelper.AppInstallationStatus {
field public static final com.google.android.horologist.data.apphelper.AppInstallationStatus.NotInstalled INSTANCE;
}

public enum AppInstallationStatusNodeType {
method public static com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType valueOf(String name) throws java.lang.IllegalArgumentException;
method public static com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType[] values();
enum_constant public static final com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType PHONE;
enum_constant public static final com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType UNKNOWN;
enum_constant public static final com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType WATCH;
}

public abstract class DataLayerAppHelper {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,28 @@ import com.google.android.horologist.data.SurfacesInfo
public data class AppHelperNodeStatus(
val id: String,
val displayName: String,
val isAppInstalled: Boolean,
val nodeType: AppHelperNodeType,
val appInstallationStatus: AppInstallationStatus,
val surfacesInfo: SurfacesInfo = SurfacesInfo.getDefaultInstance(),
)

public enum class AppHelperNodeType {
UNKNOWN,
public sealed class AppInstallationStatus {
data object NotInstalled : AppInstallationStatus()

data class Installed(
val nodeType: AppInstallationStatusNodeType,
) : AppInstallationStatus()
}

public enum class AppInstallationStatusNodeType {
WATCH,
PHONE,

/**
* This case should not happen, but it's here in order to keep the node listed even in a
* scenario where there were issues retrieving the capability of the node.
*/
UNKNOWN,
}

public val AppHelperNodeStatus.appInstalled: Boolean
get() = this.appInstallationStatus is AppInstallationStatus.Installed
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,22 @@ abstract class DataLayerAppHelper(
val allInstalledNodes = installedPhoneNodes + installedWatchNodes

return nearbyNodes.map {
val appInstallationStatus = if (allInstalledNodes.contains(it.id)) {
val nodeType = when (it.id) {
in installedPhoneNodes -> AppInstallationStatusNodeType.PHONE
in installedWatchNodes -> AppInstallationStatusNodeType.WATCH
else -> AppInstallationStatusNodeType.UNKNOWN
}
AppInstallationStatus.Installed(nodeType = nodeType)
} else {
AppInstallationStatus.NotInstalled
}

AppHelperNodeStatus(
id = it.id,
displayName = it.displayName,
isAppInstalled = allInstalledNodes.contains(it.id),
appInstallationStatus = appInstallationStatus,
surfacesInfo = getSurfaceStatus(it.id),
nodeType = when (it.id) {
in installedPhoneNodes -> AppHelperNodeType.PHONE
in installedWatchNodes -> AppHelperNodeType.WATCH
else -> AppHelperNodeType.UNKNOWN
},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.android.horologist.data.UsageStatus
import com.google.android.horologist.data.apphelper.AppHelperNodeStatus
import com.google.android.horologist.data.apphelper.AppHelperNodeType
import com.google.android.horologist.data.apphelper.AppInstallationStatus
import com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType
import com.google.android.horologist.data.apphelper.appInstalled
import com.google.android.horologist.data.complicationInfo
import com.google.android.horologist.data.surfacesInfo
import com.google.android.horologist.data.tileInfo
Expand Down Expand Up @@ -68,17 +70,22 @@ fun AppHelperNodeStatusCard(
style = MaterialTheme.typography.labelMedium,
text = stringResource(R.string.app_helper_node_id_label, nodeStatus.id),
)
Text(
style = MaterialTheme.typography.labelMedium,
text = stringResource(R.string.app_helper_node_type_label, nodeStatus.nodeType),
)
Text(
style = MaterialTheme.typography.labelMedium,
text = stringResource(
R.string.app_helper_is_app_installed_label,
nodeStatus.isAppInstalled,
nodeStatus.appInstalled,
),
)
val nodeType = if (nodeStatus.appInstalled) {
(nodeStatus.appInstallationStatus as AppInstallationStatus.Installed).nodeType
} else {
stringResource(id = R.string.app_helper_node_type_unknown_label)
}
Text(
style = MaterialTheme.typography.labelMedium,
text = stringResource(R.string.app_helper_node_type_label, nodeType),
)
if (nodeStatus.surfacesInfo.complicationsList.isNotEmpty()) {
Text(
style = MaterialTheme.typography.labelMedium,
Expand Down Expand Up @@ -140,8 +147,9 @@ fun NodeCardPreview() {
val nodeStatus = AppHelperNodeStatus(
displayName = "Pixel Watch",
id = "a1b2c3",
isAppInstalled = true,
nodeType = AppHelperNodeType.WATCH,
appInstallationStatus = AppInstallationStatus.Installed(
nodeType = AppInstallationStatusNodeType.WATCH,
),
surfacesInfo = surfacesInfo {
tiles.add(
tileInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ import com.google.android.horologist.data.ProtoDataStoreHelper.protoDataStore
import com.google.android.horologist.data.WearDataLayerRegistry
import com.google.android.horologist.data.WearableApiAvailability
import com.google.android.horologist.data.apphelper.AppHelperNodeStatus
import com.google.android.horologist.data.apphelper.AppHelperNodeType
import com.google.android.horologist.data.apphelper.AppInstallationStatus
import com.google.android.horologist.data.apphelper.AppInstallationStatusNodeType
import com.google.android.horologist.data.complicationInfo
import com.google.android.horologist.data.surfacesInfo
import com.google.android.horologist.data.tileInfo
Expand Down Expand Up @@ -96,7 +97,8 @@ class MainActivity : ComponentActivity() {
LaunchedEffect(Unit) {
coroutineScope.launch {
apiAvailable = WearableApiAvailability.isAvailable(registry.dataClient)
nodeList = if (apiAvailable) phoneDataLayerAppHelper.connectedNodes() else listOf()
nodeList =
if (apiAvailable) phoneDataLayerAppHelper.connectedNodes() else listOf()
}
}

Expand Down Expand Up @@ -202,8 +204,9 @@ fun MainPreview() {
AppHelperNodeStatus(
id = "a1b2c3d4",
displayName = "Pixel Watch",
isAppInstalled = true,
nodeType = AppHelperNodeType.WATCH,
appInstallationStatus = AppInstallationStatus.Installed(
nodeType = AppInstallationStatusNodeType.WATCH,
),
surfacesInfo = surfacesInfo {
tiles.add(
tileInfo {
Expand Down
3 changes: 2 additions & 1 deletion datalayer/sample/phone/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
<string name="wearable_message_api_unavailable">This device does not have capability to communicate to Wearable Data Layer API</string>
<string name="app_helper_node_name_label">Node: %1$s</string>
<string name="app_helper_node_id_label">ID: %1$s</string>
<string name="app_helper_node_type_label">Type: %1$s</string>
<string name="app_helper_is_app_installed_label">App installed: %1$s</string>
<string name="app_helper_node_type_label">Type: %1$s</string>
<string name="app_helper_node_type_unknown_label">UNKNOWN (app not installed)</string>
<string name="app_helper_complications_label">Complications: %1$s</string>
<string name="app_helper_tiles_label">Tiles: %1$s</string>
<string name="app_helper_usage_status">Usage: %1$s</string>
Expand Down
3 changes: 1 addition & 2 deletions docs/datalayer-helpers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ phone.
AppHelperNodeStatus(
id=7cd1c38a,
displayName=Google Pixel Watch,
isAppInstalled=true,
nodeType=WATCH,
appInstallationStatus=Installed(nodeType=WATCH),
surfacesInfo=# SurfacesInfo@125fcbff
complications {
instance_id: 1234
Expand Down

0 comments on commit 4bbd268

Please sign in to comment.