Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b92788aa authored by Erik's avatar Erik Committed by Android (Google) Code Review
Browse files

Merge "Adds time zone functionality into fw as a hidden api" into gingerbread

parents 934516e1 71ad58c7
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -942,6 +942,80 @@ public final class Calendar {
        public static final String END_MINUTE = "endMinute";
    }

    /**
     * CalendarCache stores some settings for calendar including the current
     * time zone for the app. These settings are stored using a key/value
     * scheme.
     */
    public interface CalendarCacheColumns {
        /**
         * The key for the setting. Keys are defined in CalendarChache in the
         * Calendar provider.
         * TODO Add keys to this file
         */
        public static final String KEY = "key";

        /**
         * The value of the given setting.
         */
        public static final String VALUE = "value";
    }

    public static class CalendarCache implements CalendarCacheColumns {
        /**
         * The URI to use for retrieving the properties from the Calendar db.
         */
        public static final Uri URI =
                Uri.parse("content://" + AUTHORITY + "/properties");
        public static final String[] POJECTION = { KEY, VALUE };

        /**
         * If updating a property, this must be provided as the selection. All
         * other selections will fail. For queries this field can be omitted to
         * retrieve all properties or used to query a single property. Valid
         * keys include {@link #TIMEZONE_KEY_TYPE},
         * {@link #TIMEZONE_KEY_INSTANCES}, and
         * {@link #TIMEZONE_KEY_INSTANCES_PREVIOUS}, though the last one can
         * only be read, not written.
         */
        public static final String WHERE = "key=?";

        /**
         * They key for updating the use of auto/home time zones in Calendar.
         * Valid values are {@link #TIMEZONE_TYPE_AUTO} or
         * {@link #TIMEZONE_TYPE_HOME}.
         */
        public static final String TIMEZONE_KEY_TYPE = "timezoneType";

        /**
         * The key for updating the time zone used by the provider when it
         * generates the instances table. This should only be written if the
         * type is set to {@link #TIMEZONE_TYPE_HOME}. A valid time zone id
         * should be written to this field.
         */
        public static final String TIMEZONE_KEY_INSTANCES = "timezoneInstances";

        /**
         * The key for reading the last time zone set by the user. This should
         * only be read by apps and it will be automatically updated whenever
         * {@link #TIMEZONE_KEY_INSTANCES} is updated with
         * {@link #TIMEZONE_TYPE_HOME} set.
         */
        public static final String TIMEZONE_KEY_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";

        /**
         * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
         * should stay in sync with the device's time zone.
         */
        public static final String TIMEZONE_TYPE_AUTO = "auto";

        /**
         * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
         * should use a fixed time zone set by the user.
         */
        public static final String TIMEZONE_TYPE_HOME = "home";
    }

    /**
     * A few Calendar globals are needed in the CalendarProvider for expanding
     * the Instances table and these are all stored in the first (and only)
+309 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.util;

import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.provider.Calendar.CalendarCache;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;

import java.util.Formatter;
import java.util.HashSet;
import java.util.Locale;

/**
 * A class containing utility methods related to Calendar apps.
 *
 * @hide
 */
public class CalendarUtils {
    private static final boolean DEBUG = false;
    private static final String TAG = "CalendarUtils";

    /**
     * This class contains methods specific to reading and writing time zone
     * values.
     */
    public static class TimeZoneUtils {
        private static StringBuilder mSB = new StringBuilder(50);
        private static Formatter mF = new Formatter(mSB, Locale.getDefault());
        private volatile static boolean mFirstTZRequest = true;
        private volatile static boolean mTZQueryInProgress = false;

        private volatile static boolean mUseHomeTZ = false;
        private volatile static String mHomeTZ = Time.getCurrentTimezone();

        private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
        private static int mToken = 1;
        private static AsyncTZHandler mHandler;

        // The name of the shared preferences file. This name must be maintained for historical
        // reasons, as it's what PreferenceManager assigned the first time the file was created.
        private final String mPrefsName;

        /**
         * This is the key used for writing whether or not a home time zone should
         * be used in the Calendar app to the Calendar Preferences.
         */
        public static final String KEY_HOME_TZ_ENABLED = "preferences_home_tz_enabled";
        /**
         * This is the key used for writing the time zone that should be used if
         * home time zones are enabled for the Calendar app.
         */
        public static final String KEY_HOME_TZ = "preferences_home_tz";

        /**
         * This is a helper class for handling the async queries and updates for the
         * time zone settings in Calendar.
         */
        private class AsyncTZHandler extends AsyncQueryHandler {
            public AsyncTZHandler(ContentResolver cr) {
                super(cr);
            }

            @Override
            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
                synchronized (mTZCallbacks) {
                    boolean writePrefs = false;
                    // Check the values in the db
                    int keyColumn = cursor.getColumnIndexOrThrow(CalendarCache.KEY);
                    int valueColumn = cursor.getColumnIndexOrThrow(CalendarCache.VALUE);
                    while(cursor.moveToNext()) {
                        String key = cursor.getString(keyColumn);
                        String value = cursor.getString(valueColumn);
                        if (TextUtils.equals(key, CalendarCache.TIMEZONE_KEY_TYPE)) {
                            boolean useHomeTZ = !TextUtils.equals(
                                    value, CalendarCache.TIMEZONE_TYPE_AUTO);
                            if (useHomeTZ != mUseHomeTZ) {
                                writePrefs = true;
                                mUseHomeTZ = useHomeTZ;
                            }
                        } else if (TextUtils.equals(
                                key, CalendarCache.TIMEZONE_KEY_INSTANCES_PREVIOUS)) {
                            if (!TextUtils.isEmpty(value) && !TextUtils.equals(mHomeTZ, value)) {
                                writePrefs = true;
                                mHomeTZ = value;
                            }
                        }
                    }
                    if (writePrefs) {
                        SharedPreferences prefs = getSharedPreferences((Context)cookie, mPrefsName);
                        // Write the prefs
                        setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
                        setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);
                    }

                    mTZQueryInProgress = false;
                    for (Runnable callback : mTZCallbacks) {
                        if (callback != null) {
                            callback.run();
                        }
                    }
                    mTZCallbacks.clear();
                }
            }
        }

        /**
         * The name of the file where the shared prefs for Calendar are stored
         * must be provided. All activities within an app should provide the
         * same preferences name or behavior may become erratic.
         *
         * @param prefsName
         */
        public TimeZoneUtils(String prefsName) {
            mPrefsName = prefsName;
        }

        /**
         * Formats a date or a time range according to the local conventions.
         *
         * This formats a date/time range using Calendar's time zone and the
         * local conventions for the region of the device.
         *
         * @param context the context is required only if the time is shown
         * @param startMillis the start time in UTC milliseconds
         * @param endMillis the end time in UTC milliseconds
         * @param flags a bit mask of options See
         * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
         * @return a string containing the formatted date/time range.
         */
        public String formatDateRange(Context context, long startMillis,
                long endMillis, int flags) {
            String date;
            synchronized (mSB) {
                mSB.setLength(0);
                date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
                        getTimeZone(context, null)).toString();
            }
            return date;
        }

        /**
         * Writes a new home time zone to the db.
         *
         * Updates the home time zone in the db asynchronously and updates
         * the local cache. Sending a time zone of
         * {@link CalendarCache#TIMEZONE_TYPE_AUTO} will cause it to be set
         * to the device's time zone. null or empty tz will be ignored.
         *
         * @param context The calling activity
         * @param timeZone The time zone to set Calendar to, or
         * {@link CalendarCache#TIMEZONE_TYPE_AUTO}
         */
        public void setTimeZone(Context context, String timeZone) {
            if (TextUtils.isEmpty(timeZone)) {
                if (DEBUG) {
                    Log.d(TAG, "Empty time zone, nothing to be done.");
                }
                return;
            }
            boolean updatePrefs = false;
            synchronized (mTZCallbacks) {
                if (CalendarCache.TIMEZONE_TYPE_AUTO.equals(timeZone)) {
                    if (mUseHomeTZ) {
                        updatePrefs = true;
                    }
                    mUseHomeTZ = false;
                } else {
                    if (!mUseHomeTZ || !TextUtils.equals(mHomeTZ, timeZone)) {
                        updatePrefs = true;
                    }
                    mUseHomeTZ = true;
                    mHomeTZ = timeZone;
                }
            }
            if (updatePrefs) {
                // Write the prefs
                SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
                setSharedPreference(prefs, KEY_HOME_TZ_ENABLED, mUseHomeTZ);
                setSharedPreference(prefs, KEY_HOME_TZ, mHomeTZ);

                // Update the db
                ContentValues values = new ContentValues();
                if (mHandler == null) {
                    mHandler = new AsyncTZHandler(context.getContentResolver());
                }

                mHandler.cancelOperation(mToken);

                // skip 0 so query can use it
                if (++mToken == 0) {
                    mToken = 1;
                }

                // Write the use home tz setting
                String[] selArgs = new String[] { CalendarCache.TIMEZONE_KEY_TYPE };
                values.put(CalendarCache.VALUE, mUseHomeTZ ? CalendarCache.TIMEZONE_TYPE_HOME
                        : CalendarCache.TIMEZONE_TYPE_AUTO);
                mHandler.startUpdate(mToken, null, CalendarCache.URI, values, CalendarCache.WHERE,
                        selArgs);

                // If using a home tz write it to the db
                if (mUseHomeTZ) {
                    selArgs[0] = CalendarCache.TIMEZONE_KEY_INSTANCES;
                    values.clear();
                    values.put(CalendarCache.VALUE, mHomeTZ);
                    mHandler.startUpdate(
                            mToken, null, CalendarCache.URI, values, CalendarCache.WHERE, selArgs);
                }
            }
        }

        /**
         * Gets the time zone that Calendar should be displayed in
         *
         * This is a helper method to get the appropriate time zone for Calendar. If this
         * is the first time this method has been called it will initiate an asynchronous
         * query to verify that the data in preferences is correct. The callback supplied
         * will only be called if this query returns a value other than what is stored in
         * preferences and should cause the calling activity to refresh anything that
         * depends on calling this method.
         *
         * @param context The calling activity
         * @param callback The runnable that should execute if a query returns new values
         * @return The string value representing the time zone Calendar should display
         */
        public String getTimeZone(Context context, Runnable callback) {
            synchronized (mTZCallbacks){
                if (mFirstTZRequest) {
                    mTZQueryInProgress = true;
                    mFirstTZRequest = false;

                    SharedPreferences prefs = getSharedPreferences(context, mPrefsName);
                    mUseHomeTZ = prefs.getBoolean(KEY_HOME_TZ_ENABLED, false);
                    mHomeTZ = prefs.getString(KEY_HOME_TZ, Time.getCurrentTimezone());

                    // When the async query returns it should synchronize on
                    // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the
                    // preferences, set mTZQueryInProgress to false, and call all
                    // the runnables in mTZCallbacks.
                    if (mHandler == null) {
                        mHandler = new AsyncTZHandler(context.getContentResolver());
                    }
                    mHandler.startQuery(0, context, CalendarCache.URI, CalendarCache.POJECTION,
                            null, null, null);
                }
                if (mTZQueryInProgress) {
                    mTZCallbacks.add(callback);
                }
            }
            return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone();
        }
    }

        /**
         * A helper method for writing a String value to the preferences
         * asynchronously.
         *
         * @param context A context with access to the correct preferences
         * @param key The preference to write to
         * @param value The value to write
         */
        public static void setSharedPreference(SharedPreferences prefs, String key, String value) {
//            SharedPreferences prefs = getSharedPreferences(context);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString(key, value);
            editor.apply();
        }

        /**
         * A helper method for writing a boolean value to the preferences
         * asynchronously.
         *
         * @param context A context with access to the correct preferences
         * @param key The preference to write to
         * @param value The value to write
         */
        public static void setSharedPreference(SharedPreferences prefs, String key, boolean value) {
//            SharedPreferences prefs = getSharedPreferences(context, prefsName);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putBoolean(key, value);
            editor.apply();
        }

        /** Return a properly configured SharedPreferences instance */
        public static SharedPreferences getSharedPreferences(Context context, String prefsName) {
            return context.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
        }
}