ZonePicker.java revision 0688f251af533c09682c791ae20834ab7854d7d7
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;
260f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.view.Menu;
270f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.view.MenuInflater;
280f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.view.MenuItem;
29afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.view.View;
30afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport android.widget.ListView;
310f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport android.widget.SimpleAdapter;
32afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
330f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport org.xmlpull.v1.XmlPullParserException;
340f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
350f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.ArrayList;
360f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.Calendar;
370f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.Collections;
380f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.Comparator;
39afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.HashMap;
40afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.List;
41afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Projectimport java.util.Map;
420f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawaimport java.util.TimeZone;
430f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
440f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa/**
450f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * The class displaying a list of time zones that match a filter string
460f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * such as "Africa", "Europe", etc. Choosing an item from the list will set
470f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * the time zone. Pressing Back without choosing from the list will not
480f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa * result in a change in the time zone setting.
490f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa */
500f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawapublic class ZonePicker extends ListFragment {
510f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final String TAG = "ZonePicker";
520f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
530f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public static interface ZoneSelectionListener {
540f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        // You can add any argument if you really need it...
5571cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        public void onZoneSelected(TimeZone tz);
560f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
570f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
582571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_ID = "id";  // value: String
592571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_DISPLAYNAME = "name";  // value: String
602571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_GMT = "gmt";  // value: String
612571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static final String KEY_OFFSET = "offset";  // value: int (Integer)
620f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final String XMLTAG_TIMEZONE = "timezone";
630f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
640f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final int HOURS_1 = 60 * 60000;
650f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
660f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final int MENU_TIMEZONE = Menu.FIRST+1;
670f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private static final int MENU_ALPHABETICAL = Menu.FIRST;
680f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
690f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private boolean mSortedByTimezone;
700f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
710f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private SimpleAdapter mTimezoneSortedAdapter;
720f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private SimpleAdapter mAlphabeticalAdapter;
730f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
740f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    private ZoneSelectionListener mListener;
750f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
762571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    /**
772571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * Constructs an adapter with TimeZone list. Sorted by TimeZone in default.
782571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     *
792571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param sortedByName use Name for sorting the list.
802571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     */
812571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public static SimpleAdapter constructTimezoneAdapter(Context context,
822571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            boolean sortedByName) {
830688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa        return constructTimezoneAdapter(context, sortedByName,
840688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa                android.R.layout.simple_list_item_2);
850688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa    }
860688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa
870688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa    /**
880688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     * Constructs an adapter with TimeZone list. Sorted by TimeZone in default.
890688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     *
900688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     * @param sortedByName use Name for sorting the list.
910688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa     */
920688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa    public static SimpleAdapter constructTimezoneAdapter(Context context,
930688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa            boolean sortedByName, int layoutId) {
940f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        final String[] from = new String[] {KEY_DISPLAYNAME, KEY_GMT};
950f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        final int[] to = new int[] {android.R.id.text1, android.R.id.text2};
96afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
972571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final String sortKey = (sortedByName ? KEY_DISPLAYNAME : KEY_OFFSET);
982571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final MyComparator comparator = new MyComparator(sortKey);
992571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final List<HashMap<String, Object>> sortedList = getZones(context);
1002571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        Collections.sort(sortedList, comparator);
1012571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final SimpleAdapter adapter = new SimpleAdapter(context,
1022571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                sortedList,
1030688f251af533c09682c791ae20834ab7854d7d7Daisuke Miyakawa                layoutId,
1040f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                from,
1050f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                to);
1060f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1072571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        return adapter;
1082571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    }
1092571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1102571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    /**
1112571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * Searches {@link TimeZone} from the given {@link SimpleAdapter} object, and returns
1122571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * the index for the TimeZone.
1132571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     *
1142571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param adapter SimpleAdapter constructed by
1152571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * {@link #constructTimezoneAdapter(Context, boolean)}.
1162571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param tz TimeZone to be searched.
1172571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @return Index for the given TimeZone. -1 when there's no corresponding list item.
1182571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * returned.
1192571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     */
1202571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public static int getTimeZoneIndex(SimpleAdapter adapter, TimeZone tz) {
1212571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final String defaultId = tz.getID();
1222571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final int listSize = adapter.getCount();
1232571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        for (int i = 0; i < listSize; i++) {
1242571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            // Using HashMap<String, Object> induces unnecessary warning.
1252571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            final HashMap<?,?> map = (HashMap<?,?>)adapter.getItem(i);
1262571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            final String id = (String)map.get(KEY_ID);
1272571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            if (defaultId.equals(id)) {
1282571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                // If current timezone is in this list, move focus to it
1292571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                return i;
1302571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            }
1312571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        }
1322571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        return -1;
1332571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    }
1342571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1352571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    /**
1362571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @param item one of items in adapters. The adapter should be constructed by
1372571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * {@link #constructTimezoneAdapter(Context, boolean)}.
1382571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     * @return TimeZone object corresponding to the item.
1392571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa     */
1402571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public static TimeZone obtainTimeZoneFromItem(Object item) {
1412571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        return TimeZone.getTimeZone((String)((Map<?, ?>)item).get(KEY_ID));
1422571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    }
1432571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1442571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    @Override
1452571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public void onActivityCreated(Bundle savedInstanseState) {
1462571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        super.onActivityCreated(savedInstanseState);
1472571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
1482571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final Activity activity = getActivity();
1492571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        mTimezoneSortedAdapter = constructTimezoneAdapter(activity, false);
1502571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        mAlphabeticalAdapter = constructTimezoneAdapter(activity, true);
1510f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1520f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        // Sets the adapter
1530f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        setSorting(true);
1541e9d497e2b0a3d00e83372d536b79c9ec0646b9dDaisuke Miyakawa        setHasOptionsMenu(true);
1550f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
156afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
157afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
1580f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1590f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        menu.add(0, MENU_ALPHABETICAL, 0, R.string.zone_list_menu_sort_alphabetically)
1600f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            .setIcon(android.R.drawable.ic_menu_sort_alphabetically);
1610f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        menu.add(0, MENU_TIMEZONE, 0, R.string.zone_list_menu_sort_by_timezone)
1620f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            .setIcon(R.drawable.ic_menu_3d_globe);
1630f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        super.onCreateOptionsMenu(menu, inflater);
164afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
1650f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1660f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    @Override
1670f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public void onPrepareOptionsMenu(Menu menu) {
1680f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        if (mSortedByTimezone) {
1690f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_TIMEZONE).setVisible(false);
1700f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_ALPHABETICAL).setVisible(true);
1710f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        } else {
1720f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_TIMEZONE).setVisible(true);
1730f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            menu.findItem(MENU_ALPHABETICAL).setVisible(false);
1740f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
175afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
176afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project
177afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
1780f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public boolean onOptionsItemSelected(MenuItem item) {
1790f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        switch (item.getItemId()) {
1800f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1810f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            case MENU_TIMEZONE:
1820f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                setSorting(true);
1830f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return true;
1840f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1850f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            case MENU_ALPHABETICAL:
1860f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                setSorting(false);
1870f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return true;
1880f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1890f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            default:
1900f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return false;
1910f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
1920f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
1930f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1940f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    public void setZoneSelectionListener(ZoneSelectionListener listener) {
1950f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        mListener = listener;
1960f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
1970f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
1982571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private void setSorting(boolean sortByTimezone) {
1992571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final SimpleAdapter adapter =
2002571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa                sortByTimezone ? mTimezoneSortedAdapter : mAlphabeticalAdapter;
2012571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        setListAdapter(adapter);
2022571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        mSortedByTimezone = sortByTimezone;
2032571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final int defaultIndex = getTimeZoneIndex(adapter, TimeZone.getDefault());
2042571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        if (defaultIndex >= 0) {
2052571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            setSelection(defaultIndex);
2062571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        }
2070f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
2080f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2092571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static List<HashMap<String, Object>> getZones(Context context) {
2102571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final List<HashMap<String, Object>> myData = new ArrayList<HashMap<String, Object>>();
2112571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final long date = Calendar.getInstance().getTimeInMillis();
2120f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        try {
2132571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones);
2140f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            while (xrp.next() != XmlResourceParser.START_TAG)
2150f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                continue;
2160f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            xrp.next();
2170f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            while (xrp.getEventType() != XmlResourceParser.END_TAG) {
2180f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                while (xrp.getEventType() != XmlResourceParser.START_TAG) {
2190f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) {
2200f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                        return myData;
2210f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    }
2220f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    xrp.next();
2230f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                }
2240f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                if (xrp.getName().equals(XMLTAG_TIMEZONE)) {
2250f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    String id = xrp.getAttributeValue(0);
2260f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    String displayName = xrp.nextText();
2270f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    addItem(myData, id, displayName, date);
2280f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                }
2290f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                while (xrp.getEventType() != XmlResourceParser.END_TAG) {
2300f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                    xrp.next();
2310f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                }
2320f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                xrp.next();
2330f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            }
2340f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            xrp.close();
2350f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        } catch (XmlPullParserException xppe) {
2360f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            Log.e(TAG, "Ill-formatted timezones.xml file");
2370f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        } catch (java.io.IOException ioe) {
2380f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            Log.e(TAG, "Unable to read timezones.xml file");
2390f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
2400f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2410f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        return myData;
2420f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
2430f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2442571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static void addItem(
2452571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa            List<HashMap<String, Object>> myData, String id, String displayName, long date) {
2462571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final HashMap<String, Object> map = new HashMap<String, Object>();
2470f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        map.put(KEY_ID, id);
2480f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        map.put(KEY_DISPLAYNAME, displayName);
2492571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final TimeZone tz = TimeZone.getTimeZone(id);
2502571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final int offset = tz.getOffset(date);
2512571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final int p = Math.abs(offset);
2522571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final StringBuilder name = new StringBuilder();
2530f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        name.append("GMT");
2540f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2550f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        if (offset < 0) {
2560f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            name.append('-');
2570f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        } else {
2580f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            name.append('+');
2590f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
2600f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2610f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        name.append(p / (HOURS_1));
2620f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        name.append(':');
2630f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2640f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        int min = p / 60000;
2650f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        min %= 60;
2660f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2670f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        if (min < 10) {
2680f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            name.append('0');
2690f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
2700f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        name.append(min);
2710f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2720f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        map.put(KEY_GMT, name.toString());
2730f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        map.put(KEY_OFFSET, offset);
2740f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2750f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        myData.add(map);
276afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    }
2770f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
278afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project    @Override
2792571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    public void onListItemClick(ListView listView, View v, int position, long id) {
2802571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final Map<?, ?> map = (Map<?, ?>)listView.getItemAtPosition(position);
2812571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final String tzId = (String) map.get(KEY_ID);
2822571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa
2830f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        // Update the system timezone value
2840f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        final Activity activity = getActivity();
2852571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        final AlarmManager alarm = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE);
28671cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        alarm.setTimeZone(tzId);
28771cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        final TimeZone tz = TimeZone.getTimeZone(tzId);
2880f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        if (mListener != null) {
28971cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa            mListener.onZoneSelected(tz);
29071cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa        } else {
29171cc548f7ee51ff77a2c1dfb5da7a3f7b6c55fd5Daisuke Miyakawa            getActivity().onBackPressed();
2920f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
2930f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
2940f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2952571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa    private static class MyComparator implements Comparator<HashMap<?, ?>> {
2960f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        private String mSortingKey;
2970f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
2980f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        public MyComparator(String sortingKey) {
2990f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            mSortingKey = sortingKey;
3000f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3010f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3020f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        public void setSortingKey(String sortingKey) {
3030f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            mSortingKey = sortingKey;
304afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project        }
3050f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3062571f0dcb1cc96b7220687aff6fcddc623b57c3cDaisuke Miyakawa        public int compare(HashMap<?, ?> map1, HashMap<?, ?> map2) {
3070f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            Object value1 = map1.get(mSortingKey);
3080f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            Object value2 = map2.get(mSortingKey);
3090f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3100f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            /*
3110f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa             * This should never happen, but just in-case, put non-comparable
3120f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa             * items at the end.
3130f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa             */
3140f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            if (!isComparable(value1)) {
3150f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return isComparable(value2) ? 1 : 0;
3160f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            } else if (!isComparable(value2)) {
3170f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa                return -1;
3180f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            }
3190f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3200f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            return ((Comparable) value1).compareTo(value2);
3210f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3220f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa
3230f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        private boolean isComparable(Object value) {
3240f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa            return (value != null) && (value instanceof Comparable);
3250f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa        }
3260f4f2f3a81f2a6d7100b4cff0d8de062cb2bc8f6Daisuke Miyakawa    }
327afc4ab2ffbb8327ddce9907961295a32cbf49d0fThe Android Open Source Project}
328