0

I have developed an android app that is working perfectly alright on android versions less than 31. For version 31 or greater I am getting the following error

Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.

Code

 public static void initSyncReceiver(Context context) {
    Intent intent = new Intent(context, SyncReciver.class);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    boolean alarmUp = (PendingIntent.getBroadcast(context, 23231, intent, PendingIntent.FLAG_NO_CREATE) != null);
    if (!Common.SharedPreferenceHelper.getSharedPreference(context, context.getString(R.string.survey_sync_settings_key), true)) {
        if (alarmUp) {
            //alarm is up but not needed
            Log.e(TAG, "sync booking alarm is up but not needed, canceling..");
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                    23231, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            pendingIntent.cancel();
            alarmManager.cancel(pendingIntent);
        } else {
            Log.e(TAG, "sync booking alarm neither up nor needed...");
        }
        return;
    }
    setAlarm(intent, context, 23231, 5);
    Log.e(TAG, "sync booking alarm needed so setting...");
}

I am getting the error on boolean alarmUp = (PendingIntent.getBroadcast(context, 23231, intent, PendingIntent.FLAG_NO_CREATE) != null);

I have already migrated to androidx. But no result.

Any help would be highly appreciated.

Moeez
  • 494
  • 9
  • 55
  • 147
  • When creating the pending intent with `PendingIntent.get*` (even with `FLAG_NO_CREATE` I guess) you have to add that flag, e.g. `..., PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE) ;` (bitwise "or" `|` adds bit flags). And not sure about that but wouldn't `alarmManager.cancel(alarmUp)` already do the trick? – zapl Oct 11 '22 at 12:36
  • where to add `alarmManager.cancel(alarmUp)` – Moeez Oct 11 '22 at 12:56
  • I meant `if (alarmUp) { alarmManager.cancel(alarmUp); }` instead of creating a new updated intent just to cancel it. Not sure if that works though. but https://stackoverflow.com/a/28922621/995891 looks like you don't have to do that nor cancel the intent itself – zapl Oct 11 '22 at 13:00
  • Does this answer your question? [How to solve this Targeting S+ (version 31 and above) requires that one of FLAG\_IMMUTABLE or FLAG\_MUTABLE](https://stackoverflow.com/questions/72919110/how-to-solve-this-targeting-s-version-31-and-above-requires-that-one-of-flag) – Ashvin solanki Oct 12 '22 at 10:51

1 Answers1

1

If your app targets Android 12 or higher, you must specify the mutability of each PendingIntent object that your app creates.

Source: https://developer.android.com/guide/components/intents-filters#DeclareMutabilityPendingIntent

In short, add PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_MUTABLE to other PendingIntent flags.

Whether it's mutable or not depends. For alarms, it's normally immutable.

For example, before:

PendingIntent.FLAG_UPDATE_CURRENT

Now:

PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE

If you target Android 5 or lower, you need:

PendingIntent.FLAG_UPDATE_CURRENT or
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        PendingIntent.FLAG_IMMUTABLE
    } else {
        0
    }

P.S. I happened to read this commit today. It has a similar modification.

Updated code for the question:

 public static void initSyncReceiver(Context context) {
    Intent intent = new Intent(context, SyncReciver.class);
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    boolean alarmUp = (PendingIntent.getBroadcast(context, 23231, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE) != null);
    if (!Common.SharedPreferenceHelper.getSharedPreference(context, context.getString(R.string.survey_sync_settings_key), true)) {
        if (alarmUp) {
            //alarm is up but not needed
            Log.e(TAG, "sync booking alarm is up but not needed, canceling..");
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                    23231, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
            pendingIntent.cancel();
            alarmManager.cancel(pendingIntent);
        } else {
            Log.e(TAG, "sync booking alarm neither up nor needed...");
        }
        return;
    }
    setAlarm(intent, context, 23231, 5);
    Log.e(TAG, "sync booking alarm needed so setting...");
}
Dewey Reed
  • 4,353
  • 2
  • 27
  • 41
  • So I should replace `boolean alarmUp = (PendingIntent.getBroadcast(context, 23231, intent, PendingIntent.FLAG_NO_CREATE) != null);` with `boolean alarmUp = (PendingIntent.getBroadcast(context, 23231, intent, PendingIntent.PendingIntent.FLAG_IMMUTABLE) != null);` ? – Moeez Oct 12 '22 at 06:34
  • @Moeez The answer is updated. You could copy and paste. – Dewey Reed Oct 12 '22 at 10:48