Loading core/java/android/provider/Calendar.java +74 −0 Original line number Diff line number Diff line Loading @@ -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) Loading core/java/android/util/CalendarUtils.java 0 → 100644 +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); } } Loading
core/java/android/provider/Calendar.java +74 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
core/java/android/util/CalendarUtils.java 0 → 100644 +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); } }