Skip to content

Commit 6dfc3c3

Browse files
authored
FCM updates for API levels 31 and 33 (#1401)
* refactor(fcm): use FLAG_IMMUTABLE for API level >= 31 * refactor(fcm): ask for POST_NOTIFICATION permission in APIs >= 33 * refactor(functions): ask for POST_NOTIFICATION permission in APIs >= 33
1 parent 23469de commit 6dfc3c3

File tree

8 files changed

+140
-3
lines changed

8 files changed

+140
-3
lines changed

functions/app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ dependencies {
3838
implementation project(":internal:chooserx")
3939

4040
implementation 'androidx.activity:activity-ktx:1.5.1'
41+
implementation 'androidx.fragment:fragment-ktx:1.5.2'
4142
implementation 'androidx.appcompat:appcompat:1.5.0'
4243
implementation 'com.google.android.material:material:1.6.1'
4344

functions/app/src/main/java/com/google/samples/quickstart/functions/java/MainActivity.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,29 @@
1616

1717
package com.google.samples.quickstart.functions.java;
1818

19+
import android.Manifest;
1920
import android.content.Context;
2021
import android.content.Intent;
22+
import android.content.pm.PackageManager;
23+
import android.os.Build;
2124
import android.os.Bundle;
2225

2326
import androidx.activity.result.ActivityResultLauncher;
27+
import androidx.activity.result.contract.ActivityResultContracts;
2428
import androidx.annotation.NonNull;
2529

2630
import com.firebase.ui.auth.FirebaseAuthUIActivityResultContract;
2731
import com.firebase.ui.auth.data.model.FirebaseAuthUIAuthenticationResult;
2832
import com.google.android.material.snackbar.Snackbar;
2933

3034
import androidx.appcompat.app.AppCompatActivity;
35+
import androidx.core.content.ContextCompat;
3136

3237
import android.text.TextUtils;
3338
import android.util.Log;
3439
import android.view.View;
3540
import android.view.inputmethod.InputMethodManager;
41+
import android.widget.Toast;
3642

3743
import com.firebase.ui.auth.AuthUI;
3844
import com.firebase.ui.auth.IdpResponse;
@@ -66,6 +72,18 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
6672
private FirebaseFunctions mFunctions;
6773
// [END define_functions_instance]
6874

75+
private final ActivityResultLauncher<String> requestPermissionLauncher =
76+
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
77+
if (isGranted) {
78+
Toast.makeText(this, "Notifications permission granted", Toast.LENGTH_SHORT)
79+
.show();
80+
} else {
81+
Toast.makeText(this,
82+
"FCM can't post notifications without POST_NOTIFICATIONS permission",
83+
Toast.LENGTH_LONG).show();
84+
}
85+
});
86+
6987
@Override
7088
protected void onCreate(Bundle savedInstanceState) {
7189
super.onCreate(savedInstanceState);
@@ -79,6 +97,8 @@ protected void onCreate(Bundle savedInstanceState) {
7997
// [START initialize_functions_instance]
8098
mFunctions = FirebaseFunctions.getInstance();
8199
// [END initialize_functions_instance]
100+
101+
askNotificationPermission();
82102
}
83103

84104
// [START function_add_numbers]
@@ -274,4 +294,17 @@ public void onClick(View view) {
274294
break;
275295
}
276296
}
297+
298+
private void askNotificationPermission() {
299+
// This is only necessary for API level >= 33 (TIRAMISU)
300+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
301+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
302+
PackageManager.PERMISSION_GRANTED) {
303+
// FCM SDK (and your app) can post notifications.
304+
} else{
305+
// Directly ask for the permission
306+
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
307+
}
308+
}
309+
}
277310
}

functions/app/src/main/java/com/google/samples/quickstart/functions/kotlin/MainActivity.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
package com.google.samples.quickstart.functions.kotlin
22

3+
import android.Manifest
34
import android.app.Activity
45
import android.content.Context
6+
import android.content.pm.PackageManager
7+
import android.os.Build
58
import android.os.Bundle
69
import android.text.TextUtils
710
import android.util.Log
811
import android.view.View
912
import android.view.inputmethod.InputMethodManager
13+
import android.widget.Toast
14+
import androidx.activity.result.contract.ActivityResultContracts
1015
import androidx.appcompat.app.AppCompatActivity
16+
import androidx.core.content.ContextCompat
1117
import com.firebase.ui.auth.AuthUI
1218
import com.firebase.ui.auth.FirebaseAuthUIActivityResultContract
1319
import com.firebase.ui.auth.data.model.FirebaseAuthUIAuthenticationResult
@@ -36,6 +42,18 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
3642

3743
private lateinit var binding: ActivityMainBinding
3844

45+
private val requestPermissionLauncher = registerForActivityResult(
46+
ActivityResultContracts.RequestPermission()
47+
) { isGranted: Boolean ->
48+
if (isGranted) {
49+
Toast.makeText(this, "Notifications permission granted",Toast.LENGTH_SHORT)
50+
.show()
51+
} else {
52+
Toast.makeText(this, "FCM can't post notifications without POST_NOTIFICATIONS permission",
53+
Toast.LENGTH_LONG).show()
54+
}
55+
}
56+
3957
override fun onCreate(savedInstanceState: Bundle?) {
4058
super.onCreate(savedInstanceState)
4159
binding = ActivityMainBinding.inflate(layoutInflater)
@@ -50,6 +68,8 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
5068
// [START initialize_functions_instance]
5169
functions = Firebase.functions
5270
// [END initialize_functions_instance]
71+
72+
askNotificationPermission()
5373
}
5474

5575
// [START function_add_numbers]
@@ -227,6 +247,20 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
227247
}
228248
}
229249

250+
private fun askNotificationPermission() {
251+
// This is only necessary for API Level > 33 (TIRAMISU)
252+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
253+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
254+
PackageManager.PERMISSION_GRANTED
255+
) {
256+
// FCM SDK (and your app) can post notifications.
257+
} else {
258+
// Directly ask for the permission
259+
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
260+
}
261+
}
262+
}
263+
230264
companion object {
231265
private const val TAG = "MainActivity"
232266
}

messaging/app/build.gradle

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ dependencies {
4646
implementation project(":internal:chooserx")
4747
implementation 'androidx.annotation:annotation:1.4.0'
4848
implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
49-
implementation 'androidx.core:core:1.8.0'
49+
implementation 'androidx.core:core-ktx:1.8.0'
50+
51+
// Required when asking for permission to post notifications (starting in Android 13)
52+
implementation 'androidx.activity:activity-ktx:1.5.1'
53+
implementation 'androidx.fragment:fragment-ktx:1.5.2'
5054

5155
implementation 'com.google.android.material:material:1.6.1'
5256

messaging/app/src/main/java/com/google/firebase/quickstart/fcm/java/MainActivity.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,21 @@
1616

1717
package com.google.firebase.quickstart.fcm.java;
1818

19+
import android.Manifest;
1920
import android.app.NotificationChannel;
2021
import android.app.NotificationManager;
22+
import android.content.pm.PackageManager;
2123
import android.os.Build;
2224
import android.os.Bundle;
2325
import android.util.Log;
2426
import android.view.View;
2527
import android.widget.Toast;
2628

29+
import androidx.activity.result.ActivityResultLauncher;
30+
import androidx.activity.result.contract.ActivityResultContracts;
2731
import androidx.annotation.NonNull;
2832
import androidx.appcompat.app.AppCompatActivity;
33+
import androidx.core.content.ContextCompat;
2934

3035
import com.google.android.gms.tasks.OnCompleteListener;
3136
import com.google.android.gms.tasks.Task;
@@ -36,6 +41,16 @@
3641
public class MainActivity extends AppCompatActivity {
3742

3843
private static final String TAG = "MainActivity";
44+
private final ActivityResultLauncher<String> requestPermissionLauncher =
45+
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
46+
if (isGranted) {
47+
Toast.makeText(this, "Notifications permission granted",Toast.LENGTH_SHORT)
48+
.show();
49+
} else {
50+
Toast.makeText(this, "FCM can't post notifications without POST_NOTIFICATIONS permission",
51+
Toast.LENGTH_LONG).show();
52+
}
53+
});
3954

4055
@Override
4156
protected void onCreate(Bundle savedInstanceState) {
@@ -117,6 +132,20 @@ public void onComplete(@NonNull Task<String> task) {
117132
// [END log_reg_token]
118133
}
119134
});
135+
136+
askNotificationPermission();
120137
}
121138

139+
private void askNotificationPermission() {
140+
// This is only necessary for API Level > 33 (TIRAMISU)
141+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
142+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
143+
PackageManager.PERMISSION_GRANTED) {
144+
// FCM SDK (and your app) can post notifications.
145+
} else {
146+
// Directly ask for the permission
147+
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
148+
}
149+
}
150+
}
122151
}

messaging/app/src/main/java/com/google/firebase/quickstart/fcm/java/MyFirebaseMessagingService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ public void onMessageReceived(RemoteMessage remoteMessage) {
9494
// Check if message contains a notification payload.
9595
if (remoteMessage.getNotification() != null) {
9696
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
97+
String notificationBody = remoteMessage.getNotification().getBody();
98+
if (remoteMessage.getNotification().getBody() != null) {
99+
sendNotification(notificationBody);
100+
}
97101
}
98102

99103
// Also if you intend on generating your own notifications as a result of a received FCM
@@ -162,7 +166,7 @@ private void sendNotification(String messageBody) {
162166
Intent intent = new Intent(this, MainActivity.class);
163167
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
164168
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
165-
PendingIntent.FLAG_ONE_SHOT);
169+
PendingIntent.FLAG_IMMUTABLE);
166170

167171
String channelId = getString(R.string.default_notification_channel_id);
168172
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

messaging/app/src/main/java/com/google/firebase/quickstart/fcm/kotlin/MainActivity.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.google.firebase.quickstart.fcm.kotlin
22

3+
import android.Manifest
34
import android.app.NotificationChannel
45
import android.app.NotificationManager
6+
import android.content.pm.PackageManager
57
import android.os.Build
68
import android.os.Bundle
79
import android.util.Log
810
import android.widget.Toast
11+
import androidx.activity.result.contract.ActivityResultContracts
912
import androidx.appcompat.app.AppCompatActivity
13+
import androidx.core.content.ContextCompat
1014
import com.google.android.gms.tasks.OnCompleteListener
1115
import com.google.firebase.ktx.Firebase
1216
import com.google.firebase.messaging.ktx.messaging
@@ -15,6 +19,18 @@ import com.google.firebase.quickstart.fcm.databinding.ActivityMainBinding
1519

1620
class MainActivity : AppCompatActivity() {
1721

22+
private val requestPermissionLauncher = registerForActivityResult(
23+
ActivityResultContracts.RequestPermission()
24+
) { isGranted: Boolean ->
25+
if (isGranted) {
26+
Toast.makeText(this, "Notifications permission granted", Toast.LENGTH_SHORT)
27+
.show()
28+
} else {
29+
Toast.makeText(this, "FCM can't post notifications without POST_NOTIFICATIONS permission",
30+
Toast.LENGTH_LONG).show()
31+
}
32+
}
33+
1834
override fun onCreate(savedInstanceState: Bundle?) {
1935
super.onCreate(savedInstanceState)
2036
val binding = ActivityMainBinding.inflate(layoutInflater)
@@ -82,6 +98,21 @@ class MainActivity : AppCompatActivity() {
8298
}
8399

84100
Toast.makeText(this, "See README for setup instructions", Toast.LENGTH_SHORT).show()
101+
askNotificationPermission()
102+
}
103+
104+
private fun askNotificationPermission() {
105+
// This is only necessary for API Level > 33 (TIRAMISU)
106+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
107+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
108+
PackageManager.PERMISSION_GRANTED
109+
) {
110+
// FCM SDK (and your app) can post notifications.
111+
} else {
112+
// Directly ask for the permission
113+
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
114+
}
115+
}
85116
}
86117

87118
companion object {

messaging/app/src/main/java/com/google/firebase/quickstart/fcm/kotlin/MyFirebaseMessagingService.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
5454
// Check if message contains a notification payload.
5555
remoteMessage.notification?.let {
5656
Log.d(TAG, "Message Notification Body: ${it.body}")
57+
it.body?.let { body -> sendNotification(body) }
5758
}
5859

5960
// Also if you intend on generating your own notifications as a result of a received FCM
@@ -116,7 +117,7 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
116117
val intent = Intent(this, MainActivity::class.java)
117118
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
118119
val pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
119-
PendingIntent.FLAG_ONE_SHOT)
120+
PendingIntent.FLAG_IMMUTABLE)
120121

121122
val channelId = getString(R.string.default_notification_channel_id)
122123
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)

0 commit comments

Comments
 (0)