28

I want an activity to be displayed at a certain time. For this, I am using AlarmManager. It works fine when the device is awake, but it doesn't wake it up if it's asleep.

My code for setting the alarm:

Calendar alarmTime = Calendar.getInstance();
alarmTime.set(Calendar.HOUR_OF_DAY, alarm.hour);
alarmTime.set(Calendar.MINUTE, alarm.minute);
alarmTime.set(Calendar.SECOND, 0);

if (alarmTime.before(now))
    alarmTime.add(Calendar.DAY_OF_MONTH, 1);

Intent intent = new Intent(ctxt, AlarmReceiver.class);
intent.putExtra("alarm", alarm);
PendingIntent sender = PendingIntent.getBroadcast(ctxt, alarm.id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime.getTimeInMillis(), sender);

My broadcast receiver:

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

Bundle bundle = intent.getExtras();
final Alarm alarm = (Alarm) bundle.getSerializable("alarm");

Intent newIntent;
if (alarm.type.equals("regular")) {
    newIntent = new Intent(context, RegularAlarmActivity.class);
} else if (alarm.type.equals("password")) {
    newIntent = new Intent(context, PasswordAlarmActivity.class);
} else if (alarm.type.equals("movement")) {
    newIntent = new Intent(context, MovementAlarmActivity.class);
} else {
    throw new Exception("Unknown alarm type");
}
    newIntent.putExtra("alarm", alarm);
    newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(newIntent);

} catch (Exception e) {
    Toast.makeText(context, "There was an error somewhere, but we still received an alarm", Toast.LENGTH_SHORT).show();
    Log.e("AlarmReceiver", Log.getStackTraceString(e));
}
}

This code doesn't wake the device on. However, when I turn it back again, they are displayed. I need to make them turn the screen on. Can you help me with this problem?

Gabriel
  • 2,054
  • 4
  • 26
  • 34
  • Go to the Activity which you want to start in onReceive(). Paste this in onCreate() of that Activity final Window win= getWindow(); win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); – Junaid Jul 30 '15 at 17:38

3 Answers3

58

I had a similar problem and the solution was to use WakeLocker. That should be done (preferably as the 1st thing in the receiver), or the device will wake up when the alarm is received, but will fall asleep again before context.startActivity(newIntent); is called. (I have also observed behavior when that does not happen, so it seems to be a bit arbitrary) So the easy and quick answer: Make a new class called WakeLocker with this source code:

package mypackage.test;

import android.content.Context;
import android.os.PowerManager;

public abstract class WakeLocker {
    private static PowerManager.WakeLock wakeLock;

    public static void acquire(Context ctx) {
        if (wakeLock != null) wakeLock.release();

        PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
                PowerManager.ACQUIRE_CAUSES_WAKEUP |
                PowerManager.ON_AFTER_RELEASE, MainActivity.APP_TAG);
        wakeLock.acquire();
    }

    public static void release() {
        if (wakeLock != null) wakeLock.release(); wakeLock = null;
    }
}

and in your receiver call WakeLocker.acquire(context); as the 1st thing. Extra: it would also be neat to call WakeLocker.release(); once your alarm has done its thing.

prostynick
  • 6,129
  • 4
  • 37
  • 61
user859593
  • 612
  • 6
  • 7
  • 2
    Thank you very much. Now, the phone finally wakes up at the specified time. I also like a lot the static approach of the WakeLocker class. – Gabriel Jul 29 '11 at 14:37
  • 9
    requires permission http://developer.android.com/reference/android/os/PowerManager.html – Palani Jul 26 '12 at 18:26
  • Thank you, that's great. But it still didn't work until I found that my phone (Asus Zenfone Selfie) requires me to explicitly allow the app to be waken up. – cpliu338 Aug 14 '16 at 15:08
  • the alarm even does not call its receiver!! – EsmaeelQash Oct 29 '16 at 09:58
  • would duplicate calls to acquire do any harm as your methods are static? lets say you acquire multiple times but only release 1 time – 2cupsOfTech Jul 14 '17 at 16:26
30

Most likely, the alarm is waking up the device. However, AlarmManager broadcasts won't turn the screen on, and the device may well fall back asleep before your activity starts up.

You will need to acquire a WakeLock in onReceive() before calling startActivity(), and release that WakeLock after the user responds to your activity.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • have you tested this? The screen turns on as well without the need to acquire a WakeLock – 2cupsOfTech Jul 14 '17 at 16:23
  • @2cupsOfTech: "have you tested this?" -- yes. "The screen turns on as well without the need to acquire a WakeLock" -- `AlarmManager` broadcasts do not turn on the screen. Without a `WakeLock` (e.g., using `getService()` as a `PendingIntent`, then grabbing a `WakeLock` in the service) is unreliable. It will work sometimes and not others. This is why I released the `WakefulIntentService` and why Google followed that up with the `WakefulBroadcastReceiver`. – CommonsWare Jul 14 '17 at 16:36
  • @CommonsWare a clarification I'm talking in reference to starting an activity (not service) so perhaps your results are only applicable for service? – 2cupsOfTech Jul 14 '17 at 20:37
  • @2cupsOfTech: Starting an activity directly from `AlarmManager` by way of `setAlarmClock()` might work, and I have no idea what behavior to expect there. Starting an activity directly from `AlarmManager` via other methods (e.g., `set()`) is not advisable. From the beginning, the only (undocumented) guarantee we had with `AlarmManager` was that if you used a broadcast `PendingIntent`, `AlarmManager` would keep the device awake long enough for `onReceive()` to process. Anything else, all bets are off. If they have modified their undocumented guarantee, I am not aware of it. – CommonsWare Jul 14 '17 at 20:42
  • @CommonsWare I did a test with starting activity, I would say the results are unreliable at-least with deep doze mode – 2cupsOfTech Jul 15 '17 at 01:53
8

For Services (maybe works for activity as well), extend your AlarmReceiver from WakefulBroadcastReceiver, it acquires WAKE_LOCK for you while intent is being processed.

WakefulBroadcastReceiver docs - https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html

Keeping device awake guide - https://developer.android.com/training/scheduling/wakelock.html

Kof
  • 23,893
  • 9
  • 56
  • 81