Skip to content

Commit

Permalink
Add functions to check if prompts should be displayed (#2069)
Browse files Browse the repository at this point in the history
  • Loading branch information
luizgrp authored Feb 27, 2024
1 parent 7027845 commit 5092ad2
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 51 deletions.
9 changes: 6 additions & 3 deletions datalayer/phone-ui/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ package com.google.android.horologist.datalayer.phone.ui.prompt.installapp {
}

@com.google.android.horologist.annotations.ExperimentalHorologistApi public final class InstallAppPrompt {
ctor public 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<? super com.google.android.horologist.data.apphelper.AppHelperNodeStatus>);
}

}
Expand All @@ -27,8 +28,9 @@ package com.google.android.horologist.datalayer.phone.ui.prompt.reengage {
}

@com.google.android.horologist.annotations.ExperimentalHorologistApi public final class ReEngagePrompt {
ctor public ReEngagePrompt(kotlinx.coroutines.CoroutineScope coroutineScope);
ctor public ReEngagePrompt(kotlinx.coroutines.CoroutineScope coroutineScope, com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper phoneDataLayerAppHelper);
method public android.content.Intent getIntent(android.content.Context context, String nodeId, @DrawableRes int image, String topMessage, String bottomMessage, optional String? positiveButtonLabel, optional String? negativeButtonLabel);
method public suspend Object? shouldDisplayPrompt(kotlin.coroutines.Continuation<? super com.google.android.horologist.data.apphelper.AppHelperNodeStatus>);
}

}
Expand All @@ -40,8 +42,9 @@ package com.google.android.horologist.datalayer.phone.ui.prompt.signin {
}

@com.google.android.horologist.annotations.ExperimentalHorologistApi public final class SignInPrompt {
ctor public SignInPrompt(kotlinx.coroutines.CoroutineScope coroutineScope);
ctor public SignInPrompt(kotlinx.coroutines.CoroutineScope coroutineScope, com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper phoneDataLayerAppHelper);
method public android.content.Intent getIntent(android.content.Context context, String nodeId, @DrawableRes int image, String topMessage, String bottomMessage, optional String? positiveButtonLabel, optional String? negativeButtonLabel);
method public suspend Object? shouldDisplayPrompt(kotlin.coroutines.Continuation<? super com.google.android.horologist.data.apphelper.AppHelperNodeStatus>);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,20 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.DrawableRes
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.data.apphelper.AppHelperNodeStatus
import com.google.android.horologist.data.apphelper.appInstalled
import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper

@ExperimentalHorologistApi
public class InstallAppPrompt {
public class InstallAppPrompt(private val phoneDataLayerAppHelper: PhoneDataLayerAppHelper) {

/**
* Returns a [AppHelperNodeStatus] that meets the criteria to show this prompt, otherwise
* returns null.
*/
public suspend fun shouldDisplayPrompt(): AppHelperNodeStatus? =
phoneDataLayerAppHelper.connectedNodes().firstOrNull { !it.appInstalled }

/**
* Returns the [Intent] to display an install app prompt to the user.
*
Expand All @@ -41,7 +52,7 @@ public class InstallAppPrompt {
* }
* }
*
* launcher.launch(getIntent(/*params*/))
* launcher.launch(installAppPrompt.getIntent(/*params*/))
* ```
*
* It can also be used directly in an [ComponentActivity] with
Expand All @@ -55,7 +66,7 @@ public class InstallAppPrompt {
* }
* }
*
* launcher.launch(getIntent(/*params*/))
* launcher.launch(installAppPrompt.getIntent(/*params*/))
* ```
*/
public fun getIntent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,28 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.DrawableRes
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.data.apphelper.AppHelperNodeStatus
import com.google.android.horologist.data.apphelper.appInstalled
import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper
import kotlinx.coroutines.CoroutineScope

@ExperimentalHorologistApi
public class ReEngagePrompt(coroutineScope: CoroutineScope) {
public class ReEngagePrompt(
coroutineScope: CoroutineScope,
private val phoneDataLayerAppHelper: PhoneDataLayerAppHelper,
) {

init {
CoroutineScopeHolder.coroutineScope = coroutineScope
}

/**
* Returns a [AppHelperNodeStatus] that meets the criteria to show this prompt, otherwise
* returns null.
*/
public suspend fun shouldDisplayPrompt(): AppHelperNodeStatus? =
phoneDataLayerAppHelper.connectedNodes().firstOrNull { it.appInstalled }

/**
* Returns the [Intent] to display a re-engage prompt to the user.
*
Expand All @@ -47,7 +60,7 @@ public class ReEngagePrompt(coroutineScope: CoroutineScope) {
* }
* }
*
* launcher.launch(getIntent(/*params*/))
* launcher.launch(reEngagePrompt.getIntent(/*params*/))
* ```
*
* It can also be used directly in an [ComponentActivity] with
Expand All @@ -61,7 +74,7 @@ public class ReEngagePrompt(coroutineScope: CoroutineScope) {
* }
* }
*
* launcher.launch(getIntent(/*params*/))
* launcher.launch(reEngagePrompt.getIntent(/*params*/))
* ```
*/
public fun getIntent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.DrawableRes
import com.google.android.horologist.annotations.ExperimentalHorologistApi
import com.google.android.horologist.data.UsageStatus
import com.google.android.horologist.data.apphelper.AppHelperNodeStatus
import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper
import kotlinx.coroutines.CoroutineScope

/**
Expand All @@ -31,12 +34,32 @@ import kotlinx.coroutines.CoroutineScope
* @param coroutineScope [CoroutineScope] used to make the call to launch the app on the watch.
*/
@ExperimentalHorologistApi
public class SignInPrompt(coroutineScope: CoroutineScope) {
public class SignInPrompt(
coroutineScope: CoroutineScope,
private val phoneDataLayerAppHelper: PhoneDataLayerAppHelper,
) {

init {
CoroutineScopeHolder.coroutineScope = coroutineScope
}

/**
* Returns a [AppHelperNodeStatus] that meets the criteria to show this prompt, otherwise
* returns null.
*/
public suspend fun shouldDisplayPrompt(): AppHelperNodeStatus? =
phoneDataLayerAppHelper.connectedNodes().firstOrNull {
when (it.surfacesInfo.usageInfo.usageStatus) {
UsageStatus.UNRECOGNIZED,
UsageStatus.USAGE_STATUS_UNSPECIFIED,
UsageStatus.USAGE_STATUS_LAUNCHED_ONCE,
null,
-> true

UsageStatus.USAGE_STATUS_SETUP_COMPLETE -> false
}
}

/**
* Returns the [Intent] to display a sign-in prompt to the user.
*
Expand All @@ -52,7 +75,7 @@ public class SignInPrompt(coroutineScope: CoroutineScope) {
* }
* }
*
* launcher.launch(getIntent(/*params*/))
* launcher.launch(signInPrompt.getIntent(/*params*/))
* ```
*
* It can also be used directly in an [ComponentActivity] with
Expand All @@ -66,7 +89,7 @@ public class SignInPrompt(coroutineScope: CoroutineScope) {
* }
* }
*
* launcher.launch(getIntent(/*params*/))
* launcher.launch(signInPrompt.getIntent(/*params*/))
* ```
*/
public fun getIntent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,24 @@ import com.google.android.horologist.datalayer.sample.shared.CounterValueSeriali
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.ActivityRetainedLifecycle
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.scopes.ActivityRetainedScoped
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import javax.inject.Singleton

@Module
@InstallIn(ActivityRetainedComponent::class)
@InstallIn(SingletonComponent::class)
object DatalayerModule {

@ActivityRetainedScoped
@Singleton
@Provides
fun providesCoroutineScope(
activityRetainedLifecycle: ActivityRetainedLifecycle,
): CoroutineScope {
return CoroutineScope(SupervisorJob() + Dispatchers.Default).also {
activityRetainedLifecycle.addOnClearedListener {
it.cancel()
}
}
fun providesCoroutineScope(): CoroutineScope {
return CoroutineScope(SupervisorJob() + Dispatchers.Default)
}

@ActivityRetainedScoped
@Singleton
@Provides
fun phoneDataLayerAppHelper(
@ApplicationContext applicationContext: Context,
Expand All @@ -58,7 +50,7 @@ object DatalayerModule {
registry = wearDataLayerRegistry,
)

@ActivityRetainedScoped
@Singleton
@Provides
fun wearDataLayerRegistry(
@ApplicationContext applicationContext: Context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.google.android.horologist.datalayer.sample.di

import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper
import com.google.android.horologist.datalayer.phone.ui.prompt.installapp.InstallAppPrompt
import com.google.android.horologist.datalayer.phone.ui.prompt.reengage.ReEngagePrompt
import com.google.android.horologist.datalayer.phone.ui.prompt.signin.SignInPrompt
Expand All @@ -24,26 +25,34 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object PromptModule {
@Singleton
@Provides
fun installAppPrompt(): InstallAppPrompt = InstallAppPrompt()
fun installAppPrompt(phoneDataLayerAppHelper: PhoneDataLayerAppHelper): InstallAppPrompt = InstallAppPrompt(
phoneDataLayerAppHelper = phoneDataLayerAppHelper,
)

@Singleton
@Provides
fun reEngagePrompt(): ReEngagePrompt = ReEngagePrompt(
coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default),
fun reEngagePrompt(
coroutineScope: CoroutineScope,
phoneDataLayerAppHelper: PhoneDataLayerAppHelper,
): ReEngagePrompt = ReEngagePrompt(
coroutineScope = coroutineScope,
phoneDataLayerAppHelper = phoneDataLayerAppHelper,
)

@Singleton
@Provides
fun signInPrompt(): SignInPrompt = SignInPrompt(
coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Default),
fun signInPrompt(
coroutineScope: CoroutineScope,
phoneDataLayerAppHelper: PhoneDataLayerAppHelper,
): SignInPrompt = SignInPrompt(
coroutineScope = coroutineScope,
phoneDataLayerAppHelper = phoneDataLayerAppHelper,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ 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.appInstalled
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
Expand Down Expand Up @@ -62,7 +61,7 @@ class InstallAppPromptDemoViewModel
_uiState.value = InstallAppPromptDemoScreenState.Loading

viewModelScope.launch {
val node = phoneDataLayerAppHelper.connectedNodes().firstOrNull { !it.appInstalled }
val node = installAppPrompt.shouldDisplayPrompt()

_uiState.value = if (node != null) {
InstallAppPromptDemoScreenState.WatchFound
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package com.google.android.horologist.datalayer.sample.screens.inappprompts.reen
import androidx.annotation.MainThread
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.horologist.data.apphelper.appInstalled
import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper
import com.google.android.horologist.datalayer.phone.ui.prompt.reengage.ReEngagePrompt
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -62,7 +61,7 @@ class ReEngagePromptDemoViewModel
_uiState.value = ReEngagePromptDemoScreenState.Loading

viewModelScope.launch {
val node = phoneDataLayerAppHelper.connectedNodes().firstOrNull { it.appInstalled }
val node = reEngagePrompt.shouldDisplayPrompt()

_uiState.value = if (node != null) {
ReEngagePromptDemoScreenState.WatchFound(node.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package com.google.android.horologist.datalayer.sample.screens.inappprompts.sign
import androidx.annotation.MainThread
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.horologist.data.UsageStatus
import com.google.android.horologist.datalayer.phone.PhoneDataLayerAppHelper
import com.google.android.horologist.datalayer.phone.ui.prompt.signin.SignInPrompt
import dagger.hilt.android.lifecycle.HiltViewModel
Expand Down Expand Up @@ -62,17 +61,7 @@ class SignInPromptDemoViewModel
_uiState.value = SignInPromptDemoScreenState.Loading

viewModelScope.launch {
val node = phoneDataLayerAppHelper.connectedNodes().firstOrNull {
when (it.surfacesInfo.usageInfo.usageStatus) {
UsageStatus.UNRECOGNIZED,
UsageStatus.USAGE_STATUS_UNSPECIFIED,
UsageStatus.USAGE_STATUS_LAUNCHED_ONCE,
null,
-> true

UsageStatus.USAGE_STATUS_SETUP_COMPLETE -> false
}
}
val node = signInPrompt.shouldDisplayPrompt()

_uiState.value = if (node != null) {
SignInPromptDemoScreenState.WatchFound(node.id)
Expand Down

0 comments on commit 5092ad2

Please sign in to comment.