diff --git a/datalayer/phone-ui/api/current.api b/datalayer/phone-ui/api/current.api index 5bd6437fc8..be0b85995f 100644 --- a/datalayer/phone-ui/api/current.api +++ b/datalayer/phone-ui/api/current.api @@ -16,7 +16,7 @@ package com.google.android.horologist.datalayer.phone.ui.prompt.installapp { @com.google.android.horologist.annotations.ExperimentalHorologistApi public final class InstallAppPrompt { ctor public InstallAppPrompt(com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper phoneDataLayerAppHelper); method public android.content.Intent getIntent(android.content.Context context, String appPackageName, @DrawableRes int image, String topMessage, String bottomMessage); - method public suspend Object? shouldDisplayPrompt(kotlin.coroutines.Continuation); + method public suspend Object? shouldDisplayPrompt(optional kotlin.jvm.functions.Function1? predicate, optional kotlin.coroutines.Continuation); } } diff --git a/datalayer/phone-ui/src/main/java/com/google/android/horologist/datalayer/phone/ui/prompt/installapp/InstallAppPrompt.kt b/datalayer/phone-ui/src/main/java/com/google/android/horologist/datalayer/phone/ui/prompt/installapp/InstallAppPrompt.kt index 5af28720f6..d4e41dd8e3 100644 --- a/datalayer/phone-ui/src/main/java/com/google/android/horologist/datalayer/phone/ui/prompt/installapp/InstallAppPrompt.kt +++ b/datalayer/phone-ui/src/main/java/com/google/android/horologist/datalayer/phone/ui/prompt/installapp/InstallAppPrompt.kt @@ -29,13 +29,25 @@ import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper @ExperimentalHorologistApi public class InstallAppPrompt(private val phoneDataLayerAppHelper: PhoneDataLayerAppHelper) { - /** * Returns a [AppHelperNodeStatus] that meets the criteria to show this prompt, otherwise * returns null. + * + * @param predicate augments the criteria applying a [filter][List.filter] with this predicate. */ - public suspend fun shouldDisplayPrompt(): AppHelperNodeStatus? = - phoneDataLayerAppHelper.connectedNodes().firstOrNull { !it.appInstalled } + public suspend fun shouldDisplayPrompt( + predicate: ((AppHelperNodeStatus) -> Boolean)? = null, + ): AppHelperNodeStatus? = + phoneDataLayerAppHelper.connectedNodes() + .filter { !it.appInstalled } + .let { + if (predicate != null) { + it.filter(predicate) + } else { + it + } + } + .firstOrNull() /** * Returns the [Intent] to display an install app prompt to the user. diff --git a/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoScreen.kt b/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoScreen.kt index 3c20a83cf6..b2f9ca4728 100644 --- a/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoScreen.kt +++ b/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoScreen.kt @@ -21,13 +21,18 @@ import android.content.Intent import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -75,7 +80,7 @@ fun InstallAppPromptDemoScreen( @Composable fun InstallAppPromptDemoScreen( state: InstallAppPromptDemoScreenState, - onRunDemoClick: () -> Unit, + onRunDemoClick: (shouldFilterByNearby: Boolean) -> Unit, getInstallPromptIntent: () -> Intent, onInstallPromptLaunched: () -> Unit, onInstallPromptInstallClick: () -> Unit, @@ -92,13 +97,23 @@ fun InstallAppPromptDemoScreen( } } + var shouldFilterByNearby by remember { mutableStateOf(false) } + Column( modifier = modifier.padding(all = 10.dp), ) { Text(text = stringResource(id = R.string.install_app_prompt_api_call_demo_message)) + Row( + modifier = Modifier.padding(top = 10.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Checkbox(checked = shouldFilterByNearby, onCheckedChange = { shouldFilterByNearby = it }) + Text(text = stringResource(id = R.string.install_app_prompt_checkbox_label)) + } + Button( - onClick = onRunDemoClick, + onClick = { onRunDemoClick(shouldFilterByNearby) }, modifier = Modifier .padding(top = 10.dp) .align(Alignment.CenterHorizontally), diff --git a/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoViewModel.kt b/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoViewModel.kt index 8dccca6441..b40f6e1afc 100644 --- a/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoViewModel.kt +++ b/datalayer/sample/phone/src/main/java/com/google/android/horologist/datalayer/sample/screens/inappprompts/installapp/InstallAppPromptDemoViewModel.kt @@ -19,6 +19,7 @@ package com.google.android.horologist.datalayer.sample.screens.inappprompts.inst import androidx.annotation.MainThread import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.google.android.horologist.data.apphelper.AppHelperNodeStatus import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper import com.google.android.horologist.datalayer.phone.ui.prompt.installapp.InstallAppPrompt import dagger.hilt.android.lifecycle.HiltViewModel @@ -57,11 +58,16 @@ class InstallAppPromptDemoViewModel } } - fun onRunDemoClick() { + fun onRunDemoClick(shouldFilterByNearby: Boolean) { _uiState.value = InstallAppPromptDemoScreenState.Loading viewModelScope.launch { - val node = installAppPrompt.shouldDisplayPrompt() + val filter = if (shouldFilterByNearby) { + { node: AppHelperNodeStatus -> node.isNearby } + } else { + null + } + val node = installAppPrompt.shouldDisplayPrompt(filter) _uiState.value = if (node != null) { InstallAppPromptDemoScreenState.WatchFound diff --git a/datalayer/sample/phone/src/main/res/values/strings.xml b/datalayer/sample/phone/src/main/res/values/strings.xml index 7e64025c58..6e881e1ed5 100644 --- a/datalayer/sample/phone/src/main/res/values/strings.xml +++ b/datalayer/sample/phone/src/main/res/values/strings.xml @@ -63,6 +63,7 @@ This demo calls the Horologist API to show the install app prompt for the watch demo app. The API will only display the prompt if there is a watch connected and the watch does not have the app installed.\n\nGoogle Play won\'t find this app as it is not published. + Filter by nearby watches Run demo Test the interactions between the phone and the watch with the demo app. Install the demo app on your Wear OS watch.