Home | History | Annotate | Download | only in system
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tv.settings.system;
     18 
     19 import com.android.tv.settings.ActionBehavior;
     20 import com.android.tv.settings.ActionKey;
     21 import com.android.tv.settings.BaseSettingsActivity;
     22 import com.android.tv.settings.R;
     23 import com.android.tv.settings.util.SettingsHelper;
     24 import com.android.tv.settings.dialog.old.Action;
     25 import com.android.tv.settings.dialog.old.ActionAdapter;
     26 import com.android.tv.settings.dialog.old.ActionFragment;
     27 import com.android.tv.settings.dialog.old.ContentFragment;
     28 import com.android.tv.settings.widget.picker.DatePicker;
     29 import com.android.tv.settings.widget.picker.TimePicker;
     30 import com.android.tv.settings.widget.picker.Picker;
     31 import com.android.tv.settings.widget.picker.PickerConstant;
     32 
     33 import org.xmlpull.v1.XmlPullParserException;
     34 
     35 import android.app.AlarmManager;
     36 import android.content.BroadcastReceiver;
     37 import android.content.Context;
     38 import android.content.Intent;
     39 import android.content.IntentFilter;
     40 import android.content.res.XmlResourceParser;
     41 import android.os.Bundle;
     42 import android.provider.Settings;
     43 import android.provider.Settings.SettingNotFoundException;
     44 import android.text.format.DateFormat;
     45 import android.util.Log;
     46 import android.view.View;
     47 
     48 import java.text.SimpleDateFormat;
     49 import java.util.ArrayList;
     50 import java.util.Calendar;
     51 import java.util.Collections;
     52 import java.util.Date;
     53 import java.util.List;
     54 import java.util.TimeZone;
     55 
     56 public class DateTimeActivity extends BaseSettingsActivity implements ActionAdapter.Listener {
     57 
     58     private static final String TAG = "DateTimeActivity";
     59     private static final boolean DEBUG = false;
     60 
     61     private static final String HOURS_12 = "12";
     62     private static final String HOURS_24 = "24";
     63 
     64     private static final int HOURS_IN_HALF_DAY = 12;
     65 
     66     private static final String XMLTAG_TIMEZONE = "timezone";
     67 
     68     private Calendar mDummyDate;
     69     private boolean mIsResumed;
     70 
     71     private IntentFilter mIntentFilter;
     72 
     73     private String mNowDate;
     74     private String mNowTime;
     75 
     76     private ArrayList<Action> mTimeZoneActions;
     77 
     78     private SettingsHelper mHelper;
     79 
     80     /**
     81      * Flag indicating whether this UpdateView call is from onCreate.
     82      */
     83     private boolean mOnCreateUpdateView = false;
     84 
     85     /**
     86      * Flag indicating whether this UpdateView call is from onResume.
     87      */
     88     private boolean mOnResumeUpdateView = false;
     89 
     90     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
     91         @Override
     92         public void onReceive(Context context, Intent intent) {
     93             if (mIsResumed) {
     94                 switch ((ActionType) mState) {
     95                     case DATE_TIME_OVERVIEW:
     96                     case DATE:
     97                     case TIME:
     98                         updateTimeAndDateDisplay();
     99                 }
    100             }
    101         }
    102     };
    103 
    104     @Override
    105     public void onCreate(Bundle savedInstanceState) {
    106         mDummyDate = Calendar.getInstance();
    107         mIntentFilter = new IntentFilter();
    108         mIntentFilter.addAction(Intent.ACTION_TIME_TICK);
    109         mIntentFilter.addAction(Intent.ACTION_TIME_CHANGED);
    110         mIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
    111         mIntentFilter.addAction(Intent.ACTION_DATE_CHANGED);
    112         registerReceiver(mIntentReceiver, mIntentFilter);
    113 
    114         mHelper = new SettingsHelper(getApplicationContext());
    115 
    116         setSampleDate();
    117 
    118         updateTimeAndDateStrings();
    119         mOnCreateUpdateView = true;
    120 
    121         super.onCreate(savedInstanceState);
    122     }
    123 
    124     private void setSampleDate() {
    125         Calendar now = Calendar.getInstance();
    126         mDummyDate.setTimeZone(now.getTimeZone());
    127         // We use December 31st because it's unambiguous when demonstrating the date format.
    128         // We use 15:14 so we can demonstrate the 12/24 hour options.
    129         mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 15, 14, 0);
    130     }
    131 
    132     private boolean getAutoState(String name) {
    133         try {
    134             return Settings.Global.getInt(getContentResolver(), name) > 0;
    135         } catch (SettingNotFoundException snfe) {
    136             return false;
    137         }
    138     }
    139 
    140     static void setDate(Context context, int year, int month, int day) {
    141         Calendar c = Calendar.getInstance();
    142 
    143         c.set(Calendar.YEAR, year);
    144         c.set(Calendar.MONTH, month);
    145         c.set(Calendar.DAY_OF_MONTH, day);
    146         long when = c.getTimeInMillis();
    147 
    148         if (when / 1000 < Integer.MAX_VALUE) {
    149             ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when);
    150         }
    151     }
    152 
    153     static void setTime(Context context, int hourOfDay, int minute) {
    154         Calendar c = Calendar.getInstance();
    155 
    156         c.set(Calendar.HOUR_OF_DAY, hourOfDay);
    157         c.set(Calendar.MINUTE, minute);
    158         c.set(Calendar.SECOND, 0);
    159         c.set(Calendar.MILLISECOND, 0);
    160         long when = c.getTimeInMillis();
    161 
    162         if (when / 1000 < Integer.MAX_VALUE) {
    163             ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when);
    164         }
    165     }
    166 
    167     private String[] getFormattedDates() {
    168         String[] dateFormats = getResources().getStringArray(R.array.date_format_values);
    169         String[] formattedDates = new String[dateFormats.length];
    170 
    171         for (int i = 0; i < formattedDates.length; i++) {
    172             String formatted = DateFormat.getDateFormatForSetting(this, dateFormats[i])
    173                     .format(mDummyDate.getTime());
    174 
    175             if (dateFormats[i].length() == 0) {
    176                 formattedDates[i] = getString(R.string.normal_date_format, formatted);
    177             } else {
    178                 formattedDates[i] = formatted;
    179             }
    180         }
    181         return formattedDates;
    182     }
    183 
    184     private boolean isTimeFormat24h() {
    185         return DateFormat.is24HourFormat(this);
    186     }
    187 
    188     private String getDateFormat() {
    189         return Settings.System.getString(getContentResolver(),
    190                 Settings.System.DATE_FORMAT);
    191     }
    192 
    193     private void setDateFormat(String s) {
    194         Settings.System.putString(getContentResolver(), Settings.System.DATE_FORMAT, s);
    195     }
    196 
    197     private void setTime24Hour(boolean is24Hour) {
    198         Settings.System.putString(getContentResolver(),
    199                 Settings.System.TIME_12_24,
    200                 is24Hour ? HOURS_24 : HOURS_12);
    201     }
    202 
    203     private void setAutoDateTime(boolean on) {
    204         Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, on ? 1 : 0);
    205     }
    206 
    207     @Override
    208     protected void onResume() {
    209         super.onResume();
    210         mIsResumed = true;
    211         registerReceiver(mIntentReceiver, mIntentFilter);
    212 
    213         mOnResumeUpdateView = true;
    214 
    215         updateTimeAndDateDisplay();
    216     }
    217 
    218     @Override
    219     protected void onPause() {
    220         super.onPause();
    221         mIsResumed = false;
    222         unregisterReceiver(mIntentReceiver);
    223     }
    224 
    225     // Updates the member strings to reflect the current date and time.
    226     private void updateTimeAndDateStrings() {
    227         final Calendar now = Calendar.getInstance();
    228         java.text.DateFormat dateFormat = DateFormat.getDateFormat(this);
    229         mNowDate = dateFormat.format(now.getTime());
    230         java.text.DateFormat timeFormat = DateFormat.getTimeFormat(this);
    231         mNowTime = timeFormat.format(now.getTime());
    232     }
    233 
    234     @Override
    235     public void onActionClicked(Action action) {
    236         /*
    237          * For list preferences
    238          */
    239         final String key = action.getKey();
    240         switch ((ActionType) mState) {
    241             case DATE_CHOOSE_FORMAT:
    242                 setDateFormat(key);
    243                 updateTimeAndDateStrings();
    244                 goBack();
    245                 return;
    246             case TIME_SET_TIME_ZONE:
    247                 setTimeZone(key);
    248                 updateTimeAndDateStrings();
    249                 goBack();
    250                 return;
    251         }
    252         /*
    253          * For other preferences
    254          */
    255         ActionKey<ActionType, ActionBehavior> actionKey = new ActionKey<ActionType, ActionBehavior>(
    256                 ActionType.class, ActionBehavior.class, key);
    257         final ActionType type = actionKey.getType();
    258         final ActionBehavior behavior = actionKey.getBehavior();
    259         if (type == null || behavior == null) {
    260             // Possible race condition manifested by monkey test.
    261             Log.e(TAG, "type or behavior is null - exiting  b/17404946");
    262             return;
    263         }
    264         switch (type) {
    265             case DATE:
    266             case TIME:
    267             case DATE_CHOOSE_FORMAT:
    268             case TIME_CHOOSE_FORMAT:
    269             case DATE_SET_DATE:
    270             case TIME_SET_TIME:
    271             case TIME_SET_TIME_ZONE:
    272             case AUTO_DATE_TIME:
    273                 if (behavior == ActionBehavior.INIT) {
    274                     setState(type, true);
    275                 }
    276                 break;
    277         }
    278         switch (behavior) {
    279             case ON:
    280                 if (mState == ActionType.TIME_CHOOSE_FORMAT) {
    281                     setTime24Hour(true);
    282                     updateTimeAndDateStrings();
    283                 } else if (mState == ActionType.AUTO_DATE_TIME) {
    284                     setAutoDateTime(true);
    285                 }
    286                 goBack();
    287                 break;
    288             case OFF:
    289                 if (mState == ActionType.TIME_CHOOSE_FORMAT) {
    290                     setTime24Hour(false);
    291                     updateTimeAndDateStrings();
    292                 } else if (mState == ActionType.AUTO_DATE_TIME) {
    293                     setAutoDateTime(false);
    294                 }
    295                 goBack();
    296                 break;
    297         }
    298     }
    299 
    300     @Override
    301     protected Object getInitialState() {
    302         return ActionType.DATE_TIME_OVERVIEW;
    303     }
    304 
    305     private String getDateFormatExampleString() {
    306         // Display a default example date.
    307         // TODO: Check with UX on exactly what we should display here, a sample date
    308         // or a standard (but localized) format descriptor.
    309         String setFormat = getDateFormat();
    310         String formatted = DateFormat.getDateFormatForSetting(this, getDateFormat())
    311                 .format(mDummyDate.getTime());
    312         String displayText;
    313         if (setFormat == null || setFormat.isEmpty()) {
    314             displayText = getString(R.string.normal_date_format, formatted);
    315         } else {
    316             displayText = formatted;
    317         }
    318         return displayText;
    319     }
    320 
    321     // Updates the Date and Time entries in the current view, without resetting the
    322     // Action fragment, so we don't trigger an animation.
    323     protected void updateTimeAndDateDisplay() {
    324         updateTimeAndDateStrings();
    325 
    326         if (mActionFragment instanceof ActionFragment) {
    327             ActionAdapter adapter = (ActionAdapter) ((ActionFragment)mActionFragment).getAdapter();
    328 
    329             if (adapter != null) {
    330                 mActions.clear();
    331 
    332                 switch ((ActionType) mState) {
    333                     case DATE_TIME_OVERVIEW:
    334                         mActions.add(ActionType.AUTO_DATE_TIME.toAction(mResources,
    335                                 mHelper.getStatusStringFromBoolean(getAutoState(
    336                                         Settings.Global.AUTO_TIME))));
    337                         mActions.add(ActionType.DATE.toAction(mResources, mNowDate));
    338                         mActions.add(ActionType.TIME.toAction(mResources, mNowTime));
    339                         break;
    340                     case DATE:
    341                         mActions.add(ActionType.DATE_SET_DATE.toAction(mResources, mNowDate));
    342                         mActions.add(ActionType.DATE_CHOOSE_FORMAT.toAction(mResources,
    343                                 getDateFormatExampleString()));
    344                         break;
    345                     case TIME:
    346                         mActions.add(ActionType.TIME_SET_TIME.toAction(mResources, mNowTime));
    347                         mActions.add(ActionType.TIME_SET_TIME_ZONE.toAction(mResources,
    348                                 getCurrentTimeZoneName()));
    349                         mActions.add(ActionType.TIME_CHOOSE_FORMAT.toAction(
    350                                 mResources, getTimeFormatDescription()));
    351                         break;
    352                 }
    353                 adapter.setActions(mActions);
    354                 return;
    355             }
    356         }
    357 
    358         // If we don't have an ActionFragment or adapter, fall back to the regular updateView
    359         updateView();
    360     }
    361 
    362     @Override
    363     protected void refreshActionList() {
    364         mActions.clear();
    365         boolean autoTime = getAutoState(Settings.Global.AUTO_TIME);
    366         switch ((ActionType)mState) {
    367             case DATE_TIME_OVERVIEW:
    368                 mActions.add(ActionType.AUTO_DATE_TIME.toAction(mResources,
    369                         mHelper.getStatusStringFromBoolean(autoTime)));
    370                 mActions.add(ActionType.DATE.toAction(mResources, mNowDate));
    371                 mActions.add(ActionType.TIME.toAction(mResources, mNowTime));
    372                 break;
    373             case DATE:
    374                 mActions.add(ActionType.DATE_SET_DATE.toAction(mResources, mNowDate, !autoTime));
    375 
    376                 mActions.add(ActionType.DATE_CHOOSE_FORMAT.toAction(mResources,
    377                         getDateFormatExampleString()));
    378                 break;
    379             case TIME:
    380                 mActions.add(ActionType.TIME_SET_TIME.toAction(mResources, mNowTime, !autoTime));
    381                 mActions.add(ActionType.TIME_SET_TIME_ZONE.toAction(
    382                         mResources, getCurrentTimeZoneName()));
    383                 mActions.add(ActionType.TIME_CHOOSE_FORMAT.toAction(
    384                         mResources, getTimeFormatDescription()));
    385                 break;
    386             case DATE_CHOOSE_FORMAT:
    387                 String[] formats = mResources.getStringArray(R.array.date_format_values);
    388                 String currentFormat = getDateFormat();
    389                 mActions = Action.createActionsFromArrays(formats, getFormattedDates());
    390                 for (Action action : mActions) {
    391                     action.setChecked(action.getKey().equalsIgnoreCase(currentFormat));
    392                 }
    393                 break;
    394             case TIME_CHOOSE_FORMAT:
    395                 mActions.add(ActionBehavior.ON.toAction(ActionBehavior.getOnKey(
    396                         ActionType.TIME_CHOOSE_FORMAT.name()), mResources, isTimeFormat24h()));
    397                 mActions.add(ActionBehavior.OFF.toAction(ActionBehavior.getOffKey(
    398                         ActionType.TIME_CHOOSE_FORMAT.name()), mResources, !isTimeFormat24h()));
    399                 break;
    400             case TIME_SET_TIME_ZONE:
    401                 mActions = getZoneActions(this);
    402                 break;
    403             case AUTO_DATE_TIME:
    404                 mActions.add(ActionBehavior.ON.toAction(ActionBehavior.getOnKey(
    405                         ActionType.AUTO_DATE_TIME.name()), mResources, autoTime));
    406                 mActions.add(ActionBehavior.OFF.toAction(ActionBehavior.getOffKey(
    407                         ActionType.AUTO_DATE_TIME.name()), mResources, !autoTime));
    408                 break;
    409             default:
    410                 break;
    411         }
    412     }
    413 
    414     private String getTimeFormatDescription() {
    415         String status = mHelper.getStatusStringFromBoolean(isTimeFormat24h());
    416         String desc = String.format("%s (%s)", status,
    417                 DateFormat.getTimeFormat(this).format(mDummyDate.getTime()));
    418         return desc;
    419     }
    420 
    421     @Override
    422     protected void updateView() {
    423         refreshActionList();
    424 
    425         switch ((ActionType) mState) {
    426             case DATE_TIME_OVERVIEW:
    427                 if (mOnCreateUpdateView && mOnResumeUpdateView) {
    428                     // If current updateView call is due to onResume following onCreate,
    429                     // avoid duplicate setView, which will lead to broken animation.
    430                     mOnCreateUpdateView = false;
    431                     mOnResumeUpdateView = false;
    432 
    433                     return;
    434                 } else {
    435                     mOnResumeUpdateView = false;
    436                 }
    437                 mActionFragment = ActionFragment.newInstance(mActions);
    438                 break;
    439             case DATE_SET_DATE:
    440                 DatePicker datePicker =
    441                         DatePicker.newInstance(new String(DateFormat.getDateFormatOrder(this)));
    442                 datePicker.setResultListener(new Picker.ResultListener() {
    443 
    444                     @Override
    445                     public void onCommitResult(List<String> result) {
    446                         String formatOrder = new String(
    447                                 DateFormat.getDateFormatOrder(DateTimeActivity.this)).toUpperCase();
    448                         int yIndex = formatOrder.indexOf('Y');
    449                         int mIndex = formatOrder.indexOf('M');
    450                         int dIndex = formatOrder.indexOf('D');
    451                         if (yIndex < 0 || mIndex < 0 || dIndex < 0 ||
    452                                 yIndex > 2 || mIndex > 2 || dIndex > 2) {
    453                             // Badly formatted input. Use default order.
    454                             mIndex = 0;
    455                             dIndex = 1;
    456                             yIndex = 2;
    457                         }
    458                         String month = result.get(mIndex);
    459                         int day = Integer.parseInt(result.get(dIndex));
    460                         int year = Integer.parseInt(result.get(yIndex));
    461                         int monthInt = 0;
    462                         String[] months = PickerConstant.getInstance(mResources).months;
    463                         int totalMonths = months.length;
    464                         for (int i = 0; i < totalMonths; i++) {
    465                             if (months[i].equals(month)) {
    466                                 monthInt = i;
    467                             }
    468                         }
    469 
    470                         // turn off Auto date/time
    471                         setAutoDateTime(false);
    472 
    473                         setDate(DateTimeActivity.this, year, monthInt, day);
    474                         goBack();
    475                     }
    476                 });
    477                 mActionFragment = datePicker;
    478                 break;
    479             case TIME_SET_TIME:
    480                 Picker timePicker = TimePicker.newInstance(isTimeFormat24h(), true);
    481                 timePicker.setResultListener(new Picker.ResultListener() {
    482 
    483                     @Override
    484                     public void onCommitResult(List<String> result) {
    485                         boolean is24hFormat = isTimeFormat24h();
    486                         int hour = Integer.parseInt(result.get(0));
    487                         int minute = Integer.parseInt(result.get(1));
    488                         if (!is24hFormat) {
    489                             String ampm = result.get(2);
    490                             if (ampm.equals(getResources().getStringArray(R.array.ampm)[1])) {
    491                                 // PM case, valid hours: 12-23
    492                                 hour = (hour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
    493                             } else {
    494                                 // AM case, valid hours: 0-11
    495                                 hour = hour % HOURS_IN_HALF_DAY;
    496                             }
    497                         }
    498 
    499                         // turn off Auto date/time
    500                         setAutoDateTime(false);
    501 
    502                         setTime(DateTimeActivity.this, hour, minute);
    503                         goBack();
    504                     }
    505                 });
    506                 mActionFragment = timePicker;
    507                 break;
    508             default:
    509                 mActionFragment = ActionFragment.newInstance(mActions);
    510                 break;
    511         }
    512 
    513         setViewWithActionFragment(
    514                 ((ActionType) mState).getTitle(mResources), getPrevState() != null ?
    515                         ((ActionType) getPrevState()).getTitle(mResources)
    516                         : getString(R.string.settings_app_name),
    517                 ((ActionType) mState).getDescription(mResources), R.drawable.ic_settings_datetime);
    518     }
    519 
    520     protected void setViewWithActionFragment(String title, String breadcrumb, String description,
    521             int iconResId) {
    522         mContentFragment = ContentFragment.newInstance(title, breadcrumb, description, iconResId,
    523                 getResources().getColor(R.color.icon_background));
    524         setContentAndActionFragments(mContentFragment, mActionFragment);
    525     }
    526 
    527     @Override
    528     protected void setProperty(boolean enable) {
    529     }
    530 
    531     /**
    532      * Returns a string representing the current time zone set in the system.
    533      */
    534     private String getCurrentTimeZoneName() {
    535         final Calendar now = Calendar.getInstance();
    536         TimeZone tz = now.getTimeZone();
    537 
    538         Date date = new Date();
    539         return formatOffset(new StringBuilder(), tz.getOffset(date.getTime())).
    540                 append(", ").
    541                 append(tz.getDisplayName(tz.inDaylightTime(date), TimeZone.LONG)).toString();
    542     }
    543 
    544     /**
    545      * Formats the provided timezone offset into a string of the form GMT+XX:XX
    546      */
    547     private static StringBuilder formatOffset(StringBuilder sb, long offset) {
    548         long off = offset / 1000 / 60;
    549 
    550         sb.append("GMT");
    551         if (off < 0) {
    552             sb.append('-');
    553             off = -off;
    554         } else {
    555             sb.append('+');
    556         }
    557 
    558         int hours = (int) (off / 60);
    559         int minutes = (int) (off % 60);
    560 
    561         sb.append((char) ('0' + hours / 10));
    562         sb.append((char) ('0' + hours % 10));
    563 
    564         sb.append(':');
    565 
    566         sb.append((char) ('0' + minutes / 10));
    567         sb.append((char) ('0' + minutes % 10));
    568 
    569         return sb;
    570     }
    571 
    572     /**
    573      * Helper class to hold the time zone data parsed from the Time Zones XML
    574      * file.
    575      */
    576     private class TimeZoneInfo implements Comparable<TimeZoneInfo> {
    577         public String tzId;
    578         public String tzName;
    579         public long tzOffset;
    580 
    581         public TimeZoneInfo(String id, String name, long offset) {
    582             tzId = id;
    583             tzName = name;
    584             tzOffset = offset;
    585         }
    586 
    587         @Override
    588         public int compareTo(TimeZoneInfo another) {
    589             return (int) (tzOffset - another.tzOffset);
    590         }
    591     }
    592 
    593     /**
    594      * Parse the Time Zones information from the XML file and creates Action
    595      * objects for each time zone.
    596      */
    597     private ArrayList<Action> getZoneActions(Context context) {
    598         if (mTimeZoneActions != null && mTimeZoneActions.size() != 0) {
    599             return mTimeZoneActions;
    600         }
    601 
    602         ArrayList<TimeZoneInfo> timeZones = getTimeZones(context);
    603 
    604         mTimeZoneActions = new ArrayList<Action>();
    605 
    606         // Sort the Time Zones list in ascending offset order
    607         Collections.sort(timeZones);
    608 
    609         TimeZone currentTz = TimeZone.getDefault();
    610 
    611         for (TimeZoneInfo tz : timeZones) {
    612             StringBuilder name = new StringBuilder();
    613             boolean checked = currentTz.getID().equals(tz.tzId);
    614             mTimeZoneActions.add(getTimeZoneAction(tz.tzId, tz.tzName,
    615                     formatOffset(name, tz.tzOffset).toString(), checked));
    616         }
    617 
    618         return mTimeZoneActions;
    619     }
    620 
    621     /**
    622      * Parses the XML time zone information into an array of TimeZoneInfo
    623      * objects.
    624      */
    625     private ArrayList<TimeZoneInfo> getTimeZones(Context context) {
    626         ArrayList<TimeZoneInfo> timeZones = new ArrayList<TimeZoneInfo>();
    627         final long date = Calendar.getInstance().getTimeInMillis();
    628         try {
    629             XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones);
    630             while (xrp.next() != XmlResourceParser.START_TAG)
    631                 continue;
    632             xrp.next();
    633             while (xrp.getEventType() != XmlResourceParser.END_TAG) {
    634                 while (xrp.getEventType() != XmlResourceParser.START_TAG &&
    635                         xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
    636                     xrp.next();
    637                 }
    638 
    639                 if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) {
    640                     break;
    641                 }
    642 
    643                 if (xrp.getName().equals(XMLTAG_TIMEZONE)) {
    644                     String id = xrp.getAttributeValue(0);
    645                     String displayName = xrp.nextText();
    646                     TimeZone tz = TimeZone.getTimeZone(id);
    647                     long offset;
    648                     if (tz != null) {
    649                         offset = tz.getOffset(date);
    650                         timeZones.add(new TimeZoneInfo(id, displayName, offset));
    651                     } else {
    652                         continue;
    653                     }
    654                 }
    655                 while (xrp.getEventType() != XmlResourceParser.END_TAG) {
    656                     xrp.next();
    657                 }
    658                 xrp.next();
    659             }
    660             xrp.close();
    661         } catch (XmlPullParserException xppe) {
    662             Log.e(TAG, "Ill-formatted timezones.xml file");
    663         } catch (java.io.IOException ioe) {
    664             Log.e(TAG, "Unable to read timezones.xml file");
    665         }
    666         return timeZones;
    667     }
    668 
    669     private static Action getTimeZoneAction(String tzId, String displayName, String gmt,
    670             boolean setChecked) {
    671         return new Action.Builder().key(tzId).title(displayName).description(gmt).
    672                 checked(setChecked).build();
    673     }
    674 
    675     private void setTimeZone(String tzId) {
    676         // Update the system timezone value
    677         final AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    678         alarm.setTimeZone(tzId);
    679 
    680         setSampleDate();
    681     }
    682 }
    683