jonny
jonny

Reputation: 313

Prevent/make it unathorized for user from changing Time in Settings

I have an alarm app, that when it's stopped and active, the alarm will still play on the set time. And when user returns to the app he/she can see the remaining time left on the alarm.

The methods and variables I use to set the time left for alarm is using pendingIntent and Alarm Manager and System.currentTimeMillis();

It all works perfectly fine. If the time is for example: 10:00 am and i set the alarm to be called at 10:40 am, then there is a countdown timer that shows the time left with the help of TextView, which is 40 minutes and it counts downwards till it reaches 0. When it has reached 0 the alarm is called.

However if the user goes to settings app in the smartphone and changes the system time to 9:00 am, while the alarm being active. Then if i return back to the alarm app, the Textview shows 100 minutes left. Since 10:40am - 9:00am = 100 minutes difference.

I want to prevent this from happening. Is there a way where I can prevent the user to change the system time while the alarm is active, or is there any other solution for this?

What I tried to do was to check wheter the System.currentTimeMillis(); in onStart(); is less than the savedprefs System.currentTimeMillis(); from onStop. If it's less then I want the Alarm to be called immediently.

However for it to work, the user has to go back to the alarm app after changing the system time, if the user don't go back then it wont work.

any solutions?

Upvotes: 0

Views: 445

Answers (1)

Veselin Davidov
Veselin Davidov

Reputation: 7081

Well you don't want to tell the person not to change his phone time. It's his choice not yours ;)

Also if a user sets the alarm to 10:40 and he says that the time is 9:00 there really are 100 minutes left. For example I have to wake up at 7 for work and set up an alarm but then I notice my time is 1 hour ahead. I move back time on my phone but I still want to wake up at 7 because that's when I have to go to work and the alarm interval increases.

So a correct behavior would be not to call it an alarm (based on time) but a timer - based on time left. For example if you set a timer for 40 minutes from now then no matter what the current time is the notification will go after 40 minutes.

In order to do that you need to set the countdown timer to a specific interval not depending on the system time. You can still use the system time for the initial calculation but for the subsequent calculations you shouldn't. So for example if the initial calculation tells you that your alarm should go wild after 30 minutes you can do something like that:

long initialTimeLeft= calculateTheTimeFromSystemTime(); // you write that ;)
new CountDownTimer(initialTimeLeft, 1000) {

    public void onTick(long millisUntilFinished) {
        broadcastRemainingTime();
    }

    public void onFinish() {
        broadcastTimerHasFinished();
    }

}.start();

And this will probably work as expected ;) The time doesn't depend on system time after the first iteration.

There is another issue which you might face like that though. In order to deal with that you will need to start that timer as a service and when the countdown finishes to sendBroadcast() and in the main app to create a BroadcastReceiver to receive that broadcast and turn on the music (or whatever your alarm does). In the onTick() event you can broadcast the remaining time and in your application you can receive that broadcasts and get the remaining time.

You don't want to update the time in onStart() and to do more calculations. Once you have started the timer and it works as a service let it handle the time calculations and in your main activity just worry about the display of the remaining time (getting it from the timer broadcast) and doing something when the alarm fires (also getting it from the timer broadcast)

If you don't use a timer as a service then you calculate time left like that:

 long timeLeftInMillis=initialTime;
 timer = new CountDownTimer(initialTime, 1000) {
       @Override
        public void onTick(long millisecondsUntilFinished) {
            timeleft = millisecondsUntilFinished;
        }
      }

In order to do the same with a broadcast service it will be something like:

 Intent bi = new Intent("ALARM_COUNTDOWN_INCOMING!");
 public void onTick(long millisecondsUntilFinished) {
                   bi.putExtra("timeleft ", millisUntilFinished);
                   sendBroadcast(bi);
            }

And in the main activity:

private BroadcastReceiver br = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {            
      long timeLeft = intent.getLongExtra("timeLeft ", 0);
      //Update the text view with that timeLeft
    }
};

Upvotes: 1

Related Questions