Utils.java revision 82400dd70331df7885dd59b809c4bc0667046320
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;
275b2a907fa3a983f74bb48da86846e351c2a464d0Isaac Katzenelsonimport android.content.res.Configuration;
28ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.database.Cursor;
29a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErikimport android.database.MatrixCursor;
301ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.net.Uri;
31d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chanimport android.os.Bundle;
32eb10fa8bee049e0052b5cb53dcfbdaccef9f2740Erikimport android.text.TextUtils;
3329190975b9238dd6841f822f82f2fb83b0557f36Daisuke Miyakawaimport android.text.format.DateUtils;
34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time;
35a48b9d426236d8d26bd99602bf0a84315b3f1b09Erikimport android.util.CalendarUtils.TimeZoneUtils;
361ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.util.Log;
37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelsonimport java.util.ArrayList;
3956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashiimport java.util.Calendar;
401427657d0bf7e69b831aa495828f67b45b69fd99Erikimport java.util.Formatter;
4182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelsonimport java.util.Iterator;
421ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport java.util.List;
43ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport java.util.Map;
4456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
45146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpublic class Utils {
463dc5e908a825b879978ba523d9099dc2255da9a5Erik    private static final boolean DEBUG = true;
473dc5e908a825b879978ba523d9099dc2255da9a5Erik    private static final String TAG = "CalUtils";
48bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan    // Set to 0 until we have UI to perform undo
49bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan    public static final long UNDO_DELAY = 0;
50bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan
5179f228124de7d98146ca526d743436f6419e2365Erik    // For recurring events which instances of the series are being modified
5279f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_UNINITIALIZED = 0;
5379f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_SELECTED = 1;
5479f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_ALL_FOLLOWING = 2;
5579f228124de7d98146ca526d743436f6419e2365Erik    public static final int MODIFY_ALL = 3;
5679f228124de7d98146ca526d743436f6419e2365Erik
577b92da258a480284dcc15a518ea570072329a31dErik    // When the edit event view finishes it passes back the appropriate exit
587b92da258a480284dcc15a518ea570072329a31dErik    // code.
597b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_REVERT = 1 << 0;
607b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_SAVE = 1 << 1;
617b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_DELETE = 1 << 2;
627b92da258a480284dcc15a518ea570072329a31dErik    // And should re run with DONE_EXIT if it should also leave the view, just
637b92da258a480284dcc15a518ea570072329a31dErik    // exiting is identical to reverting
647b92da258a480284dcc15a518ea570072329a31dErik    public static final int DONE_EXIT = 1 << 0;
6579f228124de7d98146ca526d743436f6419e2365Erik
66ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    protected static final String OPEN_EMAIL_MARKER = " <";
67ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    protected static final String CLOSE_EMAIL_MARKER = ">";
68ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
69d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static final String INTENT_KEY_DETAIL_VIEW = "DETAIL_VIEW";
70d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static final String INTENT_KEY_VIEW_TYPE = "VIEW";
71d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static final String INTENT_VALUE_VIEW_TYPE_DAY = "DAY";
72275232dae58bb24e3360a779ada9d24601a99bcfErik
73981874e61ecf29a96a77601a3172b2503b6537eeErik    public static final int MONDAY_BEFORE_JULIAN_EPOCH = Time.EPOCH_JULIAN_DAY - 3;
74981874e61ecf29a96a77601a3172b2503b6537eeErik
75a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // The name of the shared preferences file. This name must be maintained for
76a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // historical
77a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // reasons, as it's what PreferenceManager assigned the first time the file
78a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    // was created.
79a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
8035d1362a75eac7cebbe9de23d08fea08c4aac817Erik
81a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    private static final TimeZoneUtils mTZUtils = new TimeZoneUtils(SHARED_PREFS_NAME);
82b60218a31d948ea0a549daf6464063d20b48421fMichael Chan    private static boolean mAllowWeekForDetailView = false;
83ca4786769151f97069980443ce43d9c4f867ac5bErik    private static long mTardis = 0;
84d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
85d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static int getViewTypeFromIntentAndSharedPref(Activity activity) {
86dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        Intent intent = activity.getIntent();
87dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        Bundle extras = intent.getExtras();
884b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(activity);
89d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
907b92da258a480284dcc15a518ea570072329a31dErik        if (TextUtils.equals(intent.getAction(), Intent.ACTION_EDIT)) {
91dd95df57c8c5a58a85c4c0effad5652dec14f621Erik            return ViewType.EDIT;
92dd95df57c8c5a58a85c4c0effad5652dec14f621Erik        }
93d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        if (extras != null) {
94d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan            if (extras.getBoolean(INTENT_KEY_DETAIL_VIEW, false)) {
95d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                // This is the "detail" view which is either agenda or day view
964b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                return prefs.getInt(GeneralPreferences.KEY_DETAILED_VIEW,
974b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                        GeneralPreferences.DEFAULT_DETAILED_VIEW);
98d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan            } else if (INTENT_VALUE_VIEW_TYPE_DAY.equals(extras.getString(INTENT_KEY_VIEW_TYPE))) {
99d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                // Not sure who uses this. This logic came from LaunchActivity
100d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan                return ViewType.DAY;
101d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan            }
102d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        }
103d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
104d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        // Default to the last view
1057b92da258a480284dcc15a518ea570072329a31dErik        return prefs.getInt(
1067b92da258a480284dcc15a518ea570072329a31dErik                GeneralPreferences.KEY_START_VIEW, GeneralPreferences.DEFAULT_START_VIEW);
107d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    }
108ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
109235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    /**
1107b92da258a480284dcc15a518ea570072329a31dErik     * Writes a new home time zone to the db. Updates the home time zone in the
1117b92da258a480284dcc15a518ea570072329a31dErik     * db asynchronously and updates the local cache. Sending a time zone of
1127b92da258a480284dcc15a518ea570072329a31dErik     * **tbd** will cause it to be set to the device's time zone. null or empty
1137b92da258a480284dcc15a518ea570072329a31dErik     * tz will be ignored.
1143dc5e908a825b879978ba523d9099dc2255da9a5Erik     *
1153dc5e908a825b879978ba523d9099dc2255da9a5Erik     * @param context The calling activity
1163dc5e908a825b879978ba523d9099dc2255da9a5Erik     * @param timeZone The time zone to set Calendar to, or **tbd**
1173dc5e908a825b879978ba523d9099dc2255da9a5Erik     */
1183dc5e908a825b879978ba523d9099dc2255da9a5Erik    public static void setTimeZone(Context context, String timeZone) {
119a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        mTZUtils.setTimeZone(context, timeZone);
1203dc5e908a825b879978ba523d9099dc2255da9a5Erik    }
1213dc5e908a825b879978ba523d9099dc2255da9a5Erik
1223dc5e908a825b879978ba523d9099dc2255da9a5Erik    /**
1237b92da258a480284dcc15a518ea570072329a31dErik     * Gets the time zone that Calendar should be displayed in This is a helper
1247b92da258a480284dcc15a518ea570072329a31dErik     * method to get the appropriate time zone for Calendar. If this is the
1257b92da258a480284dcc15a518ea570072329a31dErik     * first time this method has been called it will initiate an asynchronous
1267b92da258a480284dcc15a518ea570072329a31dErik     * query to verify that the data in preferences is correct. The callback
1277b92da258a480284dcc15a518ea570072329a31dErik     * supplied will only be called if this query returns a value other than
1287b92da258a480284dcc15a518ea570072329a31dErik     * what is stored in preferences and should cause the calling activity to
1297b92da258a480284dcc15a518ea570072329a31dErik     * refresh anything that depends on calling this method.
130235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     *
131235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * @param context The calling activity
1327b92da258a480284dcc15a518ea570072329a31dErik     * @param callback The runnable that should execute if a query returns new
1337b92da258a480284dcc15a518ea570072329a31dErik     *            values
1347b92da258a480284dcc15a518ea570072329a31dErik     * @return The string value representing the time zone Calendar should
1357b92da258a480284dcc15a518ea570072329a31dErik     *         display
136235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     */
137235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    public static String getTimeZone(Context context, Runnable callback) {
138a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        return mTZUtils.getTimeZone(context, callback);
13945efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    }
14045efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan
1411427657d0bf7e69b831aa495828f67b45b69fd99Erik    /**
1421427657d0bf7e69b831aa495828f67b45b69fd99Erik     * Formats a date or a time range according to the local conventions.
1431427657d0bf7e69b831aa495828f67b45b69fd99Erik     *
1441427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @param context the context is required only if the time is shown
1451427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @param startMillis the start time in UTC milliseconds
1461427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @param endMillis the end time in UTC milliseconds
14729190975b9238dd6841f822f82f2fb83b0557f36Daisuke Miyakawa     * @param flags a bit mask of options See {@link DateUtils#formatDateRange(Context, Formatter,
14829190975b9238dd6841f822f82f2fb83b0557f36Daisuke Miyakawa     * long, long, int, String) formatDateRange}
1491427657d0bf7e69b831aa495828f67b45b69fd99Erik     * @return a string containing the formatted date/time range.
1501427657d0bf7e69b831aa495828f67b45b69fd99Erik     */
1517b92da258a480284dcc15a518ea570072329a31dErik    public static String formatDateRange(
1527b92da258a480284dcc15a518ea570072329a31dErik            Context context, long startMillis, long endMillis, int flags) {
153a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        return mTZUtils.formatDateRange(context, startMillis, endMillis, flags);
154a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    }
155a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik
156a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik    public static String getSharedPreference(Context context, String key, String defaultValue) {
157a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
158a48b9d426236d8d26bd99602bf0a84315b3f1b09Erik        return prefs.getString(key, defaultValue);
1591427657d0bf7e69b831aa495828f67b45b69fd99Erik    }
1601427657d0bf7e69b831aa495828f67b45b69fd99Erik
161d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    public static int getSharedPreference(Context context, String key, int defaultValue) {
1624b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
163d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan        return prefs.getInt(key, defaultValue);
164d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    }
165d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan
166ca4786769151f97069980443ce43d9c4f867ac5bErik    public static boolean getSharedPreference(Context context, String key, boolean defaultValue) {
167ca4786769151f97069980443ce43d9c4f867ac5bErik        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
168ca4786769151f97069980443ce43d9c4f867ac5bErik        return prefs.getBoolean(key, defaultValue);
169ca4786769151f97069980443ce43d9c4f867ac5bErik    }
170ca4786769151f97069980443ce43d9c4f867ac5bErik
171f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang    /**
172f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * Asynchronously sets the preference with the given key to the given value
173f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     *
174f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * @param context the context to use to get preferences from
175f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * @param key the key of the preference to set
176f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     * @param value the value to set
177f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang     */
178fbce65e53c7a111955f638db5bf8bee35381e5b7Erik    public static void setSharedPreference(Context context, String key, String value) {
1794b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
18024fac46d6b87ce21d5e6a4b1c0fdcaa83d408997Brad Fitzpatrick        prefs.edit().putString(key, value).apply();
18145efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    }
18245efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan
183ca4786769151f97069980443ce43d9c4f867ac5bErik    protected static void tardis() {
184ca4786769151f97069980443ce43d9c4f867ac5bErik        mTardis = System.currentTimeMillis();
185ca4786769151f97069980443ce43d9c4f867ac5bErik    }
186ca4786769151f97069980443ce43d9c4f867ac5bErik
187ca4786769151f97069980443ce43d9c4f867ac5bErik    protected static long getTardis() {
188ca4786769151f97069980443ce43d9c4f867ac5bErik        return mTardis;
189ca4786769151f97069980443ce43d9c4f867ac5bErik    }
190ca4786769151f97069980443ce43d9c4f867ac5bErik
1913dc5e908a825b879978ba523d9099dc2255da9a5Erik    static void setSharedPreference(Context context, String key, boolean value) {
1924b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
1933dc5e908a825b879978ba523d9099dc2255da9a5Erik        SharedPreferences.Editor editor = prefs.edit();
1943dc5e908a825b879978ba523d9099dc2255da9a5Erik        editor.putBoolean(key, value);
195275232dae58bb24e3360a779ada9d24601a99bcfErik        editor.apply();
1963dc5e908a825b879978ba523d9099dc2255da9a5Erik    }
1973dc5e908a825b879978ba523d9099dc2255da9a5Erik
198d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    static void setSharedPreference(Context context, String key, int value) {
199d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
200d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        SharedPreferences.Editor editor = prefs.edit();
201d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        editor.putInt(key, value);
202d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan        editor.apply();
203d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan    }
204d885c1a5876735bbf2c0086956101bd70bac37e7Michael Chan
205d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan    /**
206d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * Save default agenda/day/week/month view for next time
207d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     *
208d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * @param context
209d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     * @param viewId {@link CalendarController.ViewType}
210d6734dbbd704cdb1bc331d1bd74b7a3be58f69ffMichael Chan     */
211e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan    static void setDefaultView(Context context, int viewId) {
2124b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
213e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        SharedPreferences.Editor editor = prefs.edit();
214f4ad4757de32ace6971cf4c3db7c395aa249001aMason Tang
215b60218a31d948ea0a549daf6464063d20b48421fMichael Chan        boolean validDetailView = false;
216b60218a31d948ea0a549daf6464063d20b48421fMichael Chan        if (mAllowWeekForDetailView && viewId == CalendarController.ViewType.WEEK) {
217b60218a31d948ea0a549daf6464063d20b48421fMichael Chan            validDetailView = true;
218b60218a31d948ea0a549daf6464063d20b48421fMichael Chan        } else {
219b60218a31d948ea0a549daf6464063d20b48421fMichael Chan            validDetailView = viewId == CalendarController.ViewType.AGENDA
220b60218a31d948ea0a549daf6464063d20b48421fMichael Chan                    || viewId == CalendarController.ViewType.DAY;
221b60218a31d948ea0a549daf6464063d20b48421fMichael Chan        }
222b60218a31d948ea0a549daf6464063d20b48421fMichael Chan
223b60218a31d948ea0a549daf6464063d20b48421fMichael Chan        if (validDetailView) {
224b60218a31d948ea0a549daf6464063d20b48421fMichael Chan            // Record the detail start view
2254b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa            editor.putInt(GeneralPreferences.KEY_DETAILED_VIEW, viewId);
226e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        }
227e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
228e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        // Record the (new) start view
2294b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        editor.putInt(GeneralPreferences.KEY_START_VIEW, viewId);
23024fac46d6b87ce21d5e6a4b1c0fdcaa83d408997Brad Fitzpatrick        editor.apply();
231e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan    }
232e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
233a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    public static MatrixCursor matrixCursorFromCursor(Cursor cursor) {
234a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames());
235a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        int numColumns = cursor.getColumnCount();
236a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        String data[] = new String[numColumns];
237a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        cursor.moveToPosition(-1);
238a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        while (cursor.moveToNext()) {
239a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            for (int i = 0; i < numColumns; i++) {
240a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                data[i] = cursor.getString(i);
241a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            }
242a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            newCursor.addRow(data);
243a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
244a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        return newCursor;
245a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    }
246a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
247a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    /**
248a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     * Compares two cursors to see if they contain the same data.
249a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     *
2507b92da258a480284dcc15a518ea570072329a31dErik     * @return Returns true of the cursors contain the same data and are not
2517b92da258a480284dcc15a518ea570072329a31dErik     *         null, false otherwise
252a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     */
253a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    public static boolean compareCursors(Cursor c1, Cursor c2) {
2547b92da258a480284dcc15a518ea570072329a31dErik        if (c1 == null || c2 == null) {
255a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
256a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
257a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
258a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        int numColumns = c1.getColumnCount();
259a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if (numColumns != c2.getColumnCount()) {
260a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
261a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
262a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
263a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if (c1.getCount() != c2.getCount()) {
264a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
265a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
266a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
267a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        c1.moveToPosition(-1);
268a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        c2.moveToPosition(-1);
2697b92da258a480284dcc15a518ea570072329a31dErik        while (c1.moveToNext() && c2.moveToNext()) {
2707b92da258a480284dcc15a518ea570072329a31dErik            for (int i = 0; i < numColumns; i++) {
2717b92da258a480284dcc15a518ea570072329a31dErik                if (!TextUtils.equals(c1.getString(i), c2.getString(i))) {
272a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                    return false;
273a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                }
274a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            }
275a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
276a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
277a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        return true;
278a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    }
279a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
280146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
281146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * If the given intent specifies a time (in milliseconds since the epoch),
282146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * then that time is returned. Otherwise, the current time is returned.
283146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
284146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static final long timeFromIntentInMillis(Intent intent) {
2857b92da258a480284dcc15a518ea570072329a31dErik        // If the time was specified, then use that. Otherwise, use the current
2867b92da258a480284dcc15a518ea570072329a31dErik        // time.
2871ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        Uri data = intent.getData();
288146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
2891ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        if (millis == -1 && data != null && data.isHierarchical()) {
2901ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik            List<String> path = data.getPathSegments();
2917b92da258a480284dcc15a518ea570072329a31dErik            if (path.size() == 2 && path.get(0).equals("time")) {
2921ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                try {
2931ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                    millis = Long.valueOf(data.getLastPathSegment());
2941ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                } catch (NumberFormatException e) {
2957b92da258a480284dcc15a518ea570072329a31dErik                    Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time "
2967b92da258a480284dcc15a518ea570072329a31dErik                            + "found. Using current time.");
2971ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                }
2981ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik            }
2991ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        }
30076727b7a9cf780f200414548b9d454bf9a701e3eErik        if (millis <= 0) {
301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            millis = System.currentTimeMillis();
302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return millis;
304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
306146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3077b92da258a480284dcc15a518ea570072329a31dErik     * Formats the given Time object so that it gives the month and year (for
3087b92da258a480284dcc15a518ea570072329a31dErik     * example, "September 2007").
309146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
310146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param time the time to format
311146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return the string containing the weekday and the date
312146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
313ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan    public static String formatMonthYear(Context context, Time time) {
314cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik        int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY
315cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik                | DateUtils.FORMAT_SHOW_YEAR;
316cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik        long millis = time.toMillis(true);
317cfa204ba5c59eb6ebd4b54788ceb31010e4a37a0RoboErik        return formatDateRange(context, millis, millis, flags);
318146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
319146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
320146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
3214c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * Returns a list joined together by the provided delimiter, for example,
3224c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * ["a", "b", "c"] could be joined into "a,b,c"
3234c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     *
3244c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * @param things the things to join together
3254c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * @param delim the delimiter to use
3264c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     * @return a string contained the things joined together
3274c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang     */
3284c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang    public static String join(List<?> things, String delim) {
3294c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        StringBuilder builder = new StringBuilder();
3304c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        boolean first = true;
3314c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        for (Object thing : things) {
3324c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            if (first) {
3334c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang                first = false;
3344c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            } else {
3354c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang                builder.append(delim);
3364c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            }
3374c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang            builder.append(thing.toString());
3384c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        }
3394c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang        return builder.toString();
3404c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang    }
3414c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang
3424c8871bf5dee3b3586b375aee98effde31b781a8Mason Tang    /**
343981874e61ecf29a96a77601a3172b2503b6537eeErik     * Returns the week since {@link Time#EPOCH_JULIAN_DAY} (Jan 1, 1970)
344981874e61ecf29a96a77601a3172b2503b6537eeErik     * adjusted for first day of week.
345981874e61ecf29a96a77601a3172b2503b6537eeErik     *
346981874e61ecf29a96a77601a3172b2503b6537eeErik     * This takes a julian day and the week start day and calculates which
347981874e61ecf29a96a77601a3172b2503b6537eeErik     * week since {@link Time#EPOCH_JULIAN_DAY} that day occurs in, starting
348981874e61ecf29a96a77601a3172b2503b6537eeErik     * at 0. *Do not* use this to compute the ISO week number for the year.
349981874e61ecf29a96a77601a3172b2503b6537eeErik     *
350981874e61ecf29a96a77601a3172b2503b6537eeErik     * @param julianDay The julian day to calculate the week number for
351981874e61ecf29a96a77601a3172b2503b6537eeErik     * @param firstDayOfWeek Which week day is the first day of the week,
352981874e61ecf29a96a77601a3172b2503b6537eeErik     *          see {@link Time#SUNDAY}
353981874e61ecf29a96a77601a3172b2503b6537eeErik     * @return Weeks since the epoch
354981874e61ecf29a96a77601a3172b2503b6537eeErik     */
355981874e61ecf29a96a77601a3172b2503b6537eeErik    public static int getWeeksSinceEpochFromJulianDay(int julianDay, int firstDayOfWeek) {
356981874e61ecf29a96a77601a3172b2503b6537eeErik        int diff = Time.THURSDAY - firstDayOfWeek;
357981874e61ecf29a96a77601a3172b2503b6537eeErik        if (diff < 0) {
358981874e61ecf29a96a77601a3172b2503b6537eeErik            diff += 7;
359981874e61ecf29a96a77601a3172b2503b6537eeErik        }
360981874e61ecf29a96a77601a3172b2503b6537eeErik        int refDay = Time.EPOCH_JULIAN_DAY - diff;
361981874e61ecf29a96a77601a3172b2503b6537eeErik        return (julianDay - refDay) / 7;
362981874e61ecf29a96a77601a3172b2503b6537eeErik    }
363981874e61ecf29a96a77601a3172b2503b6537eeErik
364981874e61ecf29a96a77601a3172b2503b6537eeErik    /**
365981874e61ecf29a96a77601a3172b2503b6537eeErik     * Takes a number of weeks since the epoch and calculates the Julian day of
366981874e61ecf29a96a77601a3172b2503b6537eeErik     * the Monday for that week.
367981874e61ecf29a96a77601a3172b2503b6537eeErik     *
368981874e61ecf29a96a77601a3172b2503b6537eeErik     * This assumes that the week containing the {@link Time#EPOCH_JULIAN_DAY}
369981874e61ecf29a96a77601a3172b2503b6537eeErik     * is considered week 0. It returns the Julian day for the Monday
370981874e61ecf29a96a77601a3172b2503b6537eeErik     * {@code week} weeks after the Monday of the week containing the epoch.
371981874e61ecf29a96a77601a3172b2503b6537eeErik     *
372981874e61ecf29a96a77601a3172b2503b6537eeErik     * @param week Number of weeks since the epoch
373981874e61ecf29a96a77601a3172b2503b6537eeErik     * @return The julian day for the Monday of the given week since the epoch
374981874e61ecf29a96a77601a3172b2503b6537eeErik     */
375981874e61ecf29a96a77601a3172b2503b6537eeErik    public static int getJulianMondayFromWeeksSinceEpoch(int week) {
376981874e61ecf29a96a77601a3172b2503b6537eeErik        return MONDAY_BEFORE_JULIAN_EPOCH + week * 7;
377981874e61ecf29a96a77601a3172b2503b6537eeErik    }
378981874e61ecf29a96a77601a3172b2503b6537eeErik
379981874e61ecf29a96a77601a3172b2503b6537eeErik    /**
38056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Get first day of week as android.text.format.Time constant.
3817b92da258a480284dcc15a518ea570072329a31dErik     *
38256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return the first day of week in android.text.format.Time
38356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
3848e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang    public static int getFirstDayOfWeek(Context context) {
3854b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
3867b92da258a480284dcc15a518ea570072329a31dErik        String pref = prefs.getString(
3877b92da258a480284dcc15a518ea570072329a31dErik                GeneralPreferences.KEY_WEEK_START_DAY, GeneralPreferences.WEEK_START_DEFAULT);
3888e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang
3898e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        int startDay;
3904b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        if (GeneralPreferences.WEEK_START_DEFAULT.equals(pref)) {
3918e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang            startDay = Calendar.getInstance().getFirstDayOfWeek();
3928e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        } else {
3938e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang            startDay = Integer.parseInt(pref);
3948e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang        }
3958e3d430a020744faa21bf4ca24f1a99c36ec5c4fMason Tang
39656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        if (startDay == Calendar.SATURDAY) {
39756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.SATURDAY;
39856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        } else if (startDay == Calendar.MONDAY) {
39956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.MONDAY;
40056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        } else {
40156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.SUNDAY;
40256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        }
40356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
40456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
40556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
406d644b0df14ae6e204369b3454d16976fba32f15cDaisuke Miyakawa     * @return true when week number should be shown.
407981874e61ecf29a96a77601a3172b2503b6537eeErik     */
408981874e61ecf29a96a77601a3172b2503b6537eeErik    public static boolean getShowWeekNumber(Context context) {
409d644b0df14ae6e204369b3454d16976fba32f15cDaisuke Miyakawa        final SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
410981874e61ecf29a96a77601a3172b2503b6537eeErik        return prefs.getBoolean(
411981874e61ecf29a96a77601a3172b2503b6537eeErik                GeneralPreferences.KEY_SHOW_WEEK_NUM, GeneralPreferences.DEFAULT_SHOW_WEEK_NUM);
412981874e61ecf29a96a77601a3172b2503b6537eeErik    }
413981874e61ecf29a96a77601a3172b2503b6537eeErik
414981874e61ecf29a96a77601a3172b2503b6537eeErik    /**
41540bcd101b212c9863c3110c05a487a7ae6ebc3caErik     * @return true when declined events should be hidden.
41640bcd101b212c9863c3110c05a487a7ae6ebc3caErik     */
41740bcd101b212c9863c3110c05a487a7ae6ebc3caErik    public static boolean getHideDeclinedEvents(Context context) {
41840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        final SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
41940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        return prefs.getBoolean(GeneralPreferences.KEY_HIDE_DECLINED, false);
42040bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
42140bcd101b212c9863c3110c05a487a7ae6ebc3caErik
42291b01ed605e36fc5a7a924c226597a62c789b50dErik    public static int getDaysPerWeek(Context context) {
42391b01ed605e36fc5a7a924c226597a62c789b50dErik        final SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
42491b01ed605e36fc5a7a924c226597a62c789b50dErik        return prefs.getInt(GeneralPreferences.KEY_DAYS_PER_WEEK, 7);
42591b01ed605e36fc5a7a924c226597a62c789b50dErik    }
42691b01ed605e36fc5a7a924c226597a62c789b50dErik
42740bcd101b212c9863c3110c05a487a7ae6ebc3caErik    /**
42856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Determine whether the column position is Saturday or not.
4297b92da258a480284dcc15a518ea570072329a31dErik     *
43056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param column the column position
43156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param firstDayOfWeek the first day of week in android.text.format.Time
43256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return true if the column is Saturday position
43356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
43456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static boolean isSaturday(int column, int firstDayOfWeek) {
43556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        return (firstDayOfWeek == Time.SUNDAY && column == 6)
4367b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.MONDAY && column == 5)
4377b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.SATURDAY && column == 0);
43856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
43956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
44056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
44156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Determine whether the column position is Sunday or not.
4427b92da258a480284dcc15a518ea570072329a31dErik     *
44356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param column the column position
44456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param firstDayOfWeek the first day of week in android.text.format.Time
44556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return true if the column is Sunday position
44656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
44756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static boolean isSunday(int column, int firstDayOfWeek) {
44856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        return (firstDayOfWeek == Time.SUNDAY && column == 0)
4497b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.MONDAY && column == 6)
4507b92da258a480284dcc15a518ea570072329a31dErik                || (firstDayOfWeek == Time.SATURDAY && column == 1);
45156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
452ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
453ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    /**
4549da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik     * Convert given UTC time into current local time. This assumes it is for an
4559da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik     * allday event and will adjust the time to be on a midnight boundary.
4563ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     *
4573ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     * @param recycle Time object to recycle, otherwise null.
4583ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     * @param utcTime Time to convert, in UTC.
4599da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik     * @param tz The time zone to convert this time to.
4603ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang     */
4619da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik    public static long convertAlldayUtcToLocal(Time recycle, long utcTime, String tz) {
4623ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        if (recycle == null) {
4633ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang            recycle = new Time();
4643ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        }
4653ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        recycle.timezone = Time.TIMEZONE_UTC;
4663ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        recycle.set(utcTime);
4679da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        recycle.timezone = tz;
4689da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        return recycle.normalize(true);
4699da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik    }
4709da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik
4719da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik    public static long convertAlldayLocalToUTC(Time recycle, long localTime, String tz) {
4729da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        if (recycle == null) {
4739da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik            recycle = new Time();
4749da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        }
4759da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        recycle.timezone = tz;
4769da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        recycle.set(localTime);
4779da910f65de0a325d4268d88f0cf2e2fd653f24aRoboErik        recycle.timezone = Time.TIMEZONE_UTC;
4783ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang        return recycle.normalize(true);
4793ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang    }
4803ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang
4813ea333d41c04fd5f3a5d45f540c17894874429e8Mason Tang    /**
482ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * Scan through a cursor of calendars and check if names are duplicated.
4837b92da258a480284dcc15a518ea570072329a31dErik     * This travels a cursor containing calendar display names and fills in the
4847b92da258a480284dcc15a518ea570072329a31dErik     * provided map with whether or not each name is repeated.
485ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     *
486ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param isDuplicateName The map to put the duplicate check results in.
487ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param cursor The query of calendars to check
488ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param nameIndex The column of the query that contains the display name
489ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     */
4907b92da258a480284dcc15a518ea570072329a31dErik    public static void checkForDuplicateNames(
4917b92da258a480284dcc15a518ea570072329a31dErik            Map<String, Boolean> isDuplicateName, Cursor cursor, int nameIndex) {
492ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        isDuplicateName.clear();
493ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        cursor.moveToPosition(-1);
494ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        while (cursor.moveToNext()) {
495ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            String displayName = cursor.getString(nameIndex);
496ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            // Set it to true if we've seen this name before, false otherwise
497ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            if (displayName != null) {
498ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan                isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
499ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            }
500ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        }
501ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    }
5029138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
5039138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
5049138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * Null-safe object comparison
5057b92da258a480284dcc15a518ea570072329a31dErik     *
5069138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * @param s1
5079138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * @param s2
5089138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     * @return
5099138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang     */
5109138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public static boolean equals(Object o1, Object o2) {
5119138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return o1 == null ? o2 == null : o1.equals(o2);
5129138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    }
513b60218a31d948ea0a549daf6464063d20b48421fMichael Chan
51463cd053150e00fde045b019dbe0f48b8a9ed3559Erik    public static void setAllowWeekForDetailView(boolean allowWeekView) {
515b60218a31d948ea0a549daf6464063d20b48421fMichael Chan        mAllowWeekForDetailView  = allowWeekView;
516b60218a31d948ea0a549daf6464063d20b48421fMichael Chan    }
51763cd053150e00fde045b019dbe0f48b8a9ed3559Erik
51863cd053150e00fde045b019dbe0f48b8a9ed3559Erik    public static boolean getAllowWeekForDetailView() {
51963cd053150e00fde045b019dbe0f48b8a9ed3559Erik        return mAllowWeekForDetailView;
52063cd053150e00fde045b019dbe0f48b8a9ed3559Erik    }
5210b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson
5220b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson    public static boolean isMultiPaneConfiguration (Context c) {
5230b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson        return (c.getResources().getConfiguration().screenLayout &
5240b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson                Configuration.SCREENLAYOUT_SIZE_XLARGE) != 0;
5250b1bd10dbf90e55821a555c68a8a444854e31252Isaac Katzenelson    }
526ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson
527ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson    public static boolean getConfigBool(Context c, int key) {
528ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson        return c.getResources().getBoolean(key);
529ff5c4345f794ec12b0a92f284434ddc1c88ff3a8Isaac Katzenelson    }
53082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
53182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
53282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    // Helper class for createBusyBitSegments function
53382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
53482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    public static class BusyBitsSegment {
53582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        public int start, end;
53682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
53782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        BusyBitsSegment(int s, int e) {
53882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            start = s;
53982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            end = e;
54082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        }
54182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
54282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        @Override
54382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        public int hashCode() {
54482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            final int prime = 31;
54582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            int result = 1;
54682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            result = prime * result + end;
54782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            result = prime * result + start;
54882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            return result;
54982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        }
55082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
55182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        @Override
55282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        public boolean equals(Object obj) {
55382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (this == obj) {
55482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                return true;
55582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
55682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (obj == null) {
55782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                return false;
55882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
55982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (getClass() != obj.getClass()) {
56082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                return false;
56182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
56282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            BusyBitsSegment other = (BusyBitsSegment) obj;
56382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (end != other.end) {
56482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                return false;
56582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
56682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (start != other.start) {
56782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                return false;
56882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
56982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            return true;
57082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        }
57182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    }
57282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
57382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    // Converts a list of events to a list of busy segments to draw
57482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    // Assumes list is ordered according to start date
57582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
57682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    public static ArrayList<BusyBitsSegment> createBusyBitSegments(int pStart, int pEnd,
57782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            int startTime, int endTime,
57882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            ArrayList<Event> events) {
57982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
58082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        if (events == null || events.size() == 0 || pStart >= pEnd || startTime >= endTime)
58182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            return null;
58282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
58382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        ArrayList<BusyBitsSegment> segments = new ArrayList<BusyBitsSegment>();
58482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        int start = -1;
58582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        int end = -1;
58682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        int timeFrame = endTime - startTime;
58782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        int pSize = pEnd - pStart;
58882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
58982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        // Iterate on events and create segments
59082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        Iterator<Event> iter = events.iterator();
59182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        while (iter.hasNext()) {
59282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            Event event = iter.next();
59382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
59482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            int eStart = event.startTime;
59582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            int eEnd = event.endTime;
59682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
59782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            // skip all day events, events that are not in the time frame and
59882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            // events that are zero length
59982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (event.allDay || eStart >= endTime || eEnd <= startTime || eStart == eEnd) {
60082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                continue;
60182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
60282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
60382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (eStart < startTime) {
60482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                eStart = startTime;
60582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
60682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (eEnd > endTime) {
60782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                eEnd = endTime;
60882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
60982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
61082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            // first event , just take the values as the initial segment size
61182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (start == -1 && end == -1) {
61282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                start = eStart;
61382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                end = eEnd;
61482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                continue;
61582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
61682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
61782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            // combine event with current segment
61882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            if (eStart <= end) {
61982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                if (eEnd > end) {
62082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                    end = eEnd;
62182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                }
62282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            } else {
62382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                // Push current segment to segment list and create a new segment
62482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                BusyBitsSegment s = new BusyBitsSegment(
62582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                        (start - startTime) * pSize / timeFrame + pStart,
62682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                        (end - startTime) * pSize / timeFrame + pStart);
62782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                segments.add(s);
62882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                start = eStart;
62982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                end = eEnd;
63082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            }
63182400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        }
63282400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson
63382400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        if (start != end) {
63482400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            BusyBitsSegment s = new BusyBitsSegment(
63582400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                    (start - startTime) * pSize / timeFrame + pStart,
63682400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson                    (end - startTime) * pSize / timeFrame + pStart);
63782400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson            segments.add(s);
63882400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        }
63982400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson        return segments;
64082400dd70331df7885dd59b809c4bc0667046320Isaac Katzenelson    }
641146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
642