cannot start activity background in android 10 [ android Q ]

I use android 10 [android Q, galaxy 10],

I use android studio 3.3,

using AVD, and made a api 29 [android 10] virtual phone.

at the virtual machine, I execute my app , after that, I launch other app like calendar, calculator. so my app activity get into background mode.

when I receive a message at BroadcastReceiver. I call startActivity.

here, code --> public class myReceiver extends BroadcastReceiver {}

public void onReceive(Context context, Intent intent)
{
        Intent intentRun = new Intent(context, LoginSuccess.class);
        intentRun.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intentRun);
}

but LoginSuccess activity do not shows up. [when my app is in background mode]

using same code, LoginSuccess activity show up very well when my app is in foreground mode.

call stack capture image

above image shows call stack right before I call startActivity in broadcast receiver.

I have read guide line for android 10 background activity issue. [developer.android.com/~~ some location]

at the guide line,

I came to know that if the activity exists in call stack, it can be started even in background mode.

above code, it try to start activity that exists in recent call stack.

why startActivity call fail in background mode ? [maybe not fail , but anyway not activated into foreground]


Solution 1:

With Android Q, it is impossible to start an activity from the background automatically if your app does not include those exceptions listed in the link below.

https://developer.android.com/guide/components/activities/background-starts

Possible Solutions:

1- You can choose just show a service notification, and start pending intent with a click

2- You can use full-screen intents to show your intent immediately as shown in the other answer and suggested by Google.

For full-screen intent solution, as described in the official document

The system UI may choose to display a heads-up notification, instead of launching this intent, while the user is using the device.

3- To start the activity automatically in the background, The most possible solution in my view is adding "SYSTEM_ALERT_WINDOW" to the manifest file. And ask for user permission once when the app opened the first time. (The user can give this permission manually - (Settings-Apps-Your App-Advanced- Draw over other apps))

Example code to request permission :

In Manifest:

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

Somewhere in app:

 public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE= 2323;

//if the user already granted the permission or the API is below Android 10 no need to ask for permission

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
 !Settings.canDrawOverlays(getContext()))
                    {RequestPermission()}

 private void RequestPermission() {
            // Check if Android M or higher
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                // Show alert dialog to the user saying a separate permission is needed
                // Launch the settings activity if the user prefers
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                        Uri.parse("package:" + getActivity().getPackageName()));
                startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
            }
        }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(getContext())) {
                    PermissionDenied();
                }
                else
                {
                 // Permission Granted-System will work
            }

        }
    }
 }

Solution 2:

I'm open activity using the below logic. as google, blog says if you want to open activity in background service for use notification on android 10 or higher.

In Manifest:

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

Example:

private void startActivity() {

        Uri sound = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.siren);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            NotificationManager notificationManager =
                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            AudioAttributes attributes = new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build();

            String CHANNEL_ID = BuildConfig.APPLICATION_ID.concat("_notification_id");
            String CHANNEL_NAME = BuildConfig.APPLICATION_ID.concat("_notification_name");
            assert notificationManager != null;

            NotificationChannel mChannel = notificationManager.getNotificationChannel(CHANNEL_ID);
            if (mChannel == null) {
                mChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
                mChannel.setSound(sound, attributes);
                notificationManager.createNotificationChannel(mChannel);
            }

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);

            builder.setSmallIcon(R.drawable.logo)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText(getString(R.string.login))
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setCategory(NotificationCompat.CATEGORY_CALL)
                    .setFullScreenIntent(openScreen(Constants.NOTIFICATION_ID), true)
                    .setAutoCancel(true)
                    .setOngoing(true);

            Notification notification = builder.build();
            notificationManager.notify(Constants.NOTIFICATION_ID, notification);
        } else {
            startActivity(new Intent(BackgroundService.this, LoginActivity.class)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
        }

    }

    private PendingIntent openScreen(int notificationId) {
        Intent fullScreenIntent = new Intent(this, LoginActivity.class);
        fullScreenIntent.putExtra(Constants.NOTIFICATION_IDS, notificationId);
        return PendingIntent.getActivity(this, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    }