1

I am trying to create a countdown timer that runs even when the app is killed or when the phone is turned off. For example, let's say I run my countdown timer to count down from 5 hours. When I turned it off it resets to zero. I want it so that when I start counting it down from 5 hours and turn my phone for one hour and turn it back on, the timer shows four hours as the time remaining. I am looking into services and multithreading but haven't been able to produce or find a solution that will work for me.

In Android i want to run countdown timer who can run in background also

Implementing a Count down timer using Service in the background

Here is my code segment:

start_timer.setOnClickListener(new View.OnClickListener() {


    @Override
    public void onClick(View view) {

        new AlertDialog.Builder( MainActivity.this )
                .setMessage( "Are you sure you want to block the selected apps for the set amount of time?" )
                .setPositiveButton( "Yeah man!", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        Log.d( "AlertDialog", "Positive" );

                        hourint = Integer.valueOf(number_text.getText().toString());

                        minuteint = Integer.valueOf(minute_text.getText().toString());

                        secondint = Integer.valueOf(second_text.getText().toString());

                        Log.i("YourActivity", "Hours: " + hourint);

                        Log.i("YourActivity", "Minutes: " + minuteint);

                        Log.i("YourActivity", "Seconds: " + secondint);

                        totalTimeCountInMilliseconds = ((hourint*60*60) +(minuteint*60) + (secondint)) * 1000;      // time count
                        timeBlinkInMilliseconds = 30*1000;

                        countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
                            // 500 means, onTick function will be called at every 500 milliseconds

                            @Override
                            public void onTick(long leftTimeInMilliseconds) {
                                long seconds = leftTimeInMilliseconds / 1000;
                                mSeekArc.setVisibility(View.INVISIBLE);
                                start_timer.setVisibility(View.INVISIBLE);
                                block_button1.setVisibility(View.INVISIBLE);



                                if ( leftTimeInMilliseconds < timeBlinkInMilliseconds ) {
                                    // textViewShowTime.setTextAppearance(getApplicationContext(), R.style.blinkText);
                                    // change the style of the textview .. giving a red alert style

                                    if ( blink ) {
                                        number_text.setVisibility(View.VISIBLE);
                                        minute_text.setVisibility(View.VISIBLE);
                                        second_text.setVisibility(View.VISIBLE);


                                        // if blink is true, textview will be visible
                                    } else {
                                        number_text.setVisibility(View.INVISIBLE);
                                        minute_text.setVisibility(View.INVISIBLE);
                                        second_text.setVisibility(View.INVISIBLE);


                                    }

                                    blink = !blink;         // toggle the value of blink
                                }

                                second_text.setText(String.format("%02d", seconds % 60));
                                minute_text.setText(String.format("%02d", (seconds / 60) % 60));
                                number_text.setText(String.format("%02d", seconds / 3600));                     // format the textview to show the easily readable format
                            }


                            @Override
                            public void onFinish() {
                                // this function will be called when the timecount is finished
                                //textViewShowTime.setText("Time up!");
                                number_text.setVisibility(View.VISIBLE);
                                minute_text.setVisibility(View.VISIBLE);
                                second_text.setVisibility(View.VISIBLE);
                                mSeekArc.setVisibility(View.VISIBLE);
                                start_timer.setVisibility(View.VISIBLE);
                                block_button1.setVisibility(View.VISIBLE);


                            }

                        }.start();
                    }
                })
                .setNegativeButton( "Nope!", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        Log.d( "AlertDialog", "Negative" );
                        dialog.cancel();
                    }
                } )
                .show();

How can I achieve this and what modifications do I have to make to my code?

EDIT: HERE IS MY FULL CODE:

http://pastebin.com/pth9KZWP

EDIT 2: HERE IS REVISED CODE:

My app cannot start. And I don't receive any logcat statements so I am not sure what to do...

http://pastebin.com/L8HgGtsy

Community
  • 1
  • 1
Rohit Tigga
  • 2,373
  • 9
  • 43
  • 81
  • 1
    you need to write the current time(also date would be better) into some persistent storage when the phone is about to shut-down. Once the phone restarts, check the `current time - the time phone was shut down`.Then check `countdownTime - ( current time - the time phone was shut down)`. If this is positive, you can set the new value of countDownTime – TheLostMind Aug 21 '14 at 06:29
  • Thanks for the idea, I am getting some direction here. So I am trying to structure this right now. I am kind of understanding where are you going this. Is it possible for you clarify the conditional statement : "Once the phone restarts, check the current time - the time phone was shut down". Why would it be current time minus time phone shut down? Won't it always be positive? May need a bit more explanation. – Rohit Tigga Aug 21 '14 at 19:45
  • assume your countdown timer has 10 hours left when you switch your phone off. Now if you switch off your phone at 1 PM and turn it on at 5 pm. Then, 5-1=4. you have to subtract 4 from 10. i.e, 6 will be the current count down time. – TheLostMind Aug 22 '14 at 05:17
  • How would I store the value when the phone gets turned off? I can store everything else with SharedPreferences but how would I achieve that? Does it account for time zone changes? – Rohit Tigga Aug 22 '14 at 18:39
  • 1
    @Hereisthehelpfullink Use the timestamp in GMT -- timezones won't be relevant then. However, you should look into hitting an NTP server for accurate time (as `System.currentTimeMillis()` changes according to the user's Date/Time settings, which might be incorrect) – Kevin Coppock Aug 22 '14 at 21:04

2 Answers2

2

After the countdown time is entered, calculate when the countdown will end and write that to persistent storage. Then any time the app starts back up, read that time and calculate how much time is left from now.

Ted Bigham
  • 4,237
  • 1
  • 26
  • 31
  • What exactly should I use to achieve that? – Rohit Tigga Aug 21 '14 at 06:33
  • 1
    http://developer.android.com/training/basics/data-storage/files.html. Follow the instruction for "internal file" – Ted Bigham Aug 21 '14 at 06:35
  • 2
    If you are only going to write a date you can write it as a long. Easiest way would probably be to use SharedPreferences, example: http://stackoverflow.com/a/3624358/1137118 – Pphoenix Aug 21 '14 at 06:37
  • So I write the date to SharedPreferences, when the app is killed. Write code to figure out how much time has elapsed since the last date when the app is re-opened. And then set the time there? You guys make it sound so simple when the implementation isn't. LOL. Hmm but should I use SharedPreferences or internal file storage? – Rohit Tigga Aug 21 '14 at 19:18
  • I would not wait for the app to close to write it. I would write it as soon as it's entered, so you don't have to hook into anything during close. Also, if you're writing the END time, then you don't need to calculate how much time has elapsed. You'll have enough information just with that to know what to display to the user. – Ted Bigham Aug 22 '14 at 00:24
  • Notice how I have an onClickListener to start the timer. I am able to get the start time and end time in milliseconds and store it in sharedpreferences. The problem is that I don't know how to override the time I have counting down because this is all done in a start_timer button onClickListener? Where can I go from here because I have all the values I just am unable to edit the countdown timer value... – Rohit Tigga Aug 22 '14 at 01:46
  • Because the timer starts only when I press the button. So if I am thinking about this correctly, if the application is closed...the timer won't be started again automatically when the app is reopened unless the user hits the start timer button.... – Rohit Tigga Aug 22 '14 at 01:50
  • When your app starts up or resumes, check shared storage. If there's a time in there that's past the current time, then it should appear to the user that the timer is still running. At that point you should be able to re-create your Countdown object using that value. If you need to know the original "total" time, then just store that too. – Ted Bigham Aug 22 '14 at 06:59
0

I figured it out to anyone having the same problem ;)

Here is retrieving the SharedPreferences at the top of the class in onCreate

startimerPreferences = getPreferences(MODE_APPEND);

Date startDate = new Date(startimerPreferences.getLong("time", 0));
timerstarted = startDate.getTime();
Log.e("This is the start time!!!!!:  ", timerstarted + "");


endTimerPreferences = getPreferences(MODE_APPEND);
Date endDate = new Date(endTimerPreferences.getLong("time", 0));
timerends = endDate.getTime();
Log.e("This is the end time!!!!!:  ", timerends + "");


Date openagain = new Date(System.currentTimeMillis());
reopened = openagain.getTime();

Here if there is still time remaining start the timer with that time remaining:

    if(timerstarted > 0)
    {
        if(reopened <timerends){
            //start countdown timer with new time.
            //set countdowntime to timerends-reopen.

            newtotalTimeCountInMilliseconds = timerends-reopened;
            countDownTimer = new CountDownTimer(newtotalTimeCountInMilliseconds, 500) {
                // 500 means, onTick function will be called at every 500 milliseconds

                @Override
                public void onTick(long leftTimeInMilliseconds) {

                    long seconds = leftTimeInMilliseconds / 1000;
                    mSeekArc.setVisibility(View.INVISIBLE);
                    start_timer.setVisibility(View.INVISIBLE);
                    block_button1.setVisibility(View.INVISIBLE);


                    if (leftTimeInMilliseconds < timeBlinkInMilliseconds) {
                        // textViewShowTime.setTextAppearance(getApplicationContext(), R.style.blinkText);
                        // change the style of the textview .. giving a red alert style

                        if (blink) {
                            number_text.setVisibility(View.VISIBLE);
                            minute_text.setVisibility(View.VISIBLE);
                            second_text.setVisibility(View.VISIBLE);


                            // if blink is true, textview will be visible
                        } else {
                            number_text.setVisibility(View.INVISIBLE);
                            minute_text.setVisibility(View.INVISIBLE);
                            second_text.setVisibility(View.INVISIBLE);


                        }

                        blink = !blink;         // toggle the value of blink
                    }

                    second_text.setText(String.format("%02d", seconds % 60));
                    minute_text.setText(String.format("%02d", (seconds / 60) % 60));
                    number_text.setText(String.format("%02d", seconds / 3600));                     // format the textview to show the easily readable format
                }


                @Override
                public void onFinish() {
                    // this function will be called when the timecount is finished
                    //textViewShowTime.setText("Time up!");
                    number_text.setVisibility(View.VISIBLE);
                    minute_text.setVisibility(View.VISIBLE);
                    second_text.setVisibility(View.VISIBLE);
                    mSeekArc.setVisibility(View.VISIBLE);
                    start_timer.setVisibility(View.VISIBLE);
                    block_button1.setVisibility(View.VISIBLE);


                }

            }.start();



        }
    }

Here is the initial timer with the user submitting the action. I have the current time and end time committed and saved in SharedPreferences.

start_timer.setOnClickListener(new View.OnClickListener() {


            @Override
            public void onClick(View view) {

                new AlertDialog.Builder( MainActivity.this )
                        .setMessage( "Are you sure you want to block the selected apps for the set amount of time?" )
                        .setPositiveButton("Yeah man!", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                Log.d("AlertDialog", "Positive");

                                hourint = Integer.valueOf(number_text.getText().toString());

                                minuteint = Integer.valueOf(minute_text.getText().toString());

                                secondint = Integer.valueOf(second_text.getText().toString());

                                Log.i("YourActivity", "Hours: " + hourint);

                                Log.i("YourActivity", "Minutes: " + minuteint);

                                Log.i("YourActivity", "Seconds: " + secondint);

                                Date currenttime = new Date(System.currentTimeMillis());

                                timerstarted = currenttime.getTime();
                                Log.e("This is the current time:  ", timerstarted + "");
                                startimerPreferences = getPreferences(MODE_APPEND);
                                SharedPreferences.Editor starteditor = startimerPreferences.edit();
                                starteditor.putLong("time", timerstarted);
                                starteditor.commit();


                                Date endtime = new Date(System.currentTimeMillis());

                                timerends = endtime.getTime() + (((hourint * 60 * 60) + (minuteint * 60) + (secondint)) * 1000);
                                Log.e("This is the end time:  ", timerends + "");
                                endTimerPreferences = getPreferences(MODE_APPEND);
                                SharedPreferences.Editor endeditor = endTimerPreferences.edit();
                                endeditor.putLong("time", timerends);
                                endeditor.commit();









                                totalTimeCountInMilliseconds = (((hourint * 60 * 60) + (minuteint * 60) + (secondint)) * 1000);      // time count
                                timeBlinkInMilliseconds = 30 * 1000;

                                countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
                                    // 500 means, onTick function will be called at every 500 milliseconds

                                    @Override
                                    public void onTick(long leftTimeInMilliseconds) {

                                        long seconds = leftTimeInMilliseconds / 1000;
                                        mSeekArc.setVisibility(View.INVISIBLE);
                                        start_timer.setVisibility(View.INVISIBLE);
                                        block_button1.setVisibility(View.INVISIBLE);


                                        if (leftTimeInMilliseconds < timeBlinkInMilliseconds) {
                                            // textViewShowTime.setTextAppearance(getApplicationContext(), R.style.blinkText);
                                            // change the style of the textview .. giving a red alert style

                                            if (blink) {
                                                number_text.setVisibility(View.VISIBLE);
                                                minute_text.setVisibility(View.VISIBLE);
                                                second_text.setVisibility(View.VISIBLE);


                                                // if blink is true, textview will be visible
                                            } else {
                                                number_text.setVisibility(View.INVISIBLE);
                                                minute_text.setVisibility(View.INVISIBLE);
                                                second_text.setVisibility(View.INVISIBLE);


                                            }

                                            blink = !blink;         // toggle the value of blink
                                        }

                                        second_text.setText(String.format("%02d", seconds % 60));
                                        minute_text.setText(String.format("%02d", (seconds / 60) % 60));
                                        number_text.setText(String.format("%02d", seconds / 3600));                     // format the textview to show the easily readable format
                                    }


                                    @Override
                                    public void onFinish() {
                                        // this function will be called when the timecount is finished
                                        //textViewShowTime.setText("Time up!");
                                        number_text.setVisibility(View.VISIBLE);
                                        minute_text.setVisibility(View.VISIBLE);
                                        second_text.setVisibility(View.VISIBLE);
                                        mSeekArc.setVisibility(View.VISIBLE);
                                        start_timer.setVisibility(View.VISIBLE);
                                        block_button1.setVisibility(View.VISIBLE);


                                    }

                                }.start();
                            }
                        })
                        .setNegativeButton("Nope!", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                Log.d("AlertDialog", "Negative");
                                dialog.cancel();
                            }
                        })
                        .show();
Rohit Tigga
  • 2,373
  • 9
  • 43
  • 81