165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/*
265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project
365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *
465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License");
565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License.
665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at
765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *
865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *      http://www.apache.org/licenses/LICENSE-2.0
965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *
1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software
1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS,
1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and
1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License.
1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */
1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.system;
1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.ActionBehavior;
2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.ActionKey;
2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.BaseSettingsActivity;
2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.R;
2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.util.SettingsHelper;
2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.Action;
2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.ActionAdapter;
2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.ActionFragment;
2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.ContentFragment;
2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.picker.DatePicker;
2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.picker.TimePicker;
3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.picker.Picker;
3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.widget.picker.PickerConstant;
3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport org.xmlpull.v1.XmlPullParserException;
3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.app.AlarmManager;
3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.BroadcastReceiver;
3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Context;
3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Intent;
3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.IntentFilter;
4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.res.XmlResourceParser;
4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Bundle;
4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.provider.Settings;
4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.provider.Settings.SettingNotFoundException;
4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.text.format.DateFormat;
4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Log;
4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.ArrayList;
4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.Calendar;
4965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.Collections;
5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.Date;
5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.List;
5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.TimeZone;
5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic class DateTimeActivity extends BaseSettingsActivity implements ActionAdapter.Listener {
5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final String TAG = "DateTimeActivity";
5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final boolean DEBUG = false;
5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final String HOURS_12 = "12";
6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final String HOURS_24 = "24";
6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final int HOURS_IN_HALF_DAY = 12;
6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final String XMLTAG_TIMEZONE = "timezone";
6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
6665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Calendar mDummyDate;
6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private boolean mIsResumed;
6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private IntentFilter mIntentFilter;
7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private String mNowDate;
7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private String mNowTime;
7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private ArrayList<Action> mTimeZoneActions;
7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private SettingsHelper mHelper;
7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Flag indicating whether this UpdateView call is from onCreate.
8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private boolean mOnCreateUpdateView = false;
8265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Flag indicating whether this UpdateView call is from onResume.
8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private boolean mOnResumeUpdateView = false;
8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        @Override
9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        public void onReceive(Context context, Intent intent) {
9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (mIsResumed) {
9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                switch ((ActionType) mState) {
9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    case DATE_TIME_OVERVIEW:
9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    case DATE:
9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    case TIME:
9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        updateTimeAndDateDisplay();
9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    };
10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onCreate(Bundle savedInstanceState) {
10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mDummyDate = Calendar.getInstance();
10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIntentFilter = new IntentFilter();
10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIntentFilter.addAction(Intent.ACTION_TIME_TICK);
10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIntentFilter.addAction(Intent.ACTION_TIME_CHANGED);
10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIntentFilter.addAction(Intent.ACTION_DATE_CHANGED);
11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        registerReceiver(mIntentReceiver, mIntentFilter);
11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mHelper = new SettingsHelper(getApplicationContext());
11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        setSampleDate();
11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        updateTimeAndDateStrings();
11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mOnCreateUpdateView = true;
11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        super.onCreate(savedInstanceState);
12065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
12165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void setSampleDate() {
12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Calendar now = Calendar.getInstance();
12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mDummyDate.setTimeZone(now.getTimeZone());
12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // We use December 31st because it's unambiguous when demonstrating the date format.
12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // We use 15:14 so we can demonstrate the 12/24 hour options.
12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mDummyDate.set(now.get(Calendar.YEAR), 11, 31, 15, 14, 0);
12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private boolean getAutoState(String name) {
13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        try {
13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return Settings.Global.getInt(getContentResolver(), name) > 0;
13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } catch (SettingNotFoundException snfe) {
13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return false;
13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    static void setDate(Context context, int year, int month, int day) {
13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Calendar c = Calendar.getInstance();
14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.YEAR, year);
14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.MONTH, month);
14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.DAY_OF_MONTH, day);
14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        long when = c.getTimeInMillis();
14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (when / 1000 < Integer.MAX_VALUE) {
14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when);
14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    static void setTime(Context context, int hourOfDay, int minute) {
15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Calendar c = Calendar.getInstance();
15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.MINUTE, minute);
15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.SECOND, 0);
15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        c.set(Calendar.MILLISECOND, 0);
15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        long when = c.getTimeInMillis();
15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (when / 1000 < Integer.MAX_VALUE) {
16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when);
16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private boolean isTimeFormat24h() {
1662100f1f07a85cf21a0497517cb136869ea831bf2William Bourke        return DateFormat.is24HourFormat(this);
16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void setTime24Hour(boolean is24Hour) {
17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Settings.System.putString(getContentResolver(),
17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                Settings.System.TIME_12_24,
17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                is24Hour ? HOURS_24 : HOURS_12);
17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void setAutoDateTime(boolean on) {
17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, on ? 1 : 0);
17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void onResume() {
18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        super.onResume();
18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIsResumed = true;
18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        registerReceiver(mIntentReceiver, mIntentFilter);
18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mOnResumeUpdateView = true;
18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        updateTimeAndDateDisplay();
18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void onPause() {
19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        super.onPause();
19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mIsResumed = false;
19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        unregisterReceiver(mIntentReceiver);
19565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
19665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
19765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    // Updates the member strings to reflect the current date and time.
19865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void updateTimeAndDateStrings() {
19965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final Calendar now = Calendar.getInstance();
20065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        java.text.DateFormat dateFormat = DateFormat.getDateFormat(this);
20165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mNowDate = dateFormat.format(now.getTime());
20265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        java.text.DateFormat timeFormat = DateFormat.getTimeFormat(this);
20365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mNowTime = timeFormat.format(now.getTime());
20465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
20565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
20665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
20765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onActionClicked(Action action) {
20865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        /*
20965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane         * For list preferences
21065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane         */
21165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final String key = action.getKey();
21265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        switch ((ActionType) mState) {
21365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_SET_TIME_ZONE:
21465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                setTimeZone(key);
21565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                updateTimeAndDateStrings();
21665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                goBack();
21765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                return;
21865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
21965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        /*
22065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane         * For other preferences
22165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane         */
22265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ActionKey<ActionType, ActionBehavior> actionKey = new ActionKey<ActionType, ActionBehavior>(
22365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                ActionType.class, ActionBehavior.class, key);
22465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final ActionType type = actionKey.getType();
22565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final ActionBehavior behavior = actionKey.getBehavior();
22665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (type == null || behavior == null) {
22765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            // Possible race condition manifested by monkey test.
22865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            Log.e(TAG, "type or behavior is null - exiting  b/17404946");
22965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return;
23065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
23165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        switch (type) {
23265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case DATE:
23365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME:
23465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_CHOOSE_FORMAT:
23565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case DATE_SET_DATE:
23665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_SET_TIME:
23765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_SET_TIME_ZONE:
23865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case AUTO_DATE_TIME:
23965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (behavior == ActionBehavior.INIT) {
24065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    setState(type, true);
24165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
24265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
24365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
24465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        switch (behavior) {
24565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case ON:
24665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (mState == ActionType.TIME_CHOOSE_FORMAT) {
24765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    setTime24Hour(true);
24865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    updateTimeAndDateStrings();
24965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                } else if (mState == ActionType.AUTO_DATE_TIME) {
25065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    setAutoDateTime(true);
25165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
25265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                goBack();
25365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
25465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case OFF:
25565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (mState == ActionType.TIME_CHOOSE_FORMAT) {
25665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    setTime24Hour(false);
25765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    updateTimeAndDateStrings();
25865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                } else if (mState == ActionType.AUTO_DATE_TIME) {
25965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    setAutoDateTime(false);
26065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
26165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                goBack();
26265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
26365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
26465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
26565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
26665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
26765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected Object getInitialState() {
26865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return ActionType.DATE_TIME_OVERVIEW;
26965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
27065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
27165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    // Updates the Date and Time entries in the current view, without resetting the
27265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    // Action fragment, so we don't trigger an animation.
27365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void updateTimeAndDateDisplay() {
27465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        updateTimeAndDateStrings();
27565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
27665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (mActionFragment instanceof ActionFragment) {
27765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            ActionAdapter adapter = (ActionAdapter) ((ActionFragment)mActionFragment).getAdapter();
27865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
27965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (adapter != null) {
28065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.clear();
28165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
28265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                switch ((ActionType) mState) {
28365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    case DATE_TIME_OVERVIEW:
28465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.AUTO_DATE_TIME.toAction(mResources,
28565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                mHelper.getStatusStringFromBoolean(getAutoState(
28665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                        Settings.Global.AUTO_TIME))));
28765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.DATE.toAction(mResources, mNowDate));
28865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.TIME.toAction(mResources, mNowTime));
28965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        break;
29065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    case DATE:
29165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.DATE_SET_DATE.toAction(mResources, mNowDate));
29265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        break;
29365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    case TIME:
29465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.TIME_SET_TIME.toAction(mResources, mNowTime));
29565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.TIME_SET_TIME_ZONE.toAction(mResources,
29665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                getCurrentTimeZoneName()));
29765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mActions.add(ActionType.TIME_CHOOSE_FORMAT.toAction(
29865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                mResources, getTimeFormatDescription()));
29965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        break;
30065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
30165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                adapter.setActions(mActions);
30265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                return;
30365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
30465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
30565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
30665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // If we don't have an ActionFragment or adapter, fall back to the regular updateView
30765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        updateView();
30865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
30965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
31065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
31165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void refreshActionList() {
31265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mActions.clear();
31365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        boolean autoTime = getAutoState(Settings.Global.AUTO_TIME);
31465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        switch ((ActionType)mState) {
31565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case DATE_TIME_OVERVIEW:
31665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.AUTO_DATE_TIME.toAction(mResources,
31765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mHelper.getStatusStringFromBoolean(autoTime)));
31865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.DATE.toAction(mResources, mNowDate));
31965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.TIME.toAction(mResources, mNowTime));
32065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
32165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case DATE:
32265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.DATE_SET_DATE.toAction(mResources, mNowDate, !autoTime));
32365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
32465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME:
32565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.TIME_SET_TIME.toAction(mResources, mNowTime, !autoTime));
32665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.TIME_SET_TIME_ZONE.toAction(
32765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mResources, getCurrentTimeZoneName()));
32865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionType.TIME_CHOOSE_FORMAT.toAction(
32965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        mResources, getTimeFormatDescription()));
33065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
33165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_CHOOSE_FORMAT:
33265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionBehavior.ON.toAction(ActionBehavior.getOnKey(
33365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        ActionType.TIME_CHOOSE_FORMAT.name()), mResources, isTimeFormat24h()));
33465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionBehavior.OFF.toAction(ActionBehavior.getOffKey(
33565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        ActionType.TIME_CHOOSE_FORMAT.name()), mResources, !isTimeFormat24h()));
33665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
33765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_SET_TIME_ZONE:
33865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions = getZoneActions(this);
33965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
34065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case AUTO_DATE_TIME:
34165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionBehavior.ON.toAction(ActionBehavior.getOnKey(
34265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        ActionType.AUTO_DATE_TIME.name()), mResources, autoTime));
34365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActions.add(ActionBehavior.OFF.toAction(ActionBehavior.getOffKey(
34465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        ActionType.AUTO_DATE_TIME.name()), mResources, !autoTime));
34565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
34665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            default:
34765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
34865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
34965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
35065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
35165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private String getTimeFormatDescription() {
35265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        String status = mHelper.getStatusStringFromBoolean(isTimeFormat24h());
35365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        String desc = String.format("%s (%s)", status,
35465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                DateFormat.getTimeFormat(this).format(mDummyDate.getTime()));
35565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return desc;
35665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
35765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
35865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
35965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void updateView() {
36065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        refreshActionList();
36165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
36265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        switch ((ActionType) mState) {
36365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case DATE_TIME_OVERVIEW:
36465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (mOnCreateUpdateView && mOnResumeUpdateView) {
36565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    // If current updateView call is due to onResume following onCreate,
36665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    // avoid duplicate setView, which will lead to broken animation.
36765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    mOnCreateUpdateView = false;
36865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    mOnResumeUpdateView = false;
36965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
37065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    return;
37165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                } else {
37265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    mOnResumeUpdateView = false;
37365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
37465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActionFragment = ActionFragment.newInstance(mActions);
37565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
37665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case DATE_SET_DATE:
37765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                DatePicker datePicker =
37865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        DatePicker.newInstance(new String(DateFormat.getDateFormatOrder(this)));
37965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                datePicker.setResultListener(new Picker.ResultListener() {
38065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
38165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    @Override
38265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    public void onCommitResult(List<String> result) {
38365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        String formatOrder = new String(
38465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                DateFormat.getDateFormatOrder(DateTimeActivity.this)).toUpperCase();
38565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int yIndex = formatOrder.indexOf('Y');
38665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int mIndex = formatOrder.indexOf('M');
38765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int dIndex = formatOrder.indexOf('D');
38865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        if (yIndex < 0 || mIndex < 0 || dIndex < 0 ||
38965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                yIndex > 2 || mIndex > 2 || dIndex > 2) {
39065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            // Badly formatted input. Use default order.
39165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            mIndex = 0;
39265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            dIndex = 1;
39365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            yIndex = 2;
39465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        }
39565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        String month = result.get(mIndex);
39665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int day = Integer.parseInt(result.get(dIndex));
39765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int year = Integer.parseInt(result.get(yIndex));
39865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int monthInt = 0;
39965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        String[] months = PickerConstant.getInstance(mResources).months;
40065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int totalMonths = months.length;
40165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        for (int i = 0; i < totalMonths; i++) {
40265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            if (months[i].equals(month)) {
40365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                monthInt = i;
40465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            }
40565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        }
40665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
40765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        // turn off Auto date/time
40865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        setAutoDateTime(false);
40965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
41065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        setDate(DateTimeActivity.this, year, monthInt, day);
41165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        goBack();
41265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    }
41365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                });
41465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActionFragment = datePicker;
41565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
41665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TIME_SET_TIME:
41765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                Picker timePicker = TimePicker.newInstance(isTimeFormat24h(), true);
41865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                timePicker.setResultListener(new Picker.ResultListener() {
41965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
42065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    @Override
42165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    public void onCommitResult(List<String> result) {
42265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        boolean is24hFormat = isTimeFormat24h();
42365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int hour = Integer.parseInt(result.get(0));
42465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        int minute = Integer.parseInt(result.get(1));
42565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        if (!is24hFormat) {
42665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            String ampm = result.get(2);
42765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            if (ampm.equals(getResources().getStringArray(R.array.ampm)[1])) {
42865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                // PM case, valid hours: 12-23
42965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                hour = (hour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY;
43065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            } else {
43165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                // AM case, valid hours: 0-11
43265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                                hour = hour % HOURS_IN_HALF_DAY;
43365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            }
43465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        }
43565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
43665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        // turn off Auto date/time
43765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        setAutoDateTime(false);
43865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
43965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        setTime(DateTimeActivity.this, hour, minute);
44065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        goBack();
44165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    }
44265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                });
44365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActionFragment = timePicker;
44465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
44565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            default:
44665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mActionFragment = ActionFragment.newInstance(mActions);
44765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
44865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
44965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
45065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        setViewWithActionFragment(
45165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                ((ActionType) mState).getTitle(mResources), getPrevState() != null ?
45265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        ((ActionType) getPrevState()).getTitle(mResources)
45365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        : getString(R.string.settings_app_name),
45465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                ((ActionType) mState).getDescription(mResources), R.drawable.ic_settings_datetime);
45565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
45665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
45765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void setViewWithActionFragment(String title, String breadcrumb, String description,
45865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            int iconResId) {
45965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mContentFragment = ContentFragment.newInstance(title, breadcrumb, description, iconResId,
46065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                getResources().getColor(R.color.icon_background));
46165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        setContentAndActionFragments(mContentFragment, mActionFragment);
46265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
46365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
46465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
46565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void setProperty(boolean enable) {
46665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
46765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
46865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
46965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Returns a string representing the current time zone set in the system.
47065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
47165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private String getCurrentTimeZoneName() {
47265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final Calendar now = Calendar.getInstance();
47365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        TimeZone tz = now.getTimeZone();
47465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
47565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Date date = new Date();
47665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return formatOffset(new StringBuilder(), tz.getOffset(date.getTime())).
47765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                append(", ").
47865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                append(tz.getDisplayName(tz.inDaylightTime(date), TimeZone.LONG)).toString();
47965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
48065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
48165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
48265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Formats the provided timezone offset into a string of the form GMT+XX:XX
48365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
48465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static StringBuilder formatOffset(StringBuilder sb, long offset) {
48565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        long off = offset / 1000 / 60;
48665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
48765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        sb.append("GMT");
48865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (off < 0) {
48965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            sb.append('-');
49065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            off = -off;
49165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } else {
49265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            sb.append('+');
49365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
49465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
49565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        int hours = (int) (off / 60);
49665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        int minutes = (int) (off % 60);
49765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
49865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        sb.append((char) ('0' + hours / 10));
49965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        sb.append((char) ('0' + hours % 10));
50065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
50165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        sb.append(':');
50265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
50365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        sb.append((char) ('0' + minutes / 10));
50465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        sb.append((char) ('0' + minutes % 10));
50565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
50665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return sb;
50765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
50865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
50965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
51065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Helper class to hold the time zone data parsed from the Time Zones XML
51165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * file.
51265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
51365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private class TimeZoneInfo implements Comparable<TimeZoneInfo> {
51465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        public String tzId;
51565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        public String tzName;
51665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        public long tzOffset;
51765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
51865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        public TimeZoneInfo(String id, String name, long offset) {
51965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            tzId = id;
52065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            tzName = name;
52165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            tzOffset = offset;
52265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
52365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
52465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        @Override
52565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        public int compareTo(TimeZoneInfo another) {
52665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return (int) (tzOffset - another.tzOffset);
52765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
52865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
52965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
53065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
53165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Parse the Time Zones information from the XML file and creates Action
53265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * objects for each time zone.
53365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
53465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private ArrayList<Action> getZoneActions(Context context) {
53565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (mTimeZoneActions != null && mTimeZoneActions.size() != 0) {
53665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return mTimeZoneActions;
53765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
53865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
53965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ArrayList<TimeZoneInfo> timeZones = getTimeZones(context);
54065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
54165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mTimeZoneActions = new ArrayList<Action>();
54265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
54365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Sort the Time Zones list in ascending offset order
54465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Collections.sort(timeZones);
54565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
54665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        TimeZone currentTz = TimeZone.getDefault();
54765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
54865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        for (TimeZoneInfo tz : timeZones) {
54965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            StringBuilder name = new StringBuilder();
55065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            boolean checked = currentTz.getID().equals(tz.tzId);
55165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            mTimeZoneActions.add(getTimeZoneAction(tz.tzId, tz.tzName,
55265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    formatOffset(name, tz.tzOffset).toString(), checked));
55365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
55465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
55565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return mTimeZoneActions;
55665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
55765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
55865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
55965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Parses the XML time zone information into an array of TimeZoneInfo
56065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * objects.
56165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
56265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private ArrayList<TimeZoneInfo> getTimeZones(Context context) {
56365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ArrayList<TimeZoneInfo> timeZones = new ArrayList<TimeZoneInfo>();
56465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final long date = Calendar.getInstance().getTimeInMillis();
56565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        try {
56665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones);
56765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            while (xrp.next() != XmlResourceParser.START_TAG)
56865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                continue;
56965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            xrp.next();
57065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            while (xrp.getEventType() != XmlResourceParser.END_TAG) {
57165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                while (xrp.getEventType() != XmlResourceParser.START_TAG &&
57265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
57365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    xrp.next();
57465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
57565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
57665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) {
57765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    break;
57865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
57965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
58065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (xrp.getName().equals(XMLTAG_TIMEZONE)) {
58165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    String id = xrp.getAttributeValue(0);
58265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    String displayName = xrp.nextText();
58365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    TimeZone tz = TimeZone.getTimeZone(id);
58465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    long offset;
58565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    if (tz != null) {
58665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        offset = tz.getOffset(date);
58765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        timeZones.add(new TimeZoneInfo(id, displayName, offset));
58865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    } else {
58965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        continue;
59065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    }
59165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
59265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                while (xrp.getEventType() != XmlResourceParser.END_TAG) {
59365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    xrp.next();
59465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
59565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                xrp.next();
59665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
59765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            xrp.close();
59865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } catch (XmlPullParserException xppe) {
59965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            Log.e(TAG, "Ill-formatted timezones.xml file");
60065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } catch (java.io.IOException ioe) {
60165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            Log.e(TAG, "Unable to read timezones.xml file");
60265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
60365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return timeZones;
60465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
60565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
60665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static Action getTimeZoneAction(String tzId, String displayName, String gmt,
60765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            boolean setChecked) {
60865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return new Action.Builder().key(tzId).title(displayName).description(gmt).
60965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                checked(setChecked).build();
61065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
61165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
61265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void setTimeZone(String tzId) {
61365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Update the system timezone value
61465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        final AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
61565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        alarm.setTimeZone(tzId);
61665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
61765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        setSampleDate();
61865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
61965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane}
620