Jeetendra sahu
Jeetendra sahu

Reputation: 13

Notifications Not Working on API 34 (Android 14) in Java?

I'm encountering an issue where notifications are not being received on devices running Android 14 (API level 34) after updating my project, but they fail to appear on Android 14 devices.

Manifest permissions:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:targetSandboxVersion="1">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

    <uses-feature android:name="android.hardware.camera" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <queries>
        <intent>
            <action
                android:name="android.media.action.IMAGE_CAPTURE"
                android:exported="true" />
        </intent>
    </queries>

    <application
        android:name=".Utils.App"
        android:allowBackup="false"
        android:exported="true"
        android:icon="@drawable/app_logo"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:requestLegacyExternalStorage="true"
        android:roundIcon="@drawable/app_logo"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true"
        tools:replace="android:allowBackup">

        <uses-library
            android:name="org.apache.http.legacy"
            android:exported="true"
            android:required="false" />

        <service
            android:name=".Utils.ForegroundService"
            android:enabled="true"
            android:exported="false"
            android:foregroundServiceType="dataSync" />

        <service
            android:name=".Utils.BackgroundService"
            android:enabled="true"
            android:exported="false"
            android:foregroundServiceType="dataSync"/>

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:exported="true"
            android:value="@string/google_maps_key" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action
                    android:name="android.intent.action.MAIN"
                    android:exported="true" />

                <category
                    android:name="android.intent.category.LAUNCHER"
                    android:exported="true" />
            </intent-filter>
        </activity>

        <service
            android:name=".Utils.MyFirebaseMessagingService"
            android:enabled="true"
            android:exported="false"
            android:stopWithTask="false">
            <intent-filter>
                <action
                    android:name="com.google.firebase.MESSAGING_EVENT"
                    android:exported="true" />
            </intent-filter>
        </service>

        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:exported="true"
            android:value="@string/notification_channel_id" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:exported="true"
            android:resource="@mipmap/ic_launcher_foreground" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:exported="true"
            android:resource="@mipmap/ic_launcher_foreground" />
        <meta-data
            android:name="com.google.android.gms.wallet.api.enabled"
            android:exported="true"
            android:value="true" />

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:exported="true"
                android:resource="@xml/file_paths" />
        </provider>
    </application>

</manifest>

Notification code

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String CHANNEL_ID = "default_channel";
    private static final String CHANNEL_NAME = "FCM";
    private static final String CHANNEL_DESC = "Firebase Cloud Messaging";
    final String TAG = "MyFirebaseMsgService";
    private String id = "";
    private String title = "";
    private String message = "";
    private String type = "";
    private String fcm_notification = "";
    private String uid = "";
    private String stuName = "", clsSec = "", imgUrl_old = "", imgUrl_new = "", enrollmentNo = "", cls = "", sec = "", conType = "", component = "", period = "";

    @Override
    public void onNewToken(@NonNull String s) {
        super.onNewToken(s);
        Log.e("newToken", s);
    }

    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
        Log.e("Message Body", Objects.requireNonNull(Objects.requireNonNull(remoteMessage.getNotification()).getBody()));
        Log.e("Message data payload: ", remoteMessage.getData().toString());
        Log.e("From: ", Objects.requireNonNull(remoteMessage.getFrom()));

        if (!remoteMessage.getData().isEmpty()) {
            try {
                Log.d(TAG, "Message data payload: " + remoteMessage.getData());

                id = remoteMessage.getData().get("id");
                uid = remoteMessage.getData().get("uid");
                title = remoteMessage.getData().get("title");
                message = remoteMessage.getData().get("message");
                type = remoteMessage.getData().get("type");
                fcm_notification = "Y";

                stuName = remoteMessage.getData().get("stuName");
                clsSec = remoteMessage.getData().get("clsSec");
                imgUrl_old = remoteMessage.getData().get("oldImg");
                imgUrl_new = remoteMessage.getData().get("newImg");
                enrollmentNo = remoteMessage.getData().get("enrollmentNo");

                cls = remoteMessage.getData().get("cls");
                sec = remoteMessage.getData().get("sec");
                conType = remoteMessage.getData().get("conType");

                component = remoteMessage.getData().get("component");
                period = remoteMessage.getData().get("period");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        sendNotification(remoteMessage.getNotification().getBody(), id, uid, title, message, type, fcm_notification, stuName, clsSec, imgUrl_old, imgUrl_new, enrollmentNo, cls, sec, conType, component, period);
    }

    private void sendNotification(String body, String user_id, String uid, String title, String message, String type, String fcm_notification, String stuName, String clsSec, String imgUrl_old, String imgUrl_new, String enrollmentNo, String cls, String sec, String conType, String component, String period) {
        try {
            Intent intent = new Intent(this, MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.putExtra("fcm_notification", fcm_notification);
            intent.putExtra("title", title);
            intent.putExtra("message", message);
            intent.putExtra("type", type);
            intent.putExtra("id", user_id);
            intent.putExtra("uid", uid);
            intent.putExtra("stuName", stuName);
            intent.putExtra("clsSec", clsSec);
            intent.putExtra("imgUrl_old", imgUrl_old);
            intent.putExtra("imgUrl_new", imgUrl_new);
            intent.putExtra("enrollmentNo", enrollmentNo);
            intent.putExtra("cls", cls);
            intent.putExtra("sec", sec);
            intent.putExtra("conType", conType);
            intent.putExtra("component", component);
            intent.putExtra("period", period);

            int uniqueInt = (int) (System.currentTimeMillis() & 0xff);
            PendingIntent pendingIntent;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
                pendingIntent = PendingIntent.getActivity(getApplicationContext(), uniqueInt, intent, PendingIntent.FLAG_MUTABLE);
            } else {
                pendingIntent = PendingIntent.getActivity(getApplicationContext(), uniqueInt, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
            }

            Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
            notificationBuilder.setSmallIcon(R.drawable.app_logo)
                    .setContentText(body)
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.app_logo))
                    .setColor(ContextCompat.getColor(this, R.color.colorAccent))
                    .setLights(Color.RED, 1000, 300)
                    .setDefaults(Notification.DEFAULT_VIBRATE)
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setSmallIcon(R.drawable.app_logo);

            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
                channel.setDescription(CHANNEL_DESC);
                channel.setShowBadge(true);
                channel.canShowBadge();
                channel.enableLights(true);
                channel.setLightColor(Color.RED);
                channel.enableVibration(true);
                channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500});

                assert notificationManager != null;
                notificationManager.createNotificationChannel(channel);
            }

            assert notificationManager != null;
            notificationManager.notify(0, notificationBuilder.build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Requesting notification permission in MainActivity

public class MainActivity extends AppCompatActivity {
    private static final int REQUEST_NOTIFICATION_PERMISSION = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_NOTIFICATION_PERMISSION);
            } else {
                // Permission already granted
                showNotification();
            }
        } else {
            // For devices below Android 13, no need to request the permission
            showNotification();
        }
    }

    private void showNotification() {
        // Code to show your notification
        Toast.makeText(this, "Notification permission granted", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_NOTIFICATION_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission granted
                showNotification();
            } else {
                // Permission denied
                Toast.makeText(this, "Notification permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

Background service

public class BackgroundService extends Service {

    private static final int NOTIF_ID = 1;
    private static final String NOTIF_CHANNEL_ID = "Channel_Id";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startForegroundService();
        return super.onStartCommand(intent, flags, startId);
    }

    private void startForegroundService() {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Create Notification Channel
            CharSequence name = getString(R.string.channel_name);
            String description = getString(R.string.channel_description);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(NOTIF_CHANNEL_ID, name, importance);
            channel.setDescription(description);
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }

        startForeground(NOTIF_ID, new NotificationCompat.Builder(this, NOTIF_CHANNEL_ID)
                .setOngoing(true)
                .setSmallIcon(R.drawable.app_logo)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("Service is running in the background")
                .setContentIntent(pendingIntent)
                .build());
    }
}

Foreground Service

public class ForegroundService extends Service {
    public static final String CHANNEL_ID = "ForegroundServiceChannel";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String input = intent.getStringExtra("inputExtra");
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.app_logo)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1, notification);
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(CHANNEL_ID, "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }
}

Questions:

  1. Are there any additional changes or permissions required for notifications in Android 14 (API level 34)?
  2. Is there any specific handling required for the new notification behavior in Android 14?
  3. Are there known issues or bugs related to notifications in Android 14?

I have tried multiple options with the help of Google and ChatGPT, but it remains unresolved.

Upvotes: 0

Views: 2040

Answers (1)

Shilkan Patel
Shilkan Patel

Reputation: 1

Ensure you are requesting the POST_NOTIFICATIONS permission properly in your MainActivity. Your existing code for this seems correct, but make sure it is being executed.

or Update PendingIntent Flags: Ensure that you are using the appropriate flags for PendingIntent. Specifically, use PendingIntent.FLAG_UPDATE_CURRENT or other suitable flags depending on your needs.

 PendingIntent pendingIntent;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getActivity(getApplicationContext(), uniqueInt, intent, PendingIntent.FLAG_MUTABLE);
        } else {
            pendingIntent = PendingIntent.getActivity(getApplicationContext(), uniqueInt, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        }

Upvotes: 0

Related Questions