5

I am trying to implement an alarm based application in Android Q using a broadcast receiver. I am running a foreground service using notification for triggering the alarm broadcast receiver. The service is working fine and it is also triggering the broadcast receiver. If we close the application or lock the screen after setting an alarm, the service will be running in the foreground with a notification.

When the alarm broadcast is called I am trying to open a new activity when the screen is locked to provide the functionality to stop the alarm and service. I tried disabling the keyguard, turn on the screen and then opening the activity from the broadcast receiver, but I couldn't succeed.

I tried using WindowManager flags but they are deprecated and do not make any difference in the code.

WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON

Since I am trying to start an activity from a BroadcastReceiver I won't be having any Activity to use KeyguardManager.requestDismissKeyguard(Activity activity, KeyguardDismissCallback callback)

Is there any way to start an activity when the screen is locked to turn off the alarm. My implementation is given as follows,

I also added permissions in the manifest file.

AndroidManifest.xml

<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />

AlarmBroadcastReceiver.class

public class AlarmBroadcastReceiver extends BroadcastReceiver {
    public static MediaPlayer mp;
    public static Vibrator vibrator;

    private boolean isVibrationEnabled = false;

    @Override
    public void onReceive(Context context, Intent intent) {

        long[] mVibratePattern = new long[]{0, 400, 400, 400, 400, 400, 400, 400};
        final int[] mAmplitudes = new int[]{0, 128, 0, 128, 0, 128, 0, 128};

        isVibrationEnabled = intent.getExtras().getBoolean(LocationAlertService.IS_VIBRATE);

        mp=MediaPlayer.create(context, R.raw.ring1);
        mp.setLooping(true);
        mp.start();

        if(isVibrationEnabled) {
            vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                vibrator.vibrate(VibrationEffect.createWaveform(mVibratePattern, mAmplitudes, 0));
            } else {
                //deprecated in API 26
                vibrator.vibrate(mVibratePattern, 3);
            }
        }

        Intent wakeIntent = new Intent(context, WakeUpActivity.class);
        wakeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(wakeIntent);
    }
}

I know that I am missing something. I would be happy if there are any suggestions to overcome the issue which I am facing. Thanks in advance for helping me out.

Ram Keerthy
  • 227
  • 4
  • 16

1 Answers1

1

With Android Q, it is impossible to start an activity from background automatically if your app is not includes those exceptions listed in the link below. You can choose just show a service notification, and start pending intent with click.

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

To make the system work. The most possible solution in my view is adding "SYSTEM_ALERT_WINDOW" to manifest file. And ask for user permission once when the app opened 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:

 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 for your reply. I am trying to replicate the android's default alarm clock. Is it possible to show the alarm off and snooze UI like in the default alarm clock? If that is possible, can you guide me on how to implement that – Ram Keerthy Dec 19 '19 at 23:07
  • So you want to make it in lock screen? – Eren Tüfekçi Dec 19 '19 at 23:08
  • As far as I see, your approach is true. You just need the draw over other apps permission to make it work for Android 10+ devices. – Eren Tüfekçi Dec 19 '19 at 23:09
  • there must be other ways. Look at the google Clock app. They don't require that permission yet they can start activity on the lock screen. I don't even see WAKE_LOCK permission. How the hell on earth do they do it. It's been 1 week I am chasing after this issue – Alex Sep 14 '21 at 17:43
  • @Alex , they are the creators they can do anything they want :) – D_K Feb 09 '22 at 06:25
  • They probably are using, full-screen intents @D_K – Eren Tüfekçi Feb 10 '22 at 07:19