1

I am trying to setup an alarm that will remain on because I want it to go off 3 days from now and I know Android will kill my app before that.

In my Activity

private void setAlarm() {
    //ContactAlarmReceiver contactAlarmReceiver = new ContactAlarmReceiver();
    //contactAlarmReceiver.setAlarm(getApplicationContext(), dateInMillis, phonenumberET.getText().toString(), firstnameET.getText().toString());
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent alarmIntent = new Intent(MyConstants.BROADCAST_ACTION_CONTACT_ALARM);
    alarmIntent.putExtra("phone", phonenumberET.getText().toString());
    alarmIntent.putExtra("name", firstnameET.getText().toString());

    PendingIntent pi = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
    //am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMills, pi);
    if (Build.VERSION.SDK_INT >= 23) {
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dateInMillis, pi);
    } else if (Build.VERSION.SDK_INT >= 19) {
        am.setExact(AlarmManager.RTC_WAKEUP, dateInMillis, pi);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, dateInMillis, pi);
    }
    ComponentName component = new ComponentName(this, ContactAlarmReceiver.class);
    getPackageManager()
        .setComponentEnabledSetting(component,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);
}

Manifest:

<receiver
    android:name=".ContactAlarmReceiver"
    android:enabled="false">
    <intent-filter>
        <action android:name="com.example.johnbravado.CONTACTALARM" />
        <action android:name="com.example.johnbravado.NOTIFLTBTN" />
        <action android:name="com.example.johnbravado.NOTIFRTBTN" />
    </intent-filter>
</receiver>

ContactAlarmReceiver:

@Override
@Override
public void onReceive(Context context, Intent intent) {
    PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
    PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
            "com.example.johnbravado.zionwork");
    wakeLock.acquire();

    final NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    Bundle extras = intent.getExtras();
    ComponentName receiver = new ComponentName(context, ContactAlarmReceiver.class);
    PackageManager pm = context.getPackageManager();

    if (intent.getAction().equals(MyConstants.BROADCAST_ACTION_CONTACT_ALARM)) {
        int count = extras.size();
        String num = extras.getString("phone");
        String name = extras.getString("name");
        sendContactNotification(context, MyConstants.BIG_NOTIFICATION_ID, num, name);
    }

    if (intent.getAction().equals(MyConstants.BROADCAST_ACTION_NOTIF_LTBTN)) {
        sendSMS(context, extras.getString("phone"), extras.getString("msg"));
        mNotificationManager.cancel(MyConstants.BIG_NOTIFICATION_ID);
        pm.setComponentEnabledSetting(receiver,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }

    if (intent.getAction().equals(MyConstants.BROADCAST_ACTION_NOTIF_RTBTN)) {
        initiatePhone(context, intent.getExtras().getString("phone"));
        mNotificationManager.cancel(MyConstants.BIG_NOTIFICATION_ID);
        pm.setComponentEnabledSetting(receiver,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }
    wakeLock.release();
}

I never receive the notification after long periods of time. For example, I set the alarm at 11pm for 3am, so when i wake up i should see the notification. But there is no notification displayed.

John Bravado
  • 137
  • 4
  • 10
  • `ContactAlarmService` appears to be a `Service`, but you're using a `PendingIntent` that sends a broadcast, `PendingIntent.getBroadcast()`. – Mike M. Jan 14 '17 at 04:25
  • well the pending intent i want to fire when the alarm goes off is a broadcast. – John Bravado Jan 14 '17 at 04:27
  • Then you need a `BroadcastReceiver` class as the target; probably specifically a `WakefulBroadcastReceiver`. Then start your `Service` from that. – Mike M. Jan 14 '17 at 04:29
  • I had it working with a broadcastReceiver before but when app was killed receiver was killed. I cant figure out how to make it persist – John Bravado Jan 14 '17 at 04:33
  • Well, trying to broadcast to a `Service` class isn't the solution. Are you certain it's that your app is killed that's the problem? If your device is asleep when the alarm time occurs, you will need to account for that. You will have to use the appropriate `set*()` method, depending on the Android version, and acquire a wake lock when it fires - which the above-mentioned `WakefulBroadcastReceiver` class can help with. Have a look through the [`AlarmManager` docs](https://developer.android.com/reference/android/app/AlarmManager.html), and the `set*AndAllowWhileIdle()` methods. – Mike M. Jan 14 '17 at 04:51
  • 1
    Check out the following answer: http://stackoverflow.com/a/39739886/3363481 – earthw0rmjim Jan 14 '17 at 05:25
  • I believe you are right Mike it is the setAndAllow.... command i need but How did they do it before API23? i used earthw0rmjim example code he referenced to check for API version. Or before API23 am always was able to wake device from sleep and this is a result of the new doze feature? – John Bravado Jan 14 '17 at 12:32
  • Yep, basically. The reason those version differences exist is because they've been progressively getting more strict with `AlarmManager` use, since developers were abusing it, and killing users' batteries. Before API 23, there was no doze mode, and therefore no `set*AndAllowWhileIdle()` methods. Alarms would work pretty much like you'd expect, apart from the batching introduced in API 19, for which the exact/inexact methods were created. Kind of a pain, but _c'est la vie_. – Mike M. Jan 14 '17 at 13:25
  • So, once I register a listener, the listener should remain active until unregistered or force kill/reboot? Or is there a trick to keep the receiver active also since I am using a broadcast receiver to receive the alarm that is fired. It still did not activate after a 3 hour I did not touch my phone period. Does the receiver have to bregistered with the intent filter in the manifest for me to get the desired results? Right now I set intent and register the receiver programatically – John Bravado Jan 14 '17 at 14:46
  • Oh, yeah, you definitely need to register it in the manifest. Sorry about that. I shoulda asked that first. I'd just assumed you had it there already. My bad. Yeah, when you register a Receiver instance dynamically, it goes away when the `Context` - the `Activity` or `Service`, e.g. - you registered it on dies. If you register the Receiver class in the manifest, it will always be available for the system to start up an instance whenever it needs to. – Mike M. Jan 14 '17 at 15:06
  • I updated the code to use a broadcast receiever, see edited post as i changed it to the new current code, but it still diodnt fire at 3am – John Bravado Jan 15 '17 at 12:44

1 Answers1

2

I would like to suggest You that, first of all create a class like:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class AlarmReceiver extends BroadcastReceiver {

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

        if(intent.getAction().equals("startalarm")){
        intent = new Intent(context, Your_service.class);
        context.startService(intent);

}

    }
}

Note: If your alarm has to perform network task, then start a download service inside onRecieve() method of your alarm broadcast. Then,set AlarmReceiverclass in Intent.

Intent alarmIntent = new Intent(MyActivity.this, AlarmReceiver.class);

perhaps you will get out from your problem.

singh.indolia
  • 1,292
  • 13
  • 26
  • Are you ntelling me a broadcastreceiver should persist after the app is killed? i started with that anf it works until app is killed – John Bravado Jan 14 '17 at 04:47
  • Please look this post:http://stackoverflow.com/questions/5916859/how-to-save-alarm-after-app-killing – singh.indolia Jan 14 '17 at 04:56
  • I have looked at that and I can't figure out from the graph how to incorporate the service with a broadcast I will look more at though – John Bravado Jan 14 '17 at 04:58
  • Wait i give an example: – singh.indolia Jan 14 '17 at 05:07
  • Look my answer i edit it, first of all set an action on which you want to start your alarm then in AlarmReceiver class check it and then call your service, it will work after app killed. – singh.indolia Jan 14 '17 at 05:12
  • and also u can do like :Intent serviceIntent = new Intent(); serviceIntent.setAction("com.my.package.MyService"); context.startService(serviceIntent); – singh.indolia Jan 14 '17 at 05:13