1
+ /*
2
+ * Copyright 2025 The Android Open Source Project
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package com.example.platform.ui.live_updates
18
+
19
+ import android.annotation.SuppressLint
20
+ import android.app.NotificationManager
21
+ import android.content.Context
22
+ import android.os.Build
23
+ import androidx.annotation.RequiresApi
24
+ import androidx.compose.foundation.layout.Box
25
+ import androidx.compose.foundation.layout.Column
26
+ import androidx.compose.foundation.layout.Spacer
27
+ import androidx.compose.foundation.layout.fillMaxSize
28
+ import androidx.compose.foundation.layout.fillMaxWidth
29
+ import androidx.compose.foundation.layout.height
30
+ import androidx.compose.foundation.layout.padding
31
+ import androidx.compose.material3.Button
32
+ import androidx.compose.material3.Card
33
+ import androidx.compose.material3.Scaffold
34
+ import androidx.compose.material3.SnackbarHost
35
+ import androidx.compose.material3.SnackbarHostState
36
+ import androidx.compose.material3.Text
37
+ import androidx.compose.runtime.Composable
38
+ import androidx.compose.runtime.remember
39
+ import androidx.compose.runtime.rememberCoroutineScope
40
+ import androidx.compose.ui.Alignment
41
+ import androidx.compose.ui.Modifier
42
+ import androidx.compose.ui.platform.LocalContext
43
+ import androidx.compose.ui.res.stringResource
44
+ import androidx.compose.ui.unit.dp
45
+ import com.google.accompanist.permissions.ExperimentalPermissionsApi
46
+ import com.google.accompanist.permissions.isGranted
47
+ import com.google.accompanist.permissions.rememberPermissionState
48
+ import com.google.accompanist.permissions.shouldShowRationale
49
+ import kotlinx.coroutines.launch
50
+
51
+ @RequiresApi(Build .VERSION_CODES .O )
52
+ @Composable
53
+ fun LiveUpdateSample () {
54
+ val notificationManager =
55
+ LocalContext .current.getSystemService(Context .NOTIFICATION_SERVICE ) as NotificationManager
56
+ SnackbarNotificationManager .initialize(LocalContext .current.applicationContext, notificationManager)
57
+ val scope = rememberCoroutineScope()
58
+ val snackbarHostState = remember { SnackbarHostState () }
59
+ Scaffold (
60
+ snackbarHost = {
61
+ SnackbarHost (hostState = snackbarHostState)
62
+ },
63
+ ) { contentPadding ->
64
+ Column (
65
+ modifier = Modifier
66
+ .fillMaxSize()
67
+ .padding(contentPadding),
68
+ ) {
69
+ Text (stringResource( R .string.live_update_summary_text))
70
+ Spacer (modifier = Modifier .height(4 .dp))
71
+ NotificationPermission ()
72
+ Button (onClick = {
73
+ onCheckout()
74
+ scope.launch {
75
+ snackbarHostState.showSnackbar(" Order placed" )
76
+ }
77
+ }) {
78
+ Text (" Checkout" )
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ fun onCheckout () {
85
+ SnackbarNotificationManager .start()
86
+ }
87
+
88
+ @OptIn(ExperimentalPermissionsApi ::class )
89
+ @Composable
90
+ fun NotificationPermission () {
91
+ @SuppressLint(" InlinedApi" ) // Granted at install time on API <33.
92
+ val notificationPermissionState = rememberPermissionState(
93
+ android.Manifest .permission.POST_NOTIFICATIONS ,
94
+ )
95
+ if (! notificationPermissionState.status.isGranted) {
96
+ NotificationPermissionCard (
97
+ shouldShowRationale = notificationPermissionState.status.shouldShowRationale,
98
+ onGrantClick = {
99
+ notificationPermissionState.launchPermissionRequest()
100
+ },
101
+ modifier = Modifier
102
+ .fillMaxWidth()
103
+ )
104
+ }
105
+ }
106
+
107
+ @Composable
108
+ private fun NotificationPermissionCard (
109
+ shouldShowRationale : Boolean ,
110
+ onGrantClick : () -> Unit ,
111
+ modifier : Modifier = Modifier ,
112
+ ) {
113
+ Card (
114
+ modifier = modifier,
115
+ ) {
116
+ Text (
117
+ text = stringResource(R .string.permission_message),
118
+ modifier = Modifier .padding(16 .dp),
119
+ )
120
+ if (shouldShowRationale) {
121
+ Text (
122
+ text = stringResource(R .string.permission_rationale),
123
+ modifier = Modifier .padding(horizontal = 10 .dp),
124
+ )
125
+ }
126
+ Box (
127
+ modifier = Modifier
128
+ .fillMaxWidth()
129
+ .padding(10 .dp),
130
+ contentAlignment = Alignment .BottomEnd ,
131
+ ) {
132
+ Button (onClick = onGrantClick) {
133
+ Text (text = stringResource(R .string.permission_grant))
134
+ }
135
+ }
136
+ }
137
+ }
0 commit comments