13

I updated my OS version to android 10 last night, and since then the startActivity function inside the broadcast receiver is doing nothing. This is how I try to start the activity based on the answer of CommonsWare:

Intent i = new Intent(context, AlarmNotificationActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // This is at least android 10...

                Log.d("Debug", "This is android 10");
                // Start the alert via full-screen intent.
                PendingIntent startAlarmPendingIntent = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
                String CHANNEL_ID = "my_channel_02";
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                        context.getString(R.string.notification_channel_name_second),
                        NotificationManager.IMPORTANCE_HIGH);
                NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                notificationManager.createNotificationChannel(channel);
                NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
                        .setContentTitle("Um, hi!")
                        .setAutoCancel(true)
                        .setPriority(NotificationCompat.PRIORITY_HIGH)
                        .setFullScreenIntent(startAlarmPendingIntent, true);
                Log.d("Debug", "Try to load screen");
                notificationManager.notify(0, builder.build());

            }

The log shows that I am getting to the notify command but nothing happens. I am asking for USE_FULL_SCREEN_INTENT permission on the manifest so I should be able to use full-screen intents. My app is useless now because of that issue. Does anyone know how to solve it?

Simple UX Apps
  • 611
  • 2
  • 10
  • 20

3 Answers3

14

Android 10's restriction on background activity starts was announced about six months ago. You can read more about it in the documentation.

Use a high-priority notification, with an associated full-screen Intent, instead. See the documentation. This sample app demonstrates this, by using WorkManager to trigger a background event needing to alert the user. There, I use a high-priority notification instead of starting the activity directly:

val pi = PendingIntent.getActivity(
  appContext,
  0,
  Intent(appContext, MainActivity::class.java),
  PendingIntent.FLAG_UPDATE_CURRENT
)

val builder = NotificationCompat.Builder(appContext, CHANNEL_WHATEVER)
  .setSmallIcon(R.drawable.ic_notification)
  .setContentTitle("Um, hi!")
  .setAutoCancel(true)
  .setPriority(NotificationCompat.PRIORITY_HIGH)
  .setFullScreenIntent(pi, true)

val mgr = appContext.getSystemService(NotificationManager::class.java)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
  && mgr.getNotificationChannel(CHANNEL_WHATEVER) == null
) {
  mgr.createNotificationChannel(
    NotificationChannel(
      CHANNEL_WHATEVER,
      "Whatever",
      NotificationManager.IMPORTANCE_HIGH
    )
  )
}

mgr.notify(NOTIF_ID, builder.build())
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thank you very much. Can you show a Java version of this code? – Simple UX Apps Sep 07 '19 at 11:35
  • @SimpleUXApps: I do not have that particular book sample in Java. [Here is a whole directory of notification samples in Java](https://github.com/commonsguy/cw-omnibus/tree/FINAL/Notifications) from an older book. – CommonsWare Sep 07 '19 at 11:59
  • Thank you for your quick replay. I implemented your code but still nothing happens. Can you please check my edited question to see whether I have missed something in my new code? – Simple UX Apps Sep 07 '19 at 13:36
  • 1
    @SimpleUXApps: If you are trying to start an activity, do not use `PendingIntent.getBroadcast()`. Use `PendingIntent.getActivity()`. – CommonsWare Sep 07 '19 at 14:35
  • im trying to start an activity not a notification and i am not using pendingintent. Im confused on how to do this – steller Sep 28 '19 at 23:31
  • 1
    @steller: I assume that you are referring to [this question](https://stackoverflow.com/q/58150700/115145). **You cannot start an activity from the background in Android 10**, except in very limited cases involving user interaction. This is covered in [the documentation](https://developer.android.com/guide/components/activities/background-starts). – CommonsWare Sep 28 '19 at 23:36
  • I need to do it. I am making an alarm app and i need to show an alarm screen. How the hell can i do this on a broadcast receiver? from the broadcast reciever i am navigating to an activity so i can show an activity. This is a dumb decision by google. – steller Sep 28 '19 at 23:39
  • 3
    @steller: "I am making an alarm app and i need to show an alarm screen" -- alarm clock apps have used high-priority notifications with full-screen intents for years. This is covered in [the documentation](https://developer.android.com/guide/components/activities/background-starts#display-notification). Your activity will be displayed immediately **if** the user's device is locked, as Android knows that it is safe to show an activity then. And, in other cases, it will not take over the screen from what the user is using it for, as that may cause harm to the user. – CommonsWare Sep 28 '19 at 23:44
  • im a bit confused by "high-priority notifications with full-screen intents for years" I have never seen an example of this. Do you have a proper link that shows an example of what your talking about? Also "our activity will be displayed immediately if the user's device is locked," im a bit confused by this as my pixel 2 with android 10 is on lock and the intent doesnt fire. I need to show a screen and play sounds. I was doing this with an activity. Im not sure how this can be done with a notification. – steller Sep 28 '19 at 23:52
  • 1
    @steller: "im a bit confused by this as my pixel 2 with android 10 is on lock and the intent doesnt fire" -- my guess is that you have not implemented a high-priority notification with a full-screen intent. That is what I was referring to. "Do you have a proper link that shows an example of what your talking about?" -- this is covered in the answer and in [the documentation](https://developer.android.com/training/notify-user/time-sensitive). – CommonsWare Sep 28 '19 at 23:56
  • Will i be able to show notification that has a button to snooze the alarm or stop the sounds from playing? – steller Sep 29 '19 at 00:16
  • 1
    @steller: Yes. You might use a pair of actions for that, with associated icons. For example, [this activity](https://github.com/commonsguy/cw-omnibus/blob/v9.0/Notifications/FullScreen/app/src/main/java/com/commonsware/android/fullscreen/MainActivity.java) raises a notification with a full-screen intent and an action. This particular example is not very practical, but it shows how the APIs work. – CommonsWare Sep 29 '19 at 00:46
  • @CommonsWare: I am running the [this example](https://gitlab.com/commonsguy/cw-android-q/tree/v0.5/PayAttention) and [this one](https://github.com/commonsguy/cw-omnibus/tree/FINAL/Notifications/FullScreen) on my device Samsung Galaxy A20 with Android Pie and neither of them show the activity if the screen is turned off. The notification is displayed. Can you help me debug this? Because I am also having this issue in my own app... – amp Jan 02 '20 at 16:25
  • 1
    @amp: At least on a Samsung Galaxy S9, I need to tap on the notification on the lockscreen, then swipe, in order to get the activity to show. Device manufacturers might be tinkering with the mechanics. However, I don't have any advice about how to improve the process. – CommonsWare Jan 03 '20 at 00:37
  • @CommonsWare: Thanks for the reply. I also tried with a Pixel 2 Android 10 emulator and the screen is still off when the notification is triggered. So I am not sure it is something to do with device manufacturers modifications... I am wondering how Whatsapp is able to display the incoming call screen... Or other apps like alarms and native phone call... It should be possible to do... – amp Jan 03 '20 at 08:59
  • @CommonsWare I essentially copied your code and the notification works, but I have to tap the notification to start the activity. I am testing on a Pixel 2Q emulator. – Hong May 17 '22 at 20:36
  • 1
    @Hong: The notification will only launch the activity directly if the device is known to be idle (e.g., the screen is off). If the device might be in use, you just get the "heads-up" presentation, so the user will clearly see the notification but otherwise is not interrupted. – CommonsWare May 17 '22 at 21:12
  • @CommonsWare Thank you for the clarification. I am trying to start an app automatically on reboot. This is an enterprise app targeting a specific Samsung device, so there are no other apps interfering with it. I am not clear whether the device is regarded as idle after reboot? We have 100% control of the device and can do whatever is needed. Do you have any suggestions for this scenario? – Hong May 17 '22 at 21:30
  • @Hong: "We have 100% control of the device and can do whatever is needed" -- modify the OS to start your process on device boot. Or, write a launcher and use that in place of the existing launcher. – CommonsWare May 17 '22 at 21:47
  • @CommonsWare Thank you. OS modification is out of the question for now but a custom launcher sounds very appealing and we will look into it. – Hong May 17 '22 at 21:57
11

You can use SYSTEM_ALERT_WINDOW to force launch activity window in android 10, refer to this settingsuperposition setting:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>  
</activity>  
    <receiver
        android:name=".OnBootReceiver"
        android:enabled="true"
        android:exported="true"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>

in launched app check permissions:

private void RequestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + this.getPackageName()));
            startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
        } else {
            //Permission Granted-System will work
        }
    }
}

you will can user intent as android older versions

public class OnBootReceiver extends BroadcastReceiver {
    private static final String TAG = OnBootReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            Intent activity = new Intent(context, MainActivity.class);
            activity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(activity);
        } catch (Exception e){
            Log.d(TAG,e.getMessage()+"");
        }
    }
}
YovanyOso
  • 111
  • 1
  • 2
2

Android 10's restriction on background activity starts was announced about six months ago. You can read more about it in the documentation.

So you need to have a high-level notification and when the user clicks on the notification your activity will be opened notifications

public class UIExampleReceiver extends BroadcastReceiver {

    public static final String TAG_NOTIFICATION = "NOTIFICATION_MESSAGE";
    public static final String CHANNEL_ID = "channel_1111";
    public static final int NOTIFICATION_ID = 111111;
    private static final String TAG = "Receiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            // If android 10 or higher
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                startActivityNotification(
                    context,
                    NOTIFICATION_ID,
                    context.getResources().getString(R.string.open_app),
                    context.getResources().getString(R.string.click_app)
                );
            } else {
                // If lower than Android 10, we use the normal method ever.
                Intent activity = new Intent(context, ExampleActivity.class);
                activity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(activity);
            }
        } catch (Exception e) {
            Log.d(TAG, e.getMessage() + "");
        }
    }


    // notification method to support opening activities on Android 10
    public static void startActivityNotification (Context context, int notificationID,
    String title, String message) {

        NotificationManager mNotificationManager =
        (NotificationManager)
        context.getSystemService(Context.NOTIFICATION_SERVICE);
        //Create GPSNotification builder
        NotificationCompat.Builder mBuilder;

        //Initialise ContentIntent
        Intent ContentIntent = new Intent(context, ExampleActivity.class);
        ContentIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
        Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent ContentPendingIntent = PendingIntent . getActivity (context,
        0,
        ContentIntent,
        PendingIntent.FLAG_UPDATE_CURRENT);

        mBuilder = new NotificationCompat . Builder (context)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentTitle(title)
            .setContentText(message)
            .setColor(context.getResources().getColor(R.color.colorPrimaryDark))
            .setAutoCancel(true)
            .setContentIntent(ContentPendingIntent)
            .setDefaults(Notification.DEFAULT_LIGHTS | Notification . DEFAULT_VIBRATE)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(
                CHANNEL_ID,
                "Activity Opening Notification",
                NotificationManager.IMPORTANCE_HIGH
            );
            mChannel.enableLights(true);
            mChannel.enableVibration(true);
            mChannel.setDescription("Activity opening notification");

            mBuilder.setChannelId(CHANNEL_ID);

            Objects.requireNonNull(mNotificationManager).createNotificationChannel(mChannel);
        }
        Objects.requireNonNull(mNotificationManager).notify(
            TAG_NOTIFICATION, notificationID,
            mBuilder.build()
        );
    }
}
Jaydip
  • 592
  • 5
  • 27
Huy TRAN
  • 71
  • 6