1afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project/*
2afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
3afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *
4afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * you may not use this file except in compliance with the License.
6afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * You may obtain a copy of the License at
7afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *
8afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project *
10afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * See the License for the specific language governing permissions and
14afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project * limitations under the License.
15afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project */
16afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
17afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectpackage com.android.settings;
18afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
190f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.app.Activity;
200f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.app.AlarmManager;
210f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.app.ListFragment;
220f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.content.Context;
230f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.content.res.XmlResourceParser;
24afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.os.Bundle;
250f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.util.Log;
2697d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkeyimport android.view.LayoutInflater;
270f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.view.Menu;
280f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.view.MenuInflater;
290f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.view.MenuItem;
30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.View;
3197d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkeyimport android.view.ViewGroup;
32afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.widget.ListView;
330f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.widget.SimpleAdapter;
34afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
350f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport org.xmlpull.v1.XmlPullParserException;
360f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
37f1582bc3f58ac440c11c54b844287915594b433fElliott Hughesimport java.text.SimpleDateFormat;
380f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.ArrayList;
390f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.Calendar;
400f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.Collections;
410f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.Comparator;
42f1582bc3f58ac440c11c54b844287915594b433fElliott Hughesimport java.util.Date;
43afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.HashMap;
44f1582bc3f58ac440c11c54b844287915594b433fElliott Hughesimport java.util.HashSet;
45afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.List;
46f1582bc3f58ac440c11c54b844287915594b433fElliott Hughesimport java.util.Locale;
47afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.Map;
480f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.TimeZone;
49f1582bc3f58ac440c11c54b844287915594b433fElliott Hughesimport libcore.icu.ICU;
50f1582bc3f58ac440c11c54b844287915594b433fElliott Hughesimport libcore.icu.TimeZoneNames;
510f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
520f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa/**
530f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * The class displaying a list of time zones that match a filter string
540f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * such as "Africa", "Europe", etc. Choosing an item from the list will set
55f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes * the time zone. Pressing Back without choosing from the list will not
560f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * result in a change in the time zone setting.
570f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa */
580f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawapublic class ZonePicker extends ListFragment {
590f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final String TAG = "ZonePicker";
600f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
610f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public static interface ZoneSelectionListener {
620f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        // You can add any argument if you really need it...
6371cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        public void onZoneSelected(TimeZone tz);
640f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
650f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
662571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_ID = "id";  // value: String
672571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_DISPLAYNAME = "name";  // value: String
682571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_GMT = "gmt";  // value: String
692571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_OFFSET = "offset";  // value: int (Integer)
700f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final String XMLTAG_TIMEZONE = "timezone";
710f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
720f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final int HOURS_1 = 60 * 60000;
730f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
740f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final int MENU_TIMEZONE = Menu.FIRST+1;
750f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final int MENU_ALPHABETICAL = Menu.FIRST;
760f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
770f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private boolean mSortedByTimezone;
780f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
790f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private SimpleAdapter mTimezoneSortedAdapter;
800f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private SimpleAdapter mAlphabeticalAdapter;
810f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
820f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private ZoneSelectionListener mListener;
830f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
842571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    /**
852571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * Constructs an adapter with TimeZone list. Sorted by TimeZone in default.
862571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     *
872571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param sortedByName use Name for sorting the list.
882571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     */
892571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public static SimpleAdapter constructTimezoneAdapter(Context context,
902571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            boolean sortedByName) {
910688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa        return constructTimezoneAdapter(context, sortedByName,
924166ec39ecd8a2066f4426e1b359a0b1f95af05eJeff Sharkey                R.layout.date_time_setup_custom_list_item_2);
930688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa    }
940688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa
950688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa    /**
960688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     * Constructs an adapter with TimeZone list. Sorted by TimeZone in default.
970688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     *
980688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     * @param sortedByName use Name for sorting the list.
990688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     */
1000688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa    public static SimpleAdapter constructTimezoneAdapter(Context context,
1010688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa            boolean sortedByName, int layoutId) {
1020f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        final String[] from = new String[] {KEY_DISPLAYNAME, KEY_GMT};
1030f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        final int[] to = new int[] {android.R.id.text1, android.R.id.text2};
104afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
1052571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final String sortKey = (sortedByName ? KEY_DISPLAYNAME : KEY_OFFSET);
1062571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final MyComparator comparator = new MyComparator(sortKey);
107f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        ZoneGetter zoneGetter = new ZoneGetter();
108f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        final List<HashMap<String, Object>> sortedList = zoneGetter.getZones(context);
1092571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        Collections.sort(sortedList, comparator);
1102571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final SimpleAdapter adapter = new SimpleAdapter(context,
1112571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                sortedList,
1120688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa                layoutId,
1130f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                from,
1140f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                to);
1150f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1162571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        return adapter;
1172571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    }
1182571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1192571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    /**
1202571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * Searches {@link TimeZone} from the given {@link SimpleAdapter} object, and returns
1212571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * the index for the TimeZone.
1222571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     *
1232571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param adapter SimpleAdapter constructed by
1242571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * {@link #constructTimezoneAdapter(Context, boolean)}.
1252571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param tz TimeZone to be searched.
1262571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @return Index for the given TimeZone. -1 when there's no corresponding list item.
1272571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * returned.
1282571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     */
1292571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public static int getTimeZoneIndex(SimpleAdapter adapter, TimeZone tz) {
1302571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final String defaultId = tz.getID();
1312571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final int listSize = adapter.getCount();
1322571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        for (int i = 0; i < listSize; i++) {
1332571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            // Using HashMap<String, Object> induces unnecessary warning.
1342571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            final HashMap<?,?> map = (HashMap<?,?>)adapter.getItem(i);
1352571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            final String id = (String)map.get(KEY_ID);
1362571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            if (defaultId.equals(id)) {
1372571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                // If current timezone is in this list, move focus to it
1382571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                return i;
1392571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            }
1402571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        }
1412571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        return -1;
1422571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    }
1432571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1442571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    /**
1452571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param item one of items in adapters. The adapter should be constructed by
1462571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * {@link #constructTimezoneAdapter(Context, boolean)}.
1472571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @return TimeZone object corresponding to the item.
1482571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     */
1492571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public static TimeZone obtainTimeZoneFromItem(Object item) {
1502571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        return TimeZone.getTimeZone((String)((Map<?, ?>)item).get(KEY_ID));
1512571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    }
1522571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1532571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    @Override
154f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes    public void onActivityCreated(Bundle savedInstanceState) {
155f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        super.onActivityCreated(savedInstanceState);
1562571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1572571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final Activity activity = getActivity();
1582571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        mTimezoneSortedAdapter = constructTimezoneAdapter(activity, false);
1592571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        mAlphabeticalAdapter = constructTimezoneAdapter(activity, true);
1600f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1610f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        // Sets the adapter
1620f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        setSorting(true);
1631e9d497e2b0a3d00e83372d536b79c9ec0646b9dDaisuke Miyakawa        setHasOptionsMenu(true);
1640f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
165afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
166afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
16797d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey    public View onCreateView(LayoutInflater inflater, ViewGroup container,
16897d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey            Bundle savedInstanceState) {
16997d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey        final View view = super.onCreateView(inflater, container, savedInstanceState);
17097d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey        final ListView list = (ListView) view.findViewById(android.R.id.list);
17197d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey        Utils.forcePrepareCustomPreferencesList(container, view, list, false);
17297d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey        return view;
17397d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey    }
17497d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey
17597d07fa3aedde44368818551dc789eaff7bfb047Jeff Sharkey    @Override
1760f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1770f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        menu.add(0, MENU_ALPHABETICAL, 0, R.string.zone_list_menu_sort_alphabetically)
1780f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            .setIcon(android.R.drawable.ic_menu_sort_alphabetically);
1790f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        menu.add(0, MENU_TIMEZONE, 0, R.string.zone_list_menu_sort_by_timezone)
1800f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            .setIcon(R.drawable.ic_menu_3d_globe);
1810f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        super.onCreateOptionsMenu(menu, inflater);
182afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
1830f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1840f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    @Override
1850f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public void onPrepareOptionsMenu(Menu menu) {
1860f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        if (mSortedByTimezone) {
1870f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_TIMEZONE).setVisible(false);
1880f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_ALPHABETICAL).setVisible(true);
1890f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        } else {
1900f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_TIMEZONE).setVisible(true);
1910f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_ALPHABETICAL).setVisible(false);
1920f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
193afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
194afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
195afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
1960f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public boolean onOptionsItemSelected(MenuItem item) {
1970f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        switch (item.getItemId()) {
1980f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1990f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            case MENU_TIMEZONE:
2000f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                setSorting(true);
2010f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return true;
2020f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2030f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            case MENU_ALPHABETICAL:
2040f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                setSorting(false);
2050f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return true;
2060f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2070f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            default:
2080f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return false;
2090f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
2100f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
2110f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2120f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public void setZoneSelectionListener(ZoneSelectionListener listener) {
2130f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        mListener = listener;
2140f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
2150f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2162571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private void setSorting(boolean sortByTimezone) {
2172571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final SimpleAdapter adapter =
2182571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                sortByTimezone ? mTimezoneSortedAdapter : mAlphabeticalAdapter;
2192571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        setListAdapter(adapter);
2202571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        mSortedByTimezone = sortByTimezone;
2212571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final int defaultIndex = getTimeZoneIndex(adapter, TimeZone.getDefault());
2222571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        if (defaultIndex >= 0) {
2232571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            setSelection(defaultIndex);
2242571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        }
2250f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
2260f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
227f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes    static class ZoneGetter {
228f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        private final List<HashMap<String, Object>> mZones =
229f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                new ArrayList<HashMap<String, Object>>();
230f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        private final HashSet<String> mLocalZones = new HashSet<String>();
231f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        private final Date mNow = Calendar.getInstance().getTime();
232f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        private final SimpleDateFormat mZoneNameFormatter = new SimpleDateFormat("zzzz");
233f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes
234f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        private List<HashMap<String, Object>> getZones(Context context) {
235f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            for (String olsonId : TimeZoneNames.forLocale(Locale.getDefault())) {
236f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                mLocalZones.add(olsonId);
237f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            }
238f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            try {
239f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones);
240f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                while (xrp.next() != XmlResourceParser.START_TAG) {
241f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    continue;
2420f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                }
243f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                xrp.next();
2440f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                while (xrp.getEventType() != XmlResourceParser.END_TAG) {
245f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    while (xrp.getEventType() != XmlResourceParser.START_TAG) {
246f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                        if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) {
247f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                            return mZones;
248f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                        }
249f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                        xrp.next();
250f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    }
251f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    if (xrp.getName().equals(XMLTAG_TIMEZONE)) {
252f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                        String olsonId = xrp.getAttributeValue(0);
253f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                        addTimeZone(olsonId);
254f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    }
255f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    while (xrp.getEventType() != XmlResourceParser.END_TAG) {
256f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                        xrp.next();
257f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                    }
2580f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    xrp.next();
2590f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                }
260f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                xrp.close();
261f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            } catch (XmlPullParserException xppe) {
262f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                Log.e(TAG, "Ill-formatted timezones.xml file");
263f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            } catch (java.io.IOException ioe) {
264f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                Log.e(TAG, "Unable to read timezones.xml file");
2650f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            }
266f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            return mZones;
2670f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
2680f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
269f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes        private void addTimeZone(String olsonId) {
270f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            // We always need the "GMT-07:00" string.
271f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            final TimeZone tz = TimeZone.getTimeZone(olsonId);
272f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes
273f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            // For the display name, we treat time zones within the country differently
274f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            // from other countries' time zones. So in en_US you'd get "Pacific Daylight Time"
275f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            // but in de_DE you'd get "Los Angeles" for the same time zone.
276f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            String displayName;
277f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            if (mLocalZones.contains(olsonId)) {
278f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                // Within a country, we just use the local name for the time zone.
279f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                mZoneNameFormatter.setTimeZone(tz);
280f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                displayName = mZoneNameFormatter.format(mNow);
281f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            } else {
282f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                // For other countries' time zones, we use the exemplar location.
283f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                final String localeName = Locale.getDefault().toString();
284f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes                displayName = TimeZoneNames.getExemplarLocation(localeName, olsonId);
285f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            }
2860f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
287f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            final HashMap<String, Object> map = new HashMap<String, Object>();
288f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            map.put(KEY_ID, olsonId);
289f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            map.put(KEY_DISPLAYNAME, displayName);
29004487594d73c89aa53548e6ad864e40d15324c62Elliott Hughes            map.put(KEY_GMT, DateTimeSettings.getTimeZoneText(tz, false));
291f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            map.put(KEY_OFFSET, tz.getOffset(mNow.getTime()));
2920f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
293f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            mZones.add(map);
2940f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
295afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
2960f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
297afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
2982571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public void onListItemClick(ListView listView, View v, int position, long id) {
2998287658863ffa8885c34abfc07e020e5275619f6Amith Yamasani        // Ignore extra clicks
3008287658863ffa8885c34abfc07e020e5275619f6Amith Yamasani        if (!isResumed()) return;
3012571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final Map<?, ?> map = (Map<?, ?>)listView.getItemAtPosition(position);
3022571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final String tzId = (String) map.get(KEY_ID);
3032571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
3040f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        // Update the system timezone value
3050f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        final Activity activity = getActivity();
3062571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final AlarmManager alarm = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE);
30771cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        alarm.setTimeZone(tzId);
30871cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        final TimeZone tz = TimeZone.getTimeZone(tzId);
3090f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        if (mListener != null) {
31071cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa            mListener.onZoneSelected(tz);
31171cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        } else {
31271cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa            getActivity().onBackPressed();
3130f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3140f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
3150f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3162571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static class MyComparator implements Comparator<HashMap<?, ?>> {
3170f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        private String mSortingKey;
3180f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3190f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        public MyComparator(String sortingKey) {
3200f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            mSortingKey = sortingKey;
3210f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3220f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3230f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        public void setSortingKey(String sortingKey) {
3240f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            mSortingKey = sortingKey;
325afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
3260f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3272571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        public int compare(HashMap<?, ?> map1, HashMap<?, ?> map2) {
3280f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            Object value1 = map1.get(mSortingKey);
3290f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            Object value2 = map2.get(mSortingKey);
3300f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3310f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            /*
3320f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa             * This should never happen, but just in-case, put non-comparable
3330f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa             * items at the end.
3340f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa             */
3350f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            if (!isComparable(value1)) {
3360f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return isComparable(value2) ? 1 : 0;
3370f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            } else if (!isComparable(value2)) {
3380f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return -1;
3390f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            }
3400f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3410f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            return ((Comparable) value1).compareTo(value2);
3420f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3430f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3440f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        private boolean isComparable(Object value) {
345f1582bc3f58ac440c11c54b844287915594b433fElliott Hughes            return (value != null) && (value instanceof Comparable);
3460f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3470f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
348afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
349