Utils.java revision 7b92da258a480284dcc15a518ea570072329a31d
1146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/*
2146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
3146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *
4146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * you may not use this file except in compliance with the License.
6146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * You may obtain a copy of the License at
7146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *
8146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *
10146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * See the License for the specific language governing permissions and
14146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * limitations under the License.
15146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */
16146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
17146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpackage com.android.calendar;
18146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
19146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport static android.provider.Calendar.EVENT_BEGIN_TIME;
20e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
21d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport com.android.calendar.CalendarController.ViewType;
22d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
23d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport android.app.Activity;
24146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context;
25146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Intent;
26e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chanimport android.content.SharedPreferences;
27ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.database.Cursor;
28a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErikimport android.database.MatrixCursor;
29ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.graphics.drawable.Drawable;
30ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.graphics.drawable.GradientDrawable;
311ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.net.Uri;
32d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport android.os.Bundle;
33eb10fa8bee049e0052b5cb53dcfbdaccef9f2740Erikimport android.text.TextUtils;
34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time;
35a48b9d426236d8d26bd99602bf0a84315b3f1b09Erikimport android.util.CalendarUtils.TimeZoneUtils;
361ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.util.Log;
37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashiimport java.util.Calendar;
391427657d0bf7e69b831aa495828f67b45b69fd99Erikimport java.util.Formatter;
401ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport java.util.List;
41ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport java.util.Map;
423ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tangimport java.util.TimeZone;
4356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
44146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpublic class Utils {
453dc5e908a825b879978ba523d9099dc2255da9a5Erik    private static final boolean DEBUG = true;
463dc5e908a825b879978ba523d9099dc2255da9a5Erik    private static final String TAG = "CalUtils";
47bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan    // Set to 0 until we have UI to perform undo
48bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan    public static final long UNDO_DELAY = 0;
49bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan
5079f228124de7d98146ca526d743436f6419e2365Erik    // For recurring events which instances of the series are being modified
5179f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_UNINITIALIZED = 0;
5279f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_SELECTED = 1;
5379f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_ALL_FOLLOWING = 2;
5479f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_ALL = 3;
5579f228124de7d98146ca526d743436f6419e2365Erik
567b92da258a480284dcc15a518ea570072329a31dErik    // When the edit event view finishes it passes back the appropriate exit
577b92da258a480284dcc15a518ea570072329a31dErik    // code.
587b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_REVERT = 1 << 0;
597b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_SAVE = 1 << 1;
607b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_DELETE = 1 << 2;
617b92da258a480284dcc15a518ea570072329a31dErik    // And should re run with DONE_EXIT if it should also leave the view, just
627b92da258a480284dcc15a518ea570072329a31dErik    // exiting is identical to reverting
637b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_EXIT = 1 << 0;
6479f228124de7d98146ca526d743436f6419e2365Erik
65ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int CLEAR_ALPHA_MASK = 0x00FFFFFF;
66ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int HIGH_ALPHA = 255 << 24;
67ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int MED_ALPHA = 180 << 24;
68ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int LOW_ALPHA = 150 << 24;
69ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
70ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    protected static final String OPEN_EMAIL_MARKER = " <";
71ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    protected static final String CLOSE_EMAIL_MARKER = ">";
72ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    /* The corner should be rounded on the top right and bottom right */
737b92da258a480284dcc15a518ea570072329a31dErik    private static final float[] CORNERS = new float[] { 0, 0, 5, 5, 5, 5, 0, 0 };
74ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
75d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static final String INTENT_KEY_DETAIL_VIEW = "DETAIL_VIEW";
76d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static final String INTENT_KEY_VIEW_TYPE = "VIEW";
77d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static final String INTENT_VALUE_VIEW_TYPE_DAY = "DAY";
78275232dae58bb24e3360a779ada9d24601a99bcfErik
79a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // The name of the shared preferences file. This name must be maintained for
80a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // historical
81a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // reasons, as it's what PreferenceManager assigned the first time the file
82a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // was created.
83a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
8435d1362a75eac7cebbe9de23d08fea08c4aac817Erik
85a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    private static final TimeZoneUtils mTZUtils = new TimeZoneUtils(SHARED_PREFS_NAME);
86d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
87d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static int getViewTypeFromIntentAndSharedPref(Activity activity) {
88dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        Intent intent = activity.getIntent();
89dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        Bundle extras = intent.getExtras();
904b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(activity);
91d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
927b92da258a480284dcc15a518ea570072329a31dErik        if (TextUtils.equals(intent.getAction(), Intent.ACTION_EDIT)) {
93dd95df57c8c5a58a85c4c0effad5652dec14f621Erik            return ViewType.EDIT;
94dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        }
95d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        if (extras != null) {
96d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan            if (extras.getBoolean(INTENT_KEY_DETAIL_VIEW, false)) {
97d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                // This is the "detail" view which is either agenda or day view
984b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                return prefs.getInt(GeneralPreferences.KEY_DETAILED_VIEW,
994b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                        GeneralPreferences.DEFAULT_DETAILED_VIEW);
100d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan            } else if (INTENT_VALUE_VIEW_TYPE_DAY.equals(extras.getString(INTENT_KEY_VIEW_TYPE))) {
101d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                // Not sure who uses this. This logic came from LaunchActivity
102d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                return ViewType.DAY;
103d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan            }
104d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        }
105d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
106d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        // Default to the last view
1077b92da258a480284dcc15a518ea570072329a31dErik        return prefs.getInt(
1087b92da258a480284dcc15a518ea570072329a31dErik                GeneralPreferences.KEY_START_VIEW, GeneralPreferences.DEFAULT_START_VIEW);
109d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    }
110ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
111235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    /**
1127b92da258a480284dcc15a518ea570072329a31dErik     * Writes a new home time zone to the db. Updates the home time zone in the
1137b92da258a480284dcc15a518ea570072329a31dErik     * db asynchronously and updates the local cache. Sending a time zone of
1147b92da258a480284dcc15a518ea570072329a31dErik     * **tbd** will cause it to be set to the device's time zone. null or empty
1157b92da258a480284dcc15a518ea570072329a31dErik     * tz will be ignored.
1163dc5e908a825b879978ba523d9099dc2255da9a5Erik     *
1173dc5e908a825b879978ba523d9099dc2255da9a5Erik     * @param context The calling activity
1183dc5e908a825b879978ba523d9099dc2255da9a5Erik     * @param timeZone The time zone to set Calendar to, or **tbd**
1193dc5e908a825b879978ba523d9099dc2255da9a5Erik     */
1203dc5e908a825b879978ba523d9099dc2255da9a5Erik    public static void setTimeZone(Context context, String timeZone) {
121a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        mTZUtils.setTimeZone(context, timeZone);
1223dc5e908a825b879978ba523d9099dc2255da9a5Erik    }
1233dc5e908a825b879978ba523d9099dc2255da9a5Erik
1243dc5e908a825b879978ba523d9099dc2255da9a5Erik    /**
1257b92da258a480284dcc15a518ea570072329a31dErik     * Gets the time zone that Calendar should be displayed in This is a helper
1267b92da258a480284dcc15a518ea570072329a31dErik     * method to get the appropriate time zone for Calendar. If this is the
1277b92da258a480284dcc15a518ea570072329a31dErik     * first time this method has been called it will initiate an asynchronous
1287b92da258a480284dcc15a518ea570072329a31dErik     * query to verify that the data in preferences is correct. The callback
1297b92da258a480284dcc15a518ea570072329a31dErik     * supplied will only be called if this query returns a value other than
1307b92da258a480284dcc15a518ea570072329a31dErik     * what is stored in preferences and should cause the calling activity to
1317b92da258a480284dcc15a518ea570072329a31dErik     * refresh anything that depends on calling this method.
132235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     *
133235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * @param context The calling activity
1347b92da258a480284dcc15a518ea570072329a31dErik     * @param callback The runnable that should execute if a query returns new
1357b92da258a480284dcc15a518ea570072329a31dErik     *            values
1367b92da258a480284dcc15a518ea570072329a31dErik     * @return The string value representing the time zone Calendar should
1377b92da258a480284dcc15a518ea570072329a31dErik     *         display
138235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     */
139235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    public static String getTimeZone(Context context, Runnable callback) {
140a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        return mTZUtils.getTimeZone(context, callback);
14145efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    }
14245efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan
1431427657d0bf7e69b831aa495828f67b45b69fd99Erik    /**
1441427657d0bf7e69b831aa495828f67b45b69fd99Erik     * Formats a date or a time range according to the local conventions.
1451427657d0bf7e69b831aa495828f67b45b69fd99Erik     *
1461427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @param context the context is required only if the time is shown
1471427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @param startMillis the start time in UTC milliseconds
1481427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @param endMillis the end time in UTC milliseconds
1497b92da258a480284dcc15a518ea570072329a31dErik     * @param flags a bit mask of options See {@link #formatDateRange(Context,
1507b92da258a480284dcc15a518ea570072329a31dErik     *            Formatter, long, long, int, String) formatDateRange}
1511427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @return a string containing the formatted date/time range.
1521427657d0bf7e69b831aa495828f67b45b69fd99Erik     */
1537b92da258a480284dcc15a518ea570072329a31dErik    public static String formatDateRange(
1547b92da258a480284dcc15a518ea570072329a31dErik            Context context, long startMillis, long endMillis, int flags) {
155a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        return mTZUtils.formatDateRange(context, startMillis, endMillis, flags);
156a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    }
157a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik
158a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    public static String getSharedPreference(Context context, String key, String defaultValue) {
159a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
160a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        return prefs.getString(key, defaultValue);
1611427657d0bf7e69b831aa495828f67b45b69fd99Erik    }
1621427657d0bf7e69b831aa495828f67b45b69fd99Erik
163d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static int getSharedPreference(Context context, String key, int defaultValue) {
1644b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
165d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        return prefs.getInt(key, defaultValue);
166d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    }
167d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
168f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang    /**
169f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * Asynchronously sets the preference with the given key to the given value
170f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     *
171f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * @param context the context to use to get preferences from
172f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * @param key the key of the preference to set
173f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * @param value the value to set
174f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     */
175fbce65e53c7a111955f638db5bf8bee35381e5b7Erik    public static void setSharedPreference(Context context, String key, String value) {
1764b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
17724fac46d6b87ce21d5e6a4b1c0fdcaa83d408997Brad Fitzpatrick        prefs.edit().putString(key, value).apply();
17845efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    }
17945efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan
1803dc5e908a825b879978ba523d9099dc2255da9a5Erik    static void setSharedPreference(Context context, String key, boolean value) {
1814b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
1823dc5e908a825b879978ba523d9099dc2255da9a5Erik        SharedPreferences.Editor editor = prefs.edit();
1833dc5e908a825b879978ba523d9099dc2255da9a5Erik        editor.putBoolean(key, value);
184275232dae58bb24e3360a779ada9d24601a99bcfErik        editor.apply();
1853dc5e908a825b879978ba523d9099dc2255da9a5Erik    }
1863dc5e908a825b879978ba523d9099dc2255da9a5Erik
187d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    /**
188d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * Save default agenda/day/week/month view for next time
189d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     *
190d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * @param context
191d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * @param viewId {@link CalendarController.ViewType}
192d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     */
193e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan    static void setDefaultView(Context context, int viewId) {
1944b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
195e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        SharedPreferences.Editor editor = prefs.edit();
196f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang
197d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        if (viewId == CalendarController.ViewType.AGENDA
198d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                || viewId == CalendarController.ViewType.DAY) {
199e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan            // Record the (new) detail start view only for Agenda and Day
2004b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa            editor.putInt(GeneralPreferences.KEY_DETAILED_VIEW, viewId);
201e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        }
202e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
203e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        // Record the (new) start view
2044b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        editor.putInt(GeneralPreferences.KEY_START_VIEW, viewId);
20524fac46d6b87ce21d5e6a4b1c0fdcaa83d408997Brad Fitzpatrick        editor.apply();
206e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan    }
207e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
208a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    public static MatrixCursor matrixCursorFromCursor(Cursor cursor) {
209a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames());
210a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        int numColumns = cursor.getColumnCount();
211a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        String data[] = new String[numColumns];
212a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        cursor.moveToPosition(-1);
213a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        while (cursor.moveToNext()) {
214a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            for (int i = 0; i < numColumns; i++) {
215a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                data[i] = cursor.getString(i);
216a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            }
217a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            newCursor.addRow(data);
218a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
219a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        return newCursor;
220a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    }
221a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
222a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    /**
223a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     * Compares two cursors to see if they contain the same data.
224a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     *
2257b92da258a480284dcc15a518ea570072329a31dErik     * @return Returns true of the cursors contain the same data and are not
2267b92da258a480284dcc15a518ea570072329a31dErik     *         null, false otherwise
227a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     */
228a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    public static boolean compareCursors(Cursor c1, Cursor c2) {
2297b92da258a480284dcc15a518ea570072329a31dErik        if (c1 == null || c2 == null) {
230a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
231a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
232a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
233a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        int numColumns = c1.getColumnCount();
234a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if (numColumns != c2.getColumnCount()) {
235a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
236a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
237a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
238a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if (c1.getCount() != c2.getCount()) {
239a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
240a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
241a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
242a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        c1.moveToPosition(-1);
243a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        c2.moveToPosition(-1);
2447b92da258a480284dcc15a518ea570072329a31dErik        while (c1.moveToNext() && c2.moveToNext()) {
2457b92da258a480284dcc15a518ea570072329a31dErik            for (int i = 0; i < numColumns; i++) {
2467b92da258a480284dcc15a518ea570072329a31dErik                if (!TextUtils.equals(c1.getString(i), c2.getString(i))) {
247a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                    return false;
248a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                }
249a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            }
250a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
251a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
252a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        return true;
253a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    }
254a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * If the given intent specifies a time (in milliseconds since the epoch),
257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * then that time is returned. Otherwise, the current time is returned.
258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
259146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static final long timeFromIntentInMillis(Intent intent) {
2607b92da258a480284dcc15a518ea570072329a31dErik        // If the time was specified, then use that. Otherwise, use the current
2617b92da258a480284dcc15a518ea570072329a31dErik        // time.
2621ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        Uri data = intent.getData();
263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
2641ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        if (millis == -1 && data != null && data.isHierarchical()) {
2651ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik            List<String> path = data.getPathSegments();
2667b92da258a480284dcc15a518ea570072329a31dErik            if (path.size() == 2 && path.get(0).equals("time")) {
2671ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                try {
2681ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                    millis = Long.valueOf(data.getLastPathSegment());
2691ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                } catch (NumberFormatException e) {
2707b92da258a480284dcc15a518ea570072329a31dErik                    Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time "
2717b92da258a480284dcc15a518ea570072329a31dErik                            + "found. Using current time.");
2721ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                }
2731ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik            }
2741ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        }
27576727b7a9cf780f200414548b9d454bf9a701e3eErik        if (millis <= 0) {
276146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            millis = System.currentTimeMillis();
277146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
278146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return millis;
279146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
281ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    public static Drawable getColorChip(int color) {
282ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        /*
2837b92da258a480284dcc15a518ea570072329a31dErik         * We want the color chip to have a nice gradient using the color of the
2847b92da258a480284dcc15a518ea570072329a31dErik         * calendar. To do this we use a GradientDrawable. The color supplied
2857b92da258a480284dcc15a518ea570072329a31dErik         * has an alpha of FF so we first do: color & 0x00FFFFFF to clear the
2867b92da258a480284dcc15a518ea570072329a31dErik         * alpha. Then we add our alpha to it. We use 3 colors to get a step
2877b92da258a480284dcc15a518ea570072329a31dErik         * effect where it starts off very light and quickly becomes dark and
2887b92da258a480284dcc15a518ea570072329a31dErik         * then a slow transition to be even darker.
289ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         */
290ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        color &= CLEAR_ALPHA_MASK;
291ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int startColor = color | HIGH_ALPHA;
292ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int middleColor = color | MED_ALPHA;
293ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int endColor = color | LOW_ALPHA;
2947b92da258a480284dcc15a518ea570072329a31dErik        int[] colors = new int[] { startColor, middleColor, endColor };
295ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        GradientDrawable d = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
296ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        d.setCornerRadii(CORNERS);
297ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        return d;
298ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    }
299ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3017b92da258a480284dcc15a518ea570072329a31dErik     * Formats the given Time object so that it gives the month and year (for
3027b92da258a480284dcc15a518ea570072329a31dErik     * example, "September 2007").
303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param time the time to format
305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return the string containing the weekday and the date
306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
307ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan    public static String formatMonthYear(Context context, Time time) {
308ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan        return time.format(context.getResources().getString(R.string.month_year));
309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3124c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * Returns a list joined together by the provided delimiter, for example,
3134c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * ["a", "b", "c"] could be joined into "a,b,c"
3144c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     *
3154c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * @param things the things to join together
3164c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * @param delim the delimiter to use
3174c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * @return a string contained the things joined together
3184c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     */
3194c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang    public static String join(List<?> things, String delim) {
3204c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        StringBuilder builder = new StringBuilder();
3214c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        boolean first = true;
3224c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        for (Object thing : things) {
3234c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            if (first) {
3244c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang                first = false;
3254c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            } else {
3264c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang                builder.append(delim);
3274c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            }
3284c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            builder.append(thing.toString());
3294c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        }
3304c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        return builder.toString();
3314c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang    }
3324c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang
3334c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang    /**
33456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Get first day of week as android.text.format.Time constant.
3357b92da258a480284dcc15a518ea570072329a31dErik     *
33656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return the first day of week in android.text.format.Time
33756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
3388e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang    public static int getFirstDayOfWeek(Context context) {
3394b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
3407b92da258a480284dcc15a518ea570072329a31dErik        String pref = prefs.getString(
3417b92da258a480284dcc15a518ea570072329a31dErik                GeneralPreferences.KEY_WEEK_START_DAY, GeneralPreferences.WEEK_START_DEFAULT);
3428e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang
3438e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        int startDay;
3444b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        if (GeneralPreferences.WEEK_START_DEFAULT.equals(pref)) {
3458e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang            startDay = Calendar.getInstance().getFirstDayOfWeek();
3468e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        } else {
3478e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang            startDay = Integer.parseInt(pref);
3488e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        }
3498e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang
35056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        if (startDay == Calendar.SATURDAY) {
35156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.SATURDAY;
35256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        } else if (startDay == Calendar.MONDAY) {
35356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.MONDAY;
35456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        } else {
35556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.SUNDAY;
35656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        }
35756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
35856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
35956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
36056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Determine whether the column position is Saturday or not.
3617b92da258a480284dcc15a518ea570072329a31dErik     *
36256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param column the column position
36356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param firstDayOfWeek the first day of week in android.text.format.Time
36456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return true if the column is Saturday position
36556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
36656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static boolean isSaturday(int column, int firstDayOfWeek) {
36756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        return (firstDayOfWeek == Time.SUNDAY && column == 6)
3687b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.MONDAY && column == 5)
3697b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.SATURDAY && column == 0);
37056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
37156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
37256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
37356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Determine whether the column position is Sunday or not.
3747b92da258a480284dcc15a518ea570072329a31dErik     *
37556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param column the column position
37656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param firstDayOfWeek the first day of week in android.text.format.Time
37756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return true if the column is Sunday position
37856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
37956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static boolean isSunday(int column, int firstDayOfWeek) {
38056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        return (firstDayOfWeek == Time.SUNDAY && column == 0)
3817b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.MONDAY && column == 6)
3827b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.SATURDAY && column == 1);
38356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
384ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
385ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    /**
3863ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     * Convert given UTC time into current local time.
3873ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     *
3883ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     * @param recycle Time object to recycle, otherwise null.
3893ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     * @param utcTime Time to convert, in UTC.
3903ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     */
3913ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang    public static long convertUtcToLocal(Time recycle, long utcTime) {
3923ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        if (recycle == null) {
3933ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang            recycle = new Time();
3943ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        }
3953ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        recycle.timezone = Time.TIMEZONE_UTC;
3963ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        recycle.set(utcTime);
3973ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        recycle.timezone = TimeZone.getDefault().getID();
3983ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        return recycle.normalize(true);
3993ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang    }
4003ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang
4013ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang    /**
402ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * Scan through a cursor of calendars and check if names are duplicated.
4037b92da258a480284dcc15a518ea570072329a31dErik     * This travels a cursor containing calendar display names and fills in the
4047b92da258a480284dcc15a518ea570072329a31dErik     * provided map with whether or not each name is repeated.
405ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     *
406ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param isDuplicateName The map to put the duplicate check results in.
407ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param cursor The query of calendars to check
408ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param nameIndex The column of the query that contains the display name
409ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     */
4107b92da258a480284dcc15a518ea570072329a31dErik    public static void checkForDuplicateNames(
4117b92da258a480284dcc15a518ea570072329a31dErik            Map<String, Boolean> isDuplicateName, Cursor cursor, int nameIndex) {
412ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        isDuplicateName.clear();
413ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        cursor.moveToPosition(-1);
414ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        while (cursor.moveToNext()) {
415ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            String displayName = cursor.getString(nameIndex);
416ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            // Set it to true if we've seen this name before, false otherwise
417ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            if (displayName != null) {
418ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan                isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
419ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            }
420ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        }
421ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    }
4229138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
4239138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
4249138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * Null-safe object comparison
4257b92da258a480284dcc15a518ea570072329a31dErik     *
4269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * @param s1
4279138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * @param s2
4289138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * @return
4299138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     */
4309138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public static boolean equals(Object o1, Object o2) {
4319138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return o1 == null ? o2 == null : o1.equals(o2);
4329138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    }
433146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
434