Android – How to create persistent alarms even after rebooting

androidandroid-alarmsandroid-notifications

Presently, I am working on app that works like "To Do Task List". I have successfully implemented the NotificationService and SchedularService in my application. Also I am getting the alerts(Notifications) at the time set for the tasks.
Here are my queries as below:

  1. With this code will my alarms will be deleted after reboot ? If yes, how to overcome this.
  2. I have kept the Priority feature for the tasks. But i want the mechanism such that if user selects priority "High" then he should receive notifications thrice, say, before 30 minutes, before 15 minutes and on the time set. How to achieve this ?
  3. I want to set Phone's vibrate feature when Notifications are raised. How to achieve this ?
  4. And i want to know about, what can be done for the deprecated methods and constructor in NotifyService.java. Thesse are deprecated in API level 11: Notification notification = new Notification(icon, text, time); and notification.setLatestEventInfo(this, title, text, contentIntent);. On developer.android.com, they have suggested to Use Notification.Builder instead. So how to make my app compatible with all the API levels.

Here's my snippet code for scheduling alarm:

...
scheduleClient.setAlarmForNotification(c, tmp_task_id);
...

Here's the class ScheduleClient.java:

public class ScheduleClient {

    private ScheduleService mBoundService;
    private Context mContext;
    private boolean mIsBound;

    public ScheduleClient(Context context)
    {
        mContext = context;
    }

    public void doBindService()
    {   
        mContext.bindService(new Intent(mContext, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {

            mBoundService = ((ScheduleService.ServiceBinder) service).getService();
        }

        public void onServiceDisconnected(ComponentName className) {

            mBoundService = null;
        }
    };

    public void setAlarmForNotification(Calendar c, int tmp_task_id){

        mBoundService.setAlarm(c, tmp_task_id);
    }

    public void doUnbindService() {
        if (mIsBound)
        {           
            mContext.unbindService(mConnection);
            mIsBound = false;
        }
    }
}

Here's the ScheduleService.java:

public class ScheduleService extends Service {

    int task_id;

    public class ServiceBinder extends Binder {

        ScheduleService getService() {

            return ScheduleService.this;
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {

        return mBinder;
    }

    private final IBinder mBinder = new ServiceBinder();

    public void setAlarm(Calendar c, int tmp_task_id) {

        new AlarmTask(this, c, tmp_task_id).run();
    }
}

Here's the AlarmTask.java:

public class AlarmTask implements Runnable{

    private final Calendar date;
    private final AlarmManager am;
    private final Context context;
    int task_id;

    public AlarmTask(Context context, Calendar date, int tmp_task_id) {
        this.context = context;
        this.am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        this.date = date;

        task_id = tmp_task_id;
    }

    @Override
    public void run() {

        Intent intent = new Intent(context, NotifyService.class);
        intent.putExtra(NotifyService.INTENT_NOTIFY, true);
        intent.putExtra("task_id", task_id);
        PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);

        am.set(AlarmManager.RTC, date.getTimeInMillis(), pendingIntent);
    }
}

Here's the NotifyService.java:

public class NotifyService extends Service {

    public class ServiceBinder extends Binder
    {   
        NotifyService getService()
        {
            return NotifyService.this;
        }
    }

    int task_id;
    private static final int NOTIFICATION = 123;
    public static final String INTENT_NOTIFY = "com.todotaskmanager.service.INTENT_NOTIFY";
    private NotificationManager mNM;
    SQLiteDatabase database;

    @Override
    public void onCreate() {

        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String tmp_task_brief = null;
        task_id = intent.getIntExtra("task_id", 0);

        loadDatabase();
        Cursor cursor = database.query("task_info", new String[]{"task_brief"}, "task_id=?", new String[]{task_id+""}, null, null, null);
        while(cursor.moveToNext())
        {
            tmp_task_brief = cursor.getString(0);
        }
        cursor.close();

        if(intent.getBooleanExtra(INTENT_NOTIFY, false))
            showNotification(tmp_task_brief);

        return START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {

        return mBinder;
    }

    private final IBinder mBinder = new ServiceBinder();

    private void showNotification(String tmp_task_brief) {

        CharSequence title = "To Do Task Notification!!";
        int icon = R.drawable.e7ca62cff1c58b6709941e51825e738f;
        CharSequence text = tmp_task_brief;     
        long time = System.currentTimeMillis();

        Notification notification = new Notification(icon, text, time);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, TaskDetails.class), 0);

        notification.setLatestEventInfo(this, title, text, contentIntent);

        notification.flags |= Notification.FLAG_AUTO_CANCEL;

        mNM.notify(NOTIFICATION, notification);

        stopSelf();
    }

    void loadDatabase()
    {
        database = openOrCreateDatabase("ToDoDatabase.db",
                SQLiteDatabase.OPEN_READWRITE, null);
    }
}

Best Solution

With this code will my alarms will be deleted after reboot ? If yes, how to overcome this.

Yes alarm will get deleted, to overcome this, you need to use Android's Component called BroadcastReceiver as follows,

First, you need the permission in your manifest:

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

Also, in your manifest, define your service and listen for the boot-completed action:

<receiver
    android:name=".receiver.StartMyServiceAtBootReceiver"
    android:enabled="true"
    android:exported="true"
    android:label="StartMyServiceAtBootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

Then you need to define the receiver that will get the BOOT_COMPLETED action and start your service.

public class StartMyServiceAtBootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
            Intent serviceIntent = new Intent("com.myapp.NotifyService");
            context.startService(serviceIntent);
        }
    }
}

And now your service should be running when the phone starts up.

2 For Vibration

Again you need to define a permission in AndroidManifest.xml file as follows,

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

Here is the code for vibration,

// Get instance of Vibrator from current Context
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

// Vibrate for 300 milliseconds
v.vibrate(300);
Related Question