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