Smarter ideas worth writing about.

Android Countdown Timer

Background

We developed a mobile application for a conference that provided users with the conference agenda, speakers and bios, facility maps, and general information regarding the conference and hosting company. Because the agenda and speaker list could potentially change up until the morning of the conference, our client requested we lock the app down until an hour before the conference.

Due to the app being shipped to the users over a week before the conference, we needed to determine the best way to accomplish the following goals in an elegant way, without user interruption:

  1. Allow the user to log in and register for push notifications from the app
  2. Lock down the app until the designated time
  3. Seamlessly unlock the app at the designated time 

Solution

Our solution was the countdown timer.  Our developers and designers worked together to create a solution that meets the required goals, while causing no interruption to the user.  After successful login, the user is presented with the countdown timer:

At initial launch, the user was presented with a login screen.  After successful login, the user is presented with the countdown timer.  Logging in registered them with the Azure push notifications hub, so they would receive up-to-the-minute notifications regarding the conference.  The timer was customized with information specific to the customer (links to the conference location, company web site, questions link, etc.).   When the countdown expired, the timer closed and the user was presented with the “meat” of the application.

Technical Details

For this particular layout, I chose a relative layout with nested linear layouts with a horizontal orientation to hold the progress wheels, and the days/hours/minutes/seconds labels.  The progress wheels and labels inside the linear layouts are set to a 0dp width, and a weight of 1.  This allows them to fill across the screen in a uniform manner, with equal spacing between each item.  Here’s an example of the xml (some items omitted for brevity):

<LinearLayout 
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<com.todddavies.components.progressbar.ProgressWheel 
            		android:layout_width="0dp"    
            		android:layout_height="wrap_content"
            		android:layout_weight="1"/>

From our activity, we have to set up some integers so the timer knows when to stop.  
*Note, we’re using an android Time object, and the month is zero based (0-11), so August would be 7:

// Timer setup
Time conferenceTime = new Time(Time.getCurrentTimezone());
int hour = 22;
int minute = 33;
int second = 0;
int monthDay = 28;
// month is zero based...7 == August
int month = 7;
int year = conferenceTime.year;
// 

To actually run the countdown, we’re using an Android CountdownTimer object. That object takes the following arguments:

  1. Difference (in milliseconds) between now, and when the timer stops
  2. Interval to receive updates(1000 is default)

To calculate our difference between now and end time, we do a little math:

// second, minute, hour, monthDay, month, year declared above
conferenceTime.set(second, minute, hour, monthDay, month, year);
// normalize ensures the values in the date object are in range
conferenceTime.normalize(true);
// convert conference time to milliseconds
long confMillis = conferenceTime.toMillis(true);

// Get a Time object for now so we know what our start time is
Time nowTime = new Time(Time.getCurrentTimezone());
nowTime.setToNow();
nowTime.normalize(true);
long nowMillis = nowTime.toMillis(true);

// get the difference between conference time and now
long milliDiff = confMillis - nowMillis;


Now, here’s where the real magic happens.  First, we need to create a new CountdownTimer object with our millisecond time difference:

new CountDownTimer(milliDiff, 1000) {
}.start();

Inside that object, there are two methods we have to override to manipulate our progress wheels, and close our activity when the time comes:

@Override
public void onTick(long millisUntilFinished) {

}
@Override
public void onFinish() {
Logger.d(TAG, "Timer Finished...");
	// This is where you would launch the next activity
	closeActivity();
}

Finally, inside the overridden onTick, we update each progress wheel accordingly:

// decompose difference into days, hours, minutes and seconds
mDisplayDays = (int) ((millisUntilFinished / 1000) / 86400);
mDisplayHours = (int) (((millisUntilFinished / 1000) - (CountdownTimerActivity.this.mDisplayDays * 86400)) / 3600);
mDisplayMinutes = (int) (((millisUntilFinished / 1000) - ((CountdownTimerActivity.this.mDisplayDays * 86400) + (CountdownTimerActivity.this.mDisplayHours * 3600))) / 60);
mDisplaySeconds = (int) ((millisUntilFinished / 1000) % 60);

mDaysWheel.setText(String.valueOf(CountdownTimerActivity.this.mDisplayDays));
mDaysWheel.setProgress(CountdownTimerActivity.this.mDisplayDays);
mHoursWheel.setText(String.valueOf(CountdownTimerActivity.this.mDisplayHours));
mHoursWheel.setProgress(CountdownTimerActivity.this.mDisplayHours * 15);
mMinutesWheel.setText(String.valueOf(CountdownTimerActivity.this.mDisplayMinutes));
.mMinutesWheel.setProgress(CountdownTimerActivity.this.mDisplayMinutes * 6);
mSecondsWheel.setText(String.valueOf(CountdownTimerActivity.this.mDisplaySeconds));
mSecondsWheel.setProgress(CountdownTimerActivity.this.mDisplaySeconds * 6);

To download a sample app and see how all this works together, check out our Github:

Link: https://github.com/CardinalNow/Android-CountdownTimer

Share:

About The Author

Shane is a Principal Developer II in Cardinal's Cincinnati office who is currently focused on mobile applications development and Azure mobile back end services (NodeJS).