20

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]

jongdae lee
  • 201
  • 1
  • 2
  • 4
  • 1
    Android 10 (API level 29) and higher place restrictions on when apps can start activities when the app is running in the background. for more detail check out this blog. https://developer.android.com/guide/components/activities/background-starts – Kaushal Panchal Dec 20 '19 at 04:22
  • Look at this post where EventBus is used https://stackoverflow.com/a/64670128/12805923 – Ahmet B. Nov 03 '20 at 20:27

4 Answers4

30

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
            }

        }
    }
 }
Eren Tüfekçi
  • 2,463
  • 3
  • 16
  • 35
  • thank you ! I tested your code. it works good. but, it's not run-time permission. so, user have to go back to my app after overlay window settings finished by switching app. – jongdae lee Dec 22 '19 at 23:45
  • Yes They must. Android made starting activity in background very restricted. – Eren Tüfekçi Dec 23 '19 at 09:08
  • 1
    use shared preference to check whether you allow the permission or not , boolean checkPermission = SpUtil.getInstance().getBoolean(AppConstants.CHECK_PERMISSION, false); – Muhammad Hasnat Jan 09 '20 at 14:19
  • Settings.canDrawOverlays(getContext() method returns if this permission granted. So no need to request permission more than one time if user grants it – Eren Tüfekçi May 15 '20 at 23:52
  • what should i write in PermissionDenied() method? can you please send that method too? – Saloni Parikh Aug 13 '20 at 14:07
  • in my case, I created a dialog which explains the system wouldn't work without this permission and showed it to the user – Eren Tüfekçi Aug 13 '20 at 14:31
10

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);
    }
Kaushal Panchal
  • 1,785
  • 1
  • 11
  • 27
  • thank you for your answer. but, my app should not use notification. because response time is very important in my app. users should respond in a few seconds, so after click notification message, already time passed by, so limit time is over. is there any other method in the respect of user response time ? activating my activity from background to foreground is very good , but is it impossible ? – jongdae lee Dec 20 '19 at 05:36
  • Read this blog https://developer.android.com/guide/components/activities/background-starts .. and in your case try to handle some specific cases where the restriction doesn't apply to open activity. – Kaushal Panchal Dec 20 '19 at 05:40
  • thank you. I will read it. as you said, I think I have to handle some specific cases related to activity stack. I tested more cases, some activities show up, other activities not show up. I have to know what is different in each case. – jongdae lee Dec 20 '19 at 05:49
  • Works perfect! Thank you. You can call notificationManager.cancel(notId); right after notificationManager.notify to dismiss notification if it's not needed. – Basim Sherif Apr 08 '20 at 15:35
  • This can not work for Android 10 Go device. https://developer.android.com/about/versions/10/behavior-changes-all#sysalert-go – Shrdi May 05 '20 at 09:54
  • 1
    @Shrdi I have not to check this on go device. but above code almost all devices. give me some time I have to check and update my answer with a workable code on go device. – Kaushal Panchal May 06 '20 at 05:14
0

If you have root permissions you can simply use the am command for this in the shell:

    public static final void switchAcitivty (final Context context) throws IOException {
        final Runtime runtime = Runtime.getRuntime();
        final String intentCommand =  "su -c am start -n yourpackage/.MainActivity -a android.intent.action.VIEW";
        Log.i("TAG", intentCommand);
        runtime.exec(intentCommand);
    }

It gets blocked without root permission (silently, which is annoying).

Jappie Kerk
  • 1,257
  • 12
  • 16
0

Very strange but launching activity from foreground service worked in release build. Was not working in debug build (when debugging via Android Studio).

Nah
  • 1,690
  • 2
  • 26
  • 46