Skip to content

Commit a1dbdd7

Browse files
committed
Moves Wear OS to install over Data Layer
1 parent 3f310f1 commit a1dbdd7

File tree

8 files changed

+85
-9
lines changed

8 files changed

+85
-9
lines changed

feature/results/src/main/java/com/android/developers/androidify/customize/CustomizeExportScreen.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ fun CustomizeAndExportScreen(
130130
onInstallWatchFaceClicked = {
131131
viewModel.installWatchFace()
132132
},
133+
onInstallAndroidifyClicked = {
134+
viewModel.installAndroidifyOnWatch()
135+
},
133136
onResetWatchFaceSend = {
134137
viewModel.resetWatchFaceSend()
135138
},
@@ -151,6 +154,7 @@ private fun CustomizeExportContents(
151154
onToolSelected: (CustomizeTool) -> Unit,
152155
onSelectedToolStateChanged: (ToolState) -> Unit,
153156
onInstallWatchFaceClicked: () -> Unit,
157+
onInstallAndroidifyClicked: () -> Unit,
154158
onResetWatchFaceSend: () -> Unit,
155159
layoutType: CustomizeExportLayoutType,
156160
snackbarHostState: SnackbarHostState,
@@ -263,6 +267,9 @@ private fun CustomizeExportContents(
263267
onWatchFaceInstallClick = {
264268
onInstallWatchFaceClicked()
265269
},
270+
onAndroidifyInstallClick = {
271+
onInstallAndroidifyClicked()
272+
},
266273
onLoad = loadWatchFaces,
267274
watchFaceSelectionState = state.watchFaceSelectionState,
268275
onWatchFaceSelect = onWatchFaceSelect,
@@ -599,6 +606,7 @@ fun CustomizeExportPreview() {
599606
layoutType = CustomizeExportLayoutType.Compact,
600607
onSelectedToolStateChanged = {},
601608
onInstallWatchFaceClicked = {},
609+
onInstallAndroidifyClicked = {},
602610
onResetWatchFaceSend = {},
603611
loadWatchFaces = {},
604612
onWatchFaceSelect = {},
@@ -640,6 +648,7 @@ fun CustomizeExportPreviewLarge() {
640648
layoutType = CustomizeExportLayoutType.Medium,
641649
onSelectedToolStateChanged = {},
642650
onInstallWatchFaceClicked = {},
651+
onInstallAndroidifyClicked = {},
643652
onResetWatchFaceSend = {},
644653
loadWatchFaces = {},
645654
onWatchFaceSelect = {},

feature/results/src/main/java/com/android/developers/androidify/customize/CustomizeExportViewModel.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.fillMaxSize
2222
import androidx.compose.material3.SnackbarHostState
2323
import androidx.compose.ui.Modifier
2424
import androidx.lifecycle.AndroidViewModel
25+
import androidx.lifecycle.application
2526
import androidx.lifecycle.viewModelScope
2627
import com.android.developers.androidify.RemoteConfigDataSource
2728
import com.android.developers.androidify.customize.watchface.WatchFaceSelectionState
@@ -367,6 +368,15 @@ class CustomizeExportViewModel @AssistedInject constructor(
367368
}
368369
}
369370

371+
fun installAndroidifyOnWatch() {
372+
viewModelScope.launch {
373+
val watch = state.value.connectedWatch
374+
watch?.let {
375+
watchfaceInstallationRepository.installAndroidify(application.applicationContext, it.nodeId)
376+
}
377+
}
378+
}
379+
370380
fun installWatchFace() {
371381
val watchFaceToInstall = _state.value.watchFaceSelectionState.selectedWatchFace ?: return
372382
val bitmap = state.value.exportImageCanvas.imageBitmap

feature/results/src/main/java/com/android/developers/androidify/customize/watchface/InstallAndroidifyPanel.kt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package com.android.developers.androidify.customize.watchface
1717

18-
import android.content.Intent
1918
import androidx.compose.foundation.layout.Arrangement
2019
import androidx.compose.foundation.layout.Column
2120
import androidx.compose.foundation.layout.Row
@@ -24,24 +23,31 @@ import androidx.compose.foundation.layout.fillMaxSize
2423
import androidx.compose.foundation.layout.fillMaxWidth
2524
import androidx.compose.foundation.layout.height
2625
import androidx.compose.foundation.layout.padding
26+
import androidx.compose.material3.ButtonDefaults
2727
import androidx.compose.material3.ExperimentalMaterial3Api
28+
import androidx.compose.material3.MaterialTheme
2829
import androidx.compose.runtime.Composable
30+
import androidx.compose.runtime.getValue
31+
import androidx.compose.runtime.mutableStateOf
32+
import androidx.compose.runtime.remember
33+
import androidx.compose.runtime.setValue
2934
import androidx.compose.ui.Alignment
3035
import androidx.compose.ui.Modifier
3136
import androidx.compose.ui.platform.LocalContext
3237
import androidx.compose.ui.res.stringResource
3338
import androidx.compose.ui.tooling.preview.Preview
3439
import androidx.compose.ui.unit.dp
35-
import androidx.core.net.toUri
3640
import com.android.developers.androidify.results.R
3741
import com.android.developers.androidify.theme.AndroidifyTheme
3842
import com.android.developers.androidify.watchface.WatchFaceAsset
3943

4044
@Composable
4145
fun InstallAndroidifyPanel(
46+
onInstallClick: () -> Unit,
4247
modifier: Modifier = Modifier,
4348
) {
4449
val context = LocalContext.current
50+
var isPlayLaunched by remember { mutableStateOf(false) }
4551
val placeholderWatchFace = WatchFaceAsset(
4652
id = "watch_face_1",
4753
previewPath = R.drawable.watch_app_placeholder,
@@ -60,21 +66,42 @@ fun InstallAndroidifyPanel(
6066
) {
6167
WatchFacePreviewItem(
6268
watchFace = placeholderWatchFace,
63-
isSelected = false,
69+
isSelected = true,
6470
onClick = { },
6571
)
6672
}
6773

6874
Spacer(modifier = Modifier.height(24.dp))
75+
76+
val buttonText = if (isPlayLaunched) {
77+
stringResource(R.string.continue_on_watch)
78+
} else {
79+
stringResource(R.string.install_androidify)
80+
}
81+
val launchedColors = ButtonDefaults.buttonColors(
82+
contentColor = MaterialTheme.colorScheme.onSurface,
83+
containerColor = MaterialTheme.colorScheme.secondaryContainer,
84+
)
85+
val installColors = ButtonDefaults.buttonColors(
86+
contentColor = MaterialTheme.colorScheme.surface,
87+
containerColor = MaterialTheme.colorScheme.onSurface,
88+
)
6989
WatchFacePanelButton(
7090
modifier = modifier.padding(horizontal = 16.dp),
71-
buttonText = stringResource(R.string.install_androidify),
91+
buttonText = buttonText,
7292
iconResId = R.drawable.watch_arrow_24,
7393
onClick = {
74-
val uri = "market://details?id=${context.packageName}".toUri()
75-
val intent = Intent(Intent.ACTION_VIEW, uri)
76-
context.startActivity(intent)
94+
if (!isPlayLaunched) {
95+
isPlayLaunched = true
96+
onInstallClick()
97+
}
98+
},
99+
colors = if (isPlayLaunched) {
100+
launchedColors
101+
} else {
102+
installColors
77103
},
104+
isSending = isPlayLaunched,
78105
)
79106
}
80107
}
@@ -84,6 +111,6 @@ fun InstallAndroidifyPanel(
84111
@Composable
85112
private fun InstallAndroidifyPanelPreview() {
86113
AndroidifyTheme {
87-
InstallAndroidifyPanel()
114+
InstallAndroidifyPanel({})
88115
}
89116
}

feature/results/src/main/java/com/android/developers/androidify/customize/watchface/WatchFaceModalSheet.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import com.android.developers.androidify.wear.common.WatchFaceInstallationStatus
6464
fun WatchFaceModalSheet(
6565
connectedWatch: ConnectedWatch,
6666
onWatchFaceInstallClick: (String) -> Unit,
67+
onAndroidifyInstallClick: () -> Unit,
6768
installationStatus: WatchFaceInstallationStatus,
6869
sheetState: SheetState,
6970
watchFaceSelectionState: WatchFaceSelectionState,
@@ -202,7 +203,9 @@ fun WatchFaceModalSheet(
202203
}
203204

204205
else -> {
205-
InstallAndroidifyPanel()
206+
InstallAndroidifyPanel(
207+
onInstallClick = onAndroidifyInstallClick,
208+
)
206209
}
207210
}
208211
}
@@ -243,6 +246,7 @@ private fun WatchFaceModalSheetPreview() {
243246
onLoad = {},
244247
onDismiss = {},
245248
onWatchFaceInstallClick = {},
249+
onAndroidifyInstallClick = {},
246250
sheetState = sheetState,
247251
)
248252
}

feature/results/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,5 @@
5959
<string name="complete_error_message">Check your watch is connected and try again</string>
6060
<string name="no_watch_faces">"No available watch faces"</string>
6161
<string name="error_dismiss">OK</string>
62+
<string name="continue_on_watch">Continue on watch</string>
6263
</resources>

watchface/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ dependencies {
6161
implementation(libs.validator.push.android) {
6262
exclude(group = "com.google.guava", "listenablefuture")
6363
}
64+
implementation(libs.androidx.wear.remote.interactions)
6465
implementation(libs.bcpkix.jdk18on)
6566
implementation(libs.play.services.wearable)
6667
implementation(libs.kotlinx.coroutines.play.services)

watchface/src/main/java/com/android/developers/androidify/watchface/transfer/EmptyWatchFaceInstallationRepository.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.android.developers.androidify.watchface.transfer
1717

18+
import android.content.Context
1819
import android.graphics.Bitmap
1920
import com.android.developers.androidify.watchface.WatchFaceAsset
2021
import com.android.developers.androidify.wear.common.ConnectedWatch
@@ -48,4 +49,6 @@ class EmptyWatchFaceInstallationRepositoryImpl @Inject constructor() : WatchFace
4849
override suspend fun resetInstallationStatus() { }
4950

5051
override suspend fun prepareForTransfer() { }
52+
53+
override suspend fun installAndroidify(context: Context, nodeId: String) { }
5154
}

watchface/src/main/java/com/android/developers/androidify/watchface/transfer/WatchFaceInstallationRepository.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616
package com.android.developers.androidify.watchface.transfer
1717

1818
import android.content.Context
19+
import android.content.Intent
1920
import android.graphics.Bitmap
21+
import android.net.Uri
22+
import androidx.concurrent.futures.await
23+
import androidx.wear.remote.interactions.RemoteActivityHelper
2024
import com.android.developers.androidify.watchface.WatchFaceAsset
2125
import com.android.developers.androidify.watchface.creator.WatchFaceCreator
2226
import com.android.developers.androidify.wear.common.ConnectedWatch
2327
import com.android.developers.androidify.wear.common.WatchFaceInstallError
2428
import com.android.developers.androidify.wear.common.WatchFaceInstallationStatus
2529
import dagger.hilt.android.qualifiers.ApplicationContext
2630
import kotlinx.coroutines.Dispatchers
31+
import kotlinx.coroutines.asExecutor
2732
import kotlinx.coroutines.channels.BufferOverflow
2833
import kotlinx.coroutines.flow.Flow
2934
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -70,6 +75,8 @@ interface WatchFaceInstallationRepository {
7075
suspend fun resetInstallationStatus()
7176

7277
suspend fun prepareForTransfer()
78+
79+
suspend fun installAndroidify(context: Context, nodeId: String)
7380
}
7481

7582
class WatchFaceInstallationRepositoryImpl @Inject constructor(
@@ -133,4 +140,18 @@ class WatchFaceInstallationRepositoryImpl @Inject constructor(
133140
override suspend fun prepareForTransfer() {
134141
manualStatusUpdates.tryEmit(WatchFaceInstallationStatus.Preparing)
135142
}
143+
144+
override suspend fun installAndroidify(context: Context, nodeId: String) {
145+
val backgroundExecutor = Dispatchers.IO.asExecutor()
146+
val remoteActivityHelper = RemoteActivityHelper(context, backgroundExecutor)
147+
148+
remoteActivityHelper.startRemoteActivity(
149+
Intent(Intent.ACTION_VIEW)
150+
.setData(
151+
Uri.parse("market://details?id=${context.packageName}"),
152+
)
153+
.addCategory(Intent.CATEGORY_BROWSABLE),
154+
nodeId,
155+
).await()
156+
}
136157
}

0 commit comments

Comments
 (0)