171ad58c751eb12a500916556c41e704a93895801Erik/*
271ad58c751eb12a500916556c41e704a93895801Erik * Copyright (C) 2010 The Android Open Source Project
371ad58c751eb12a500916556c41e704a93895801Erik *
471ad58c751eb12a500916556c41e704a93895801Erik * Licensed under the Apache License, Version 2.0 (the "License");
571ad58c751eb12a500916556c41e704a93895801Erik * you may not use this file except in compliance with the License.
671ad58c751eb12a500916556c41e704a93895801Erik * You may obtain a copy of the License at
771ad58c751eb12a500916556c41e704a93895801Erik *
871ad58c751eb12a500916556c41e704a93895801Erik *      http://www.apache.org/licenses/LICENSE-2.0
971ad58c751eb12a500916556c41e704a93895801Erik *
1071ad58c751eb12a500916556c41e704a93895801Erik * Unless required by applicable law or agreed to in writing, software
1171ad58c751eb12a500916556c41e704a93895801Erik * distributed under the License is distributed on an "AS IS" BASIS,
1271ad58c751eb12a500916556c41e704a93895801Erik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1371ad58c751eb12a500916556c41e704a93895801Erik * See the License for the specific language governing permissions and
1471ad58c751eb12a500916556c41e704a93895801Erik * limitations under the License.
1571ad58c751eb12a500916556c41e704a93895801Erik */
1671ad58c751eb12a500916556c41e704a93895801Erik
1771ad58c751eb12a500916556c41e704a93895801Erikpackage android.util;
1871ad58c751eb12a500916556c41e704a93895801Erik
1971ad58c751eb12a500916556c41e704a93895801Erikimport android.content.AsyncQueryHandler;
2071ad58c751eb12a500916556c41e704a93895801Erikimport android.content.ContentResolver;
2171ad58c751eb12a500916556c41e704a93895801Erikimport android.content.ContentValues;
2271ad58c751eb12a500916556c41e704a93895801Erikimport android.content.Context;
2371ad58c751eb12a500916556c41e704a93895801Erikimport android.content.SharedPreferences;
2471ad58c751eb12a500916556c41e704a93895801Erikimport android.database.Cursor;
2571ad58c751eb12a500916556c41e704a93895801Erikimport android.provider.Calendar.CalendarCache;
2671ad58c751eb12a500916556c41e704a93895801Erikimport android.text.TextUtils;
2771ad58c751eb12a500916556c41e704a93895801Erikimport android.text.format.DateUtils;
2871ad58c751eb12a500916556c41e704a93895801Erikimport android.text.format.Time;
2971ad58c751eb12a500916556c41e704a93895801Erik
3071ad58c751eb12a500916556c41e704a93895801Erikimport java.util.Formatter;
3171ad58c751eb12a500916556c41e704a93895801Erikimport java.util.HashSet;
3271ad58c751eb12a500916556c41e704a93895801Erikimport java.util.Locale;
3371ad58c751eb12a500916556c41e704a93895801Erik
3471ad58c751eb12a500916556c41e704a93895801Erik/**
3571ad58c751eb12a500916556c41e704a93895801Erik * A class containing utility methods related to Calendar apps.
3671ad58c751eb12a500916556c41e704a93895801Erik *
3771ad58c751eb12a500916556c41e704a93895801Erik * @hide
3871ad58c751eb12a500916556c41e704a93895801Erik */
3971ad58c751eb12a500916556c41e704a93895801Erikpublic class CalendarUtils {
4071ad58c751eb12a500916556c41e704a93895801Erik    private static final boolean DEBUG = false;
4171ad58c751eb12a500916556c41e704a93895801Erik    private static final String TAG = "CalendarUtils";
4271ad58c751eb12a500916556c41e704a93895801Erik
4371ad58c751eb12a500916556c41e704a93895801Erik    /**
4471ad58c751eb12a500916556c41e704a93895801Erik     * This class contains methods specific to reading and writing time zone
4571ad58c751eb12a500916556c41e704a93895801Erik     * values.
4671ad58c751eb12a500916556c41e704a93895801Erik     */
4771ad58c751eb12a500916556c41e704a93895801Erik    public static class TimeZoneUtils {
48426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik        private static final String[] TIMEZONE_TYPE_ARGS = { CalendarCache.TIMEZONE_KEY_TYPE };
49426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik        private static final String[] TIMEZONE_INSTANCES_ARGS =
50426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                { CalendarCache.TIMEZONE_KEY_INSTANCES };
51426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik
5271ad58c751eb12a500916556c41e704a93895801Erik        private static StringBuilder mSB = new StringBuilder(50);
5371ad58c751eb12a500916556c41e704a93895801Erik        private static Formatter mF = new Formatter(mSB, Locale.getDefault());
5471ad58c751eb12a500916556c41e704a93895801Erik        private volatile static boolean mFirstTZRequest = true;
5571ad58c751eb12a500916556c41e704a93895801Erik        private volatile static boolean mTZQueryInProgress = false;
5671ad58c751eb12a500916556c41e704a93895801Erik
5771ad58c751eb12a500916556c41e704a93895801Erik        private volatile static boolean mUseHomeTZ = false;
5871ad58c751eb12a500916556c41e704a93895801Erik        private volatile static String mHomeTZ = Time.getCurrentTimezone();
5971ad58c751eb12a500916556c41e704a93895801Erik
6071ad58c751eb12a500916556c41e704a93895801Erik        private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
6171ad58c751eb12a500916556c41e704a93895801Erik        private static int mToken = 1;
6271ad58c751eb12a500916556c41e704a93895801Erik        private static AsyncTZHandler mHandler;
6371ad58c751eb12a500916556c41e704a93895801Erik
6471ad58c751eb12a500916556c41e704a93895801Erik        // The name of the shared preferences file. This name must be maintained for historical
6571ad58c751eb12a500916556c41e704a93895801Erik        // reasons, as it's what PreferenceManager assigned the first time the file was created.
6671ad58c751eb12a500916556c41e704a93895801Erik        private final String mPrefsName;
6771ad58c751eb12a500916556c41e704a93895801Erik
6871ad58c751eb12a500916556c41e704a93895801Erik        /**
6971ad58c751eb12a500916556c41e704a93895801Erik         * This is the key used for writing whether or not a home time zone should
7071ad58c751eb12a500916556c41e704a93895801Erik         * be used in the Calendar app to the Calendar Preferences.
7171ad58c751eb12a500916556c41e704a93895801Erik         */
7271ad58c751eb12a500916556c41e704a93895801Erik        public static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
7371ad58c751eb12a500916556c41e704a93895801Erik        /**
7471ad58c751eb12a500916556c41e704a93895801Erik         * This is the key used for writing the time zone that should be used if
7571ad58c751eb12a500916556c41e704a93895801Erik         * home time zones are enabled for the Calendar app.
7671ad58c751eb12a500916556c41e704a93895801Erik         */
7771ad58c751eb12a500916556c41e704a93895801Erik        public static final String KEY_HOME_TZ = "preferences_home_tz";
7871ad58c751eb12a500916556c41e704a93895801Erik
7971ad58c751eb12a500916556c41e704a93895801Erik        /**
8071ad58c751eb12a500916556c41e704a93895801Erik         * This is a helper class for handling the async queries and updates for the
8171ad58c751eb12a500916556c41e704a93895801Erik         * time zone settings in Calendar.
8271ad58c751eb12a500916556c41e704a93895801Erik         */
8371ad58c751eb12a500916556c41e704a93895801Erik        private class AsyncTZHandler extends AsyncQueryHandler {
8471ad58c751eb12a500916556c41e704a93895801Erik            public AsyncTZHandler(ContentResolver cr) {
8571ad58c751eb12a500916556c41e704a93895801Erik                super(cr);
8671ad58c751eb12a500916556c41e704a93895801Erik            }
8771ad58c751eb12a500916556c41e704a93895801Erik
8871ad58c751eb12a500916556c41e704a93895801Erik            @Override
8971ad58c751eb12a500916556c41e704a93895801Erik            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
9071ad58c751eb12a500916556c41e704a93895801Erik                synchronized (mTZCallbacks) {
9171ad58c751eb12a500916556c41e704a93895801Erik                    boolean writePrefs = false;
9271ad58c751eb12a500916556c41e704a93895801Erik                    // Check the values in the db
9371ad58c751eb12a500916556c41e704a93895801Erik                    int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
9471ad58c751eb12a500916556c41e704a93895801Erik                    int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
9571ad58c751eb12a500916556c41e704a93895801Erik                    while(cursor.moveToNext()) {
9671ad58c751eb12a500916556c41e704a93895801Erik                        String key = cursor.getString(keyColumn);
9771ad58c751eb12a500916556c41e704a93895801Erik                        String value = cursor.getString(valueColumn);
9871ad58c751eb12a500916556c41e704a93895801Erik                        if (TextUtils.equals(key, CalendarCache.TIMEZONE_KEY_TYPE)) {
9971ad58c751eb12a500916556c41e704a93895801Erik                            boolean useHomeTZ = !TextUtils.equals(
10071ad58c751eb12a500916556c41e704a93895801Erik                                    value, CalendarCache.TIMEZONE_TYPE_AUTO);
10171ad58c751eb12a500916556c41e704a93895801Erik                            if (useHomeTZ != mUseHomeTZ) {
10271ad58c751eb12a500916556c41e704a93895801Erik                                writePrefs = true;
10371ad58c751eb12a500916556c41e704a93895801Erik                                mUseHomeTZ = useHomeTZ;
10471ad58c751eb12a500916556c41e704a93895801Erik                            }
10571ad58c751eb12a500916556c41e704a93895801Erik                        } else if (TextUtils.equals(
10671ad58c751eb12a500916556c41e704a93895801Erik                                key, CalendarCache.TIMEZONE_KEY_INSTANCES_PREVIOUS)) {
10771ad58c751eb12a500916556c41e704a93895801Erik                            if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
10871ad58c751eb12a500916556c41e704a93895801Erik                                writePrefs = true;
10971ad58c751eb12a500916556c41e704a93895801Erik                                mHomeTZ = value;
11071ad58c751eb12a500916556c41e704a93895801Erik                            }
11171ad58c751eb12a500916556c41e704a93895801Erik                        }
11271ad58c751eb12a500916556c41e704a93895801Erik                    }
1135ba5de93c71218c505f28d0b05c638afa6f4d1d3Erik                    cursor.close();
11471ad58c751eb12a500916556c41e704a93895801Erik                    if (writePrefs) {
11571ad58c751eb12a500916556c41e704a93895801Erik                        SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName);
11671ad58c751eb12a500916556c41e704a93895801Erik                        // Write the prefs
11771ad58c751eb12a500916556c41e704a93895801Erik                        setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
11871ad58c751eb12a500916556c41e704a93895801Erik                        setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
11971ad58c751eb12a500916556c41e704a93895801Erik                    }
12071ad58c751eb12a500916556c41e704a93895801Erik
12171ad58c751eb12a500916556c41e704a93895801Erik                    mTZQueryInProgress = false;
12271ad58c751eb12a500916556c41e704a93895801Erik                    for (Runnable callback : mTZCallbacks) {
12371ad58c751eb12a500916556c41e704a93895801Erik                        if (callback != null) {
12471ad58c751eb12a500916556c41e704a93895801Erik                            callback.run();
12571ad58c751eb12a500916556c41e704a93895801Erik                        }
12671ad58c751eb12a500916556c41e704a93895801Erik                    }
12771ad58c751eb12a500916556c41e704a93895801Erik                    mTZCallbacks.clear();
12871ad58c751eb12a500916556c41e704a93895801Erik                }
12971ad58c751eb12a500916556c41e704a93895801Erik            }
13071ad58c751eb12a500916556c41e704a93895801Erik        }
13171ad58c751eb12a500916556c41e704a93895801Erik
13271ad58c751eb12a500916556c41e704a93895801Erik        /**
13371ad58c751eb12a500916556c41e704a93895801Erik         * The name of the file where the shared prefs for Calendar are stored
13471ad58c751eb12a500916556c41e704a93895801Erik         * must be provided. All activities within an app should provide the
13571ad58c751eb12a500916556c41e704a93895801Erik         * same preferences name or behavior may become erratic.
13671ad58c751eb12a500916556c41e704a93895801Erik         *
13771ad58c751eb12a500916556c41e704a93895801Erik         * @param prefsName
13871ad58c751eb12a500916556c41e704a93895801Erik         */
13971ad58c751eb12a500916556c41e704a93895801Erik        public TimeZoneUtils(String prefsName) {
14071ad58c751eb12a500916556c41e704a93895801Erik            mPrefsName = prefsName;
14171ad58c751eb12a500916556c41e704a93895801Erik        }
14271ad58c751eb12a500916556c41e704a93895801Erik
14371ad58c751eb12a500916556c41e704a93895801Erik        /**
14471ad58c751eb12a500916556c41e704a93895801Erik         * Formats a date or a time range according to the local conventions.
14571ad58c751eb12a500916556c41e704a93895801Erik         *
14671ad58c751eb12a500916556c41e704a93895801Erik         * This formats a date/time range using Calendar's time zone and the
14771ad58c751eb12a500916556c41e704a93895801Erik         * local conventions for the region of the device.
14871ad58c751eb12a500916556c41e704a93895801Erik         *
149d762a347fb6459d7b7c87d6f09a58b210400cb95Erik         * If the {@link DateUtils#FORMAT_UTC} flag is used it will pass in
150d762a347fb6459d7b7c87d6f09a58b210400cb95Erik         * the UTC time zone instead.
151d762a347fb6459d7b7c87d6f09a58b210400cb95Erik         *
15271ad58c751eb12a500916556c41e704a93895801Erik         * @param context the context is required only if the time is shown
15371ad58c751eb12a500916556c41e704a93895801Erik         * @param startMillis the start time in UTC milliseconds
15471ad58c751eb12a500916556c41e704a93895801Erik         * @param endMillis the end time in UTC milliseconds
15571ad58c751eb12a500916556c41e704a93895801Erik         * @param flags a bit mask of options See
15671ad58c751eb12a500916556c41e704a93895801Erik         * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
15771ad58c751eb12a500916556c41e704a93895801Erik         * @return a string containing the formatted date/time range.
15871ad58c751eb12a500916556c41e704a93895801Erik         */
15971ad58c751eb12a500916556c41e704a93895801Erik        public String formatDateRange(Context context, long startMillis,
16071ad58c751eb12a500916556c41e704a93895801Erik                long endMillis, int flags) {
16171ad58c751eb12a500916556c41e704a93895801Erik            String date;
162d762a347fb6459d7b7c87d6f09a58b210400cb95Erik            String tz;
163d762a347fb6459d7b7c87d6f09a58b210400cb95Erik            if ((flags & DateUtils.FORMAT_UTC) != 0) {
164d762a347fb6459d7b7c87d6f09a58b210400cb95Erik                tz = Time.TIMEZONE_UTC;
165d762a347fb6459d7b7c87d6f09a58b210400cb95Erik            } else {
166d762a347fb6459d7b7c87d6f09a58b210400cb95Erik                tz = getTimeZone(context, null);
167d762a347fb6459d7b7c87d6f09a58b210400cb95Erik            }
16871ad58c751eb12a500916556c41e704a93895801Erik            synchronized (mSB) {
16971ad58c751eb12a500916556c41e704a93895801Erik                mSB.setLength(0);
17071ad58c751eb12a500916556c41e704a93895801Erik                date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
171d762a347fb6459d7b7c87d6f09a58b210400cb95Erik                        tz).toString();
17271ad58c751eb12a500916556c41e704a93895801Erik            }
17371ad58c751eb12a500916556c41e704a93895801Erik            return date;
17471ad58c751eb12a500916556c41e704a93895801Erik        }
17571ad58c751eb12a500916556c41e704a93895801Erik
17671ad58c751eb12a500916556c41e704a93895801Erik        /**
17771ad58c751eb12a500916556c41e704a93895801Erik         * Writes a new home time zone to the db.
17871ad58c751eb12a500916556c41e704a93895801Erik         *
17971ad58c751eb12a500916556c41e704a93895801Erik         * Updates the home time zone in the db asynchronously and updates
18071ad58c751eb12a500916556c41e704a93895801Erik         * the local cache. Sending a time zone of
18171ad58c751eb12a500916556c41e704a93895801Erik         * {@link CalendarCache#TIMEZONE_TYPE_AUTO} will cause it to be set
18271ad58c751eb12a500916556c41e704a93895801Erik         * to the device's time zone. null or empty tz will be ignored.
18371ad58c751eb12a500916556c41e704a93895801Erik         *
18471ad58c751eb12a500916556c41e704a93895801Erik         * @param context The calling activity
18571ad58c751eb12a500916556c41e704a93895801Erik         * @param timeZone The time zone to set Calendar to, or
18671ad58c751eb12a500916556c41e704a93895801Erik         * {@link CalendarCache#TIMEZONE_TYPE_AUTO}
18771ad58c751eb12a500916556c41e704a93895801Erik         */
18871ad58c751eb12a500916556c41e704a93895801Erik        public void setTimeZone(Context context, String timeZone) {
18971ad58c751eb12a500916556c41e704a93895801Erik            if (TextUtils.isEmpty(timeZone)) {
19071ad58c751eb12a500916556c41e704a93895801Erik                if (DEBUG) {
19171ad58c751eb12a500916556c41e704a93895801Erik                    Log.d(TAG, "Empty time zone, nothing to be done.");
19271ad58c751eb12a500916556c41e704a93895801Erik                }
19371ad58c751eb12a500916556c41e704a93895801Erik                return;
19471ad58c751eb12a500916556c41e704a93895801Erik            }
19571ad58c751eb12a500916556c41e704a93895801Erik            boolean updatePrefs = false;
19671ad58c751eb12a500916556c41e704a93895801Erik            synchronized (mTZCallbacks) {
19771ad58c751eb12a500916556c41e704a93895801Erik                if (CalendarCache.TIMEZONE_TYPE_AUTO.equals(timeZone)) {
19871ad58c751eb12a500916556c41e704a93895801Erik                    if (mUseHomeTZ) {
19971ad58c751eb12a500916556c41e704a93895801Erik                        updatePrefs = true;
20071ad58c751eb12a500916556c41e704a93895801Erik                    }
20171ad58c751eb12a500916556c41e704a93895801Erik                    mUseHomeTZ = false;
20271ad58c751eb12a500916556c41e704a93895801Erik                } else {
20371ad58c751eb12a500916556c41e704a93895801Erik                    if (!mUseHomeTZ || !TextUtils.equals(mHomeTZ, timeZone)) {
20471ad58c751eb12a500916556c41e704a93895801Erik                        updatePrefs = true;
20571ad58c751eb12a500916556c41e704a93895801Erik                    }
20671ad58c751eb12a500916556c41e704a93895801Erik                    mUseHomeTZ = true;
20771ad58c751eb12a500916556c41e704a93895801Erik                    mHomeTZ = timeZone;
20871ad58c751eb12a500916556c41e704a93895801Erik                }
20971ad58c751eb12a500916556c41e704a93895801Erik            }
21071ad58c751eb12a500916556c41e704a93895801Erik            if (updatePrefs) {
21171ad58c751eb12a500916556c41e704a93895801Erik                // Write the prefs
21271ad58c751eb12a500916556c41e704a93895801Erik                SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
21371ad58c751eb12a500916556c41e704a93895801Erik                setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
21471ad58c751eb12a500916556c41e704a93895801Erik                setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
21571ad58c751eb12a500916556c41e704a93895801Erik
21671ad58c751eb12a500916556c41e704a93895801Erik                // Update the db
21771ad58c751eb12a500916556c41e704a93895801Erik                ContentValues values = new ContentValues();
21809bd4bf85e357fc8eaa5c6a219a8827159e865daErik                if (mHandler != null) {
21909bd4bf85e357fc8eaa5c6a219a8827159e865daErik                    mHandler.cancelOperation(mToken);
22071ad58c751eb12a500916556c41e704a93895801Erik                }
22171ad58c751eb12a500916556c41e704a93895801Erik
22209bd4bf85e357fc8eaa5c6a219a8827159e865daErik                mHandler = new AsyncTZHandler(context.getContentResolver());
22371ad58c751eb12a500916556c41e704a93895801Erik
22471ad58c751eb12a500916556c41e704a93895801Erik                // skip 0 so query can use it
22571ad58c751eb12a500916556c41e704a93895801Erik                if (++mToken == 0) {
22671ad58c751eb12a500916556c41e704a93895801Erik                    mToken = 1;
22771ad58c751eb12a500916556c41e704a93895801Erik                }
22871ad58c751eb12a500916556c41e704a93895801Erik
22971ad58c751eb12a500916556c41e704a93895801Erik                // Write the use home tz setting
23071ad58c751eb12a500916556c41e704a93895801Erik                values.put(CalendarCache.VALUE, mUseHomeTZ ? CalendarCache.TIMEZONE_TYPE_HOME
23171ad58c751eb12a500916556c41e704a93895801Erik                        : CalendarCache.TIMEZONE_TYPE_AUTO);
23271ad58c751eb12a500916556c41e704a93895801Erik                mHandler.startUpdate(mToken, null, CalendarCache.URI, values, CalendarCache.WHERE,
233426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                        TIMEZONE_TYPE_ARGS);
23471ad58c751eb12a500916556c41e704a93895801Erik
23571ad58c751eb12a500916556c41e704a93895801Erik                // If using a home tz write it to the db
23671ad58c751eb12a500916556c41e704a93895801Erik                if (mUseHomeTZ) {
237426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                    ContentValues values2 = new ContentValues();
238426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                    values2.put(CalendarCache.VALUE, mHomeTZ);
239426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                    mHandler.startUpdate(mToken, null, CalendarCache.URI, values2,
240426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                            CalendarCache.WHERE, TIMEZONE_INSTANCES_ARGS);
24171ad58c751eb12a500916556c41e704a93895801Erik                }
24271ad58c751eb12a500916556c41e704a93895801Erik            }
24371ad58c751eb12a500916556c41e704a93895801Erik        }
24471ad58c751eb12a500916556c41e704a93895801Erik
24571ad58c751eb12a500916556c41e704a93895801Erik        /**
24671ad58c751eb12a500916556c41e704a93895801Erik         * Gets the time zone that Calendar should be displayed in
24771ad58c751eb12a500916556c41e704a93895801Erik         *
24871ad58c751eb12a500916556c41e704a93895801Erik         * This is a helper method to get the appropriate time zone for Calendar. If this
24971ad58c751eb12a500916556c41e704a93895801Erik         * is the first time this method has been called it will initiate an asynchronous
25071ad58c751eb12a500916556c41e704a93895801Erik         * query to verify that the data in preferences is correct. The callback supplied
25171ad58c751eb12a500916556c41e704a93895801Erik         * will only be called if this query returns a value other than what is stored in
25271ad58c751eb12a500916556c41e704a93895801Erik         * preferences and should cause the calling activity to refresh anything that
25371ad58c751eb12a500916556c41e704a93895801Erik         * depends on calling this method.
25471ad58c751eb12a500916556c41e704a93895801Erik         *
25571ad58c751eb12a500916556c41e704a93895801Erik         * @param context The calling activity
25671ad58c751eb12a500916556c41e704a93895801Erik         * @param callback The runnable that should execute if a query returns new values
25771ad58c751eb12a500916556c41e704a93895801Erik         * @return The string value representing the time zone Calendar should display
25871ad58c751eb12a500916556c41e704a93895801Erik         */
25971ad58c751eb12a500916556c41e704a93895801Erik        public String getTimeZone(Context context, Runnable callback) {
26071ad58c751eb12a500916556c41e704a93895801Erik            synchronized (mTZCallbacks){
26171ad58c751eb12a500916556c41e704a93895801Erik                if (mFirstTZRequest) {
26271ad58c751eb12a500916556c41e704a93895801Erik                    mTZQueryInProgress = true;
26371ad58c751eb12a500916556c41e704a93895801Erik                    mFirstTZRequest = false;
26471ad58c751eb12a500916556c41e704a93895801Erik
26571ad58c751eb12a500916556c41e704a93895801Erik                    SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
26671ad58c751eb12a500916556c41e704a93895801Erik                    mUseHomeTZ = prefs.getBoolean(KEY_HOME_TZ_ENABLED, false);
26771ad58c751eb12a500916556c41e704a93895801Erik                    mHomeTZ = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone());
26871ad58c751eb12a500916556c41e704a93895801Erik
26971ad58c751eb12a500916556c41e704a93895801Erik                    // When the async query returns it should synchronize on
27071ad58c751eb12a500916556c41e704a93895801Erik                    // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the
27171ad58c751eb12a500916556c41e704a93895801Erik                    // preferences, set mTZQueryInProgress to false, and call all
27271ad58c751eb12a500916556c41e704a93895801Erik                    // the runnables in mTZCallbacks.
27371ad58c751eb12a500916556c41e704a93895801Erik                    if (mHandler == null) {
27471ad58c751eb12a500916556c41e704a93895801Erik                        mHandler = new AsyncTZHandler(context.getContentResolver());
27571ad58c751eb12a500916556c41e704a93895801Erik                    }
27671ad58c751eb12a500916556c41e704a93895801Erik                    mHandler.startQuery(0, context, CalendarCache.URI, CalendarCache.POJECTION,
27771ad58c751eb12a500916556c41e704a93895801Erik                            null, null, null);
27871ad58c751eb12a500916556c41e704a93895801Erik                }
27971ad58c751eb12a500916556c41e704a93895801Erik                if (mTZQueryInProgress) {
28071ad58c751eb12a500916556c41e704a93895801Erik                    mTZCallbacks.add(callback);
28171ad58c751eb12a500916556c41e704a93895801Erik                }
28271ad58c751eb12a500916556c41e704a93895801Erik            }
28371ad58c751eb12a500916556c41e704a93895801Erik            return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone();
28471ad58c751eb12a500916556c41e704a93895801Erik        }
285426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik
286426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik        /**
287426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         * Forces a query of the database to check for changes to the time zone.
288426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         * This should be called if another app may have modified the db. If a
289426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         * query is already in progress the callback will be added to the list
290426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         * of callbacks to be called when it returns.
291426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         *
292426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         * @param context The calling activity
293426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         * @param callback The runnable that should execute if a query returns
294426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         *            new values
295426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik         */
296426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik        public void forceDBRequery(Context context, Runnable callback) {
297426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik            synchronized (mTZCallbacks){
298426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                if (mTZQueryInProgress) {
299426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                    mTZCallbacks.add(callback);
300426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                    return;
301426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                }
302426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                mFirstTZRequest = true;
303426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik                getTimeZone(context, callback);
304426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik            }
305426ee7f22eeaa016cdbf0addbb7b2cc6b6cc3487Erik        }
30671ad58c751eb12a500916556c41e704a93895801Erik    }
30771ad58c751eb12a500916556c41e704a93895801Erik
30871ad58c751eb12a500916556c41e704a93895801Erik        /**
30971ad58c751eb12a500916556c41e704a93895801Erik         * A helper method for writing a String value to the preferences
31071ad58c751eb12a500916556c41e704a93895801Erik         * asynchronously.
31171ad58c751eb12a500916556c41e704a93895801Erik         *
31271ad58c751eb12a500916556c41e704a93895801Erik         * @param context A context with access to the correct preferences
31371ad58c751eb12a500916556c41e704a93895801Erik         * @param key The preference to write to
31471ad58c751eb12a500916556c41e704a93895801Erik         * @param value The value to write
31571ad58c751eb12a500916556c41e704a93895801Erik         */
31671ad58c751eb12a500916556c41e704a93895801Erik        public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
31771ad58c751eb12a500916556c41e704a93895801Erik//            SharedPreferences prefs = getSharedPreferences(context);
31871ad58c751eb12a500916556c41e704a93895801Erik            SharedPreferences.Editor editor = prefs.edit();
31971ad58c751eb12a500916556c41e704a93895801Erik            editor.putString(key, value);
32071ad58c751eb12a500916556c41e704a93895801Erik            editor.apply();
32171ad58c751eb12a500916556c41e704a93895801Erik        }
32271ad58c751eb12a500916556c41e704a93895801Erik
32371ad58c751eb12a500916556c41e704a93895801Erik        /**
32471ad58c751eb12a500916556c41e704a93895801Erik         * A helper method for writing a boolean value to the preferences
32571ad58c751eb12a500916556c41e704a93895801Erik         * asynchronously.
32671ad58c751eb12a500916556c41e704a93895801Erik         *
32771ad58c751eb12a500916556c41e704a93895801Erik         * @param context A context with access to the correct preferences
32871ad58c751eb12a500916556c41e704a93895801Erik         * @param key The preference to write to
32971ad58c751eb12a500916556c41e704a93895801Erik         * @param value The value to write
33071ad58c751eb12a500916556c41e704a93895801Erik         */
33171ad58c751eb12a500916556c41e704a93895801Erik        public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
33271ad58c751eb12a500916556c41e704a93895801Erik//            SharedPreferences prefs = getSharedPreferences(context, prefsName);
33371ad58c751eb12a500916556c41e704a93895801Erik            SharedPreferences.Editor editor = prefs.edit();
33471ad58c751eb12a500916556c41e704a93895801Erik            editor.putBoolean(key, value);
33571ad58c751eb12a500916556c41e704a93895801Erik            editor.apply();
33671ad58c751eb12a500916556c41e704a93895801Erik        }
33771ad58c751eb12a500916556c41e704a93895801Erik
33871ad58c751eb12a500916556c41e704a93895801Erik        /** Return a properly configured SharedPreferences instance */
33971ad58c751eb12a500916556c41e704a93895801Erik        public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
34071ad58c751eb12a500916556c41e704a93895801Erik            return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
34171ad58c751eb12a500916556c41e704a93895801Erik        }
34271ad58c751eb12a500916556c41e704a93895801Erik}
343