Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android AlarmManager to continue after reboot / removed from RecentTaskManager

I would like to implement sending notification to users from server using AlarmManager at the time user pre-set before. Code is as follows:

MainActivity:

public void set_Retrival_then_notifcation_Alarm(Context context, int year, int month, int day, int hour, int min, int sec) 
    {
        Calendar updateTime = Calendar.getInstance();
        updateTime.setTimeZone(TimeZone.getDefault());
        updateTime.set(Calendar.YEAR, year);
        updateTime.set(Calendar.MONTH, month-1);
        updateTime.set(Calendar.DATE, day);
        updateTime.set(Calendar.HOUR_OF_DAY, hour);
        updateTime.set(Calendar.MINUTE, min);
        updateTime.set(Calendar.SECOND, sec);
        Intent downloader = new Intent(context, AlarmBroadcastReceiver.class);
        downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);           
        alarmManager.set(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), pendingIntent);                        
    }

ParseService:

public class ParseService extends IntentService 
{
    static String Parse_AppID = "abc";  
    static String Parse_ClientKey = "abckey";
    String notification_next_price = "";
    String notification_next_date = "";
    SharedPreferences settings;

    public class LocalBinder extends Binder 
    {
        public ParseService getService() 
        {
            return ParseService.this;
        }
    }

    public ParseService() 
    {
        super("ParseService");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent,flags,startId);
        return START_STICKY ;
    }

    @Override
    protected void onHandleIntent(Intent intent) 
    {
        Log.d("MyService", "About to execute MyTask");
        new MyTask().execute();
    }

    private class MyTask extends AsyncTask<String, Void, Boolean> 
    {
        @Override
        protected Boolean doInBackground(String... strings) 
        {
            Log.d("MyService - MyTask", "Calling doInBackground within MyTask");
            initParse(ParseService.this);
            get_notification_info(ParseService.this);
            return false;
        }
    }

    private void sendNotification(Context context, String title, String content) 
    {
        Log.d("MyService - MyTask", "A - sendNotification");
        settings = context.getSharedPreferences("MyApp",0);
        boolean notify_is_on = settings.getBoolean("notify_is_on", true);
        int saved_amount = settings.getInt("saved_amount", 800);

        NumberFormat numberFormat = NumberFormat.getInstance();
        int k = 0;
        try
        {
            k = numberFormat.parse(notification_next_price).intValue();
            if (notify_is_on && (k >= (saved_amount*10000)))
            {
                setNotificationContent(context, k, ""+title, content + "");
            }
            else
            {
                Toast.makeText(getApplicationContext(), "No need notification", Toast.LENGTH_SHORT).show();
            }
        }
        catch (Exception ex)
        {
            setNotificationContent(context, k, "Title2", "Content2");
        }
    } 

    public void setNotificationContent(Context context, int k, String title, String content)
    {
        Intent notificationIntent = new Intent(context, CurrentResult.class);
        PendingIntent pi = PendingIntent.getActivity(context, 0, notificationIntent, 0);
        Notification noti = new Notification.Builder(context)
            .setTicker("Hello")
            .setSmallIcon(R.drawable.b06)
            .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher))
            .setAutoCancel(true)
            .setOngoing(true) 
            .setOnlyAlertOnce(true)
            .setContentTitle(""+title)
            .setContentText(""+content)
            .setContentIntent(pi)
         .build();

        startForeground(1337, noti);

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, noti);

        stopSelf();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    public void initParse(Context context) 
    {
        try 
        {
            ...connection to Parse.com
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

    public void get_notification_info(Context context)
    {       
        ParseQuery<ParseObject> query = ParseQuery.getQuery("Record_db");
        //....getting records from server
        sendNotification(ParseService.this, ""+notification_next_price, ""+notification_next_date);
                    }                   
                } 
                else 
                {
                    Toast.makeText(getApplicationContext(), "Getting server content error", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

AlarmBroadcastManager

public class AlarmBroadcastReceiver extends BroadcastReceiver 
{
    public AlarmBroadcastReceiver () {
    }

    @Override
     public void onReceive(Context context, Intent intent) 
     {
         Intent dailyUpdater = new Intent(context, ParseService.class); 
         context.startService(dailyUpdater);
         Log.d("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive");
     }
}

Manifest:

<service android:name="com.abc.abc.ParseService" 
                android:enabled="true"
                android:exported="true" />
        <receiver 
            android:name="com.abc.abc.AlarmBroadcastReceiver"
            android:enabled="true"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>         

Question:

The fetching records from server and sending to notification are working properly when the app is in the recent task list.

However, if the app is manually removed from the recent task list, the alarmManager and hence the notification are cancelled and no notification is thereby received.

I have googled and most solution are to return START_STICKY in onStartCommand, to register in Manifest, but I have tried with no success.

Could you please help see what the problem is? Why the notification cannot be rebooted after the app is manually removed from the recent task list? Are there any example such that this ParseService is working at the user's pre-set time?

Thanks!

like image 677
pearmak Avatar asked Nov 15 '16 16:11

pearmak


2 Answers

  • You need to store the registered alarms in a local db
  • then create an on boot completed receiver
    • in this receiver load all alarms and register them again
  • in AlarmBroadcastReceiver class delete this alarm from the db

thats it

like image 57
Hossam Alaa Avatar answered Sep 27 '22 17:09

Hossam Alaa


Instead of AlarmManager you should use GcmListenerService this will get notify even your app is removed from the task manager, GcmListenerService

like image 39
Sanat Chandravanshi Avatar answered Sep 27 '22 17:09

Sanat Chandravanshi