Utils.java revision 235d59cf61769ec8ab777d81cd1ceb2e7530f439
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
21146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context;
22146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Intent;
23e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chanimport android.content.SharedPreferences;
24ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.database.Cursor;
25a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErikimport android.database.MatrixCursor;
26ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.graphics.drawable.Drawable;
27ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport android.graphics.drawable.GradientDrawable;
281ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.net.Uri;
29eb10fa8bee049e0052b5cb53dcfbdaccef9f2740Erikimport android.text.TextUtils;
30146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.format.Time;
311ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport android.util.Log;
32146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.view.animation.AlphaAnimation;
33146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.widget.ViewFlipper;
34146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
3556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashiimport java.util.Calendar;
36235d59cf61769ec8ab777d81cd1ceb2e7530f439Erikimport java.util.HashSet;
371ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erikimport java.util.List;
38ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chanimport java.util.Map;
3956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
40146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpublic class Utils {
41ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int CLEAR_ALPHA_MASK = 0x00FFFFFF;
42ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int HIGH_ALPHA = 255 << 24;
43ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int MED_ALPHA = 180 << 24;
44ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final int LOW_ALPHA = 150 << 24;
45ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
46ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    protected static final String OPEN_EMAIL_MARKER = " <";
47ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    protected static final String CLOSE_EMAIL_MARKER = ">";
48ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
49ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    /* The corner should be rounded on the top right and bottom right */
50ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    private static final float[] CORNERS = new float[] {0, 0, 5, 5, 5, 5, 0, 0};
51ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
52235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    private volatile static boolean mFirstTZRequest = true;
53235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    private volatile static boolean mTZQueryInProgress = false;
54235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik
55235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    private volatile static boolean mUseHomeTZ = false;
56235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    private volatile static String mHomeTZ = Time.getCurrentTimezone();
57235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik
58235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    private static HashSet<Runnable> mTZCallbacks = new HashSet<Runnable>();
59ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
60146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static void startActivity(Context context, String className, long time) {
61146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Intent intent = new Intent(Intent.ACTION_VIEW);
62146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
63146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        intent.setClassName(context, className);
64146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        intent.putExtra(EVENT_BEGIN_TIME, time);
6523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
66146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
67146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        context.startActivity(intent);
68146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
7045efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    static String getSharedPreference(Context context, String key, String defaultValue) {
71a17725e24d51b7a6f002dd5afd3270c8eeea0dbeJeff Hamilton        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
7245efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan        return prefs.getString(key, defaultValue);
7345efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    }
7445efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan
75235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    /**
76235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * Gets the time zone that Calendar should be displayed in
77235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     *
78235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * This is a helper method to get the appropriate time zone for Calendar. If this
79235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * is the first time this method has been called it will initiate an asynchronous
80235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * query to verify that the data in preferences is correct. The callback supplied
81235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * will only be called if this query returns a value other than what is stored in
82235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * preferences and should cause the calling activity to refresh anything that
83235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * depends on calling this method.
84235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     *
85235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * @param context The calling activity
86235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * @param callback The runnable that should execute if a query returns new values
87235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     * @return The string value representing the time zone Calendar should display
88235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik     */
89235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    public static String getTimeZone(Context context, Runnable callback) {
90235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik        synchronized (mTZCallbacks){
91235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik            if (mFirstTZRequest) {
92235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                mTZQueryInProgress = true;
93235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                mFirstTZRequest = false;
94235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik
95235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
96235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                mUseHomeTZ = prefs.getBoolean(
97235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                        CalendarPreferenceActivity.KEY_HOME_TZ_ENABLED, false);
98235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                mHomeTZ = prefs.getString(
99235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                        CalendarPreferenceActivity.KEY_HOME_TZ, Time.getCurrentTimezone());
100235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                // TODO kick off async query
101235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                // When the async query returns it should synchronize on
102235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                // mTZCallbacks, update mUseHomeTZ, mHomeTZ, and the
103235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                // preferences, set mTZQueryInProgress to false, and call all
104235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                // the runnables in mTZCallbacks.
105235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                // TODO remove this line when we have a query
106235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                mTZQueryInProgress = false;
107235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik            }
108235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik            if (mTZQueryInProgress) {
109235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik                mTZCallbacks.add(callback);
110235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik            }
111235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik        }
112235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik        return mUseHomeTZ ? mHomeTZ : Time.getCurrentTimezone();
113235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik    }
114235d59cf61769ec8ab777d81cd1ceb2e7530f439Erik
11545efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    static void setSharedPreference(Context context, String key, String value) {
116a17725e24d51b7a6f002dd5afd3270c8eeea0dbeJeff Hamilton        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
11745efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan        SharedPreferences.Editor editor = prefs.edit();
11845efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan        editor.putString(key, value);
11945efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan        editor.commit();
12045efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan    }
12145efa09d6e06f5569b2c0ae0dae0436dbfe6cb28Michael Chan
122e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan    static void setDefaultView(Context context, int viewId) {
123e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        String activityString = CalendarApplication.ACTIVITY_NAMES[viewId];
124e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
125a17725e24d51b7a6f002dd5afd3270c8eeea0dbeJeff Hamilton        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
126e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        SharedPreferences.Editor editor = prefs.edit();
127e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        if (viewId == CalendarApplication.AGENDA_VIEW_ID ||
128e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan                viewId == CalendarApplication.DAY_VIEW_ID) {
129e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan            // Record the (new) detail start view only for Agenda and Day
130e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan            editor.putString(CalendarPreferenceActivity.KEY_DETAILED_VIEW, activityString);
131e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        }
132e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
133e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        // Record the (new) start view
134e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
135e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan        editor.commit();
136e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan    }
137e8aa59d4575d712601a133a9263acc23adbc8c17Michael Chan
138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static final Time timeFromIntent(Intent intent) {
139146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Time time = new Time();
140146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.set(timeFromIntentInMillis(intent));
141146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return time;
142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
143146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
144a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    public static MatrixCursor matrixCursorFromCursor(Cursor cursor) {
145a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames());
146a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        int numColumns = cursor.getColumnCount();
147a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        String data[] = new String[numColumns];
148a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        cursor.moveToPosition(-1);
149a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        while (cursor.moveToNext()) {
150a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            for (int i = 0; i < numColumns; i++) {
151a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                data[i] = cursor.getString(i);
152a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            }
153a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            newCursor.addRow(data);
154a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
155a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        return newCursor;
156a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    }
157a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
158a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    /**
159a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     * Compares two cursors to see if they contain the same data.
160a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     *
161a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     * @return Returns true of the cursors contain the same data and are not null, false
162a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     * otherwise
163a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik     */
164a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    public static boolean compareCursors(Cursor c1, Cursor c2) {
165a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if(c1 == null || c2 == null) {
166a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
167a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
168a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
169a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        int numColumns = c1.getColumnCount();
170a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if (numColumns != c2.getColumnCount()) {
171a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
172a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
173a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
174a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        if (c1.getCount() != c2.getCount()) {
175a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            return false;
176a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
177a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
178a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        c1.moveToPosition(-1);
179a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        c2.moveToPosition(-1);
180a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        while(c1.moveToNext() && c2.moveToNext()) {
181a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            for(int i = 0; i < numColumns; i++) {
182eb10fa8bee049e0052b5cb53dcfbdaccef9f2740Erik                if(!TextUtils.equals(c1.getString(i), c2.getString(i))) {
183a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                    return false;
184a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik                }
185a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik            }
186a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        }
187a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
188a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik        return true;
189a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik    }
190a144f86b41170e8ee7fe8d966cc51c5fc90cd44aErik
191146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
192146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * If the given intent specifies a time (in milliseconds since the epoch),
193146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * then that time is returned. Otherwise, the current time is returned.
194146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
195146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static final long timeFromIntentInMillis(Intent intent) {
196146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // If the time was specified, then use that.  Otherwise, use the current time.
1971ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        Uri data = intent.getData();
198146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
1991ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        if (millis == -1 && data != null && data.isHierarchical()) {
2001ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik            List<String> path = data.getPathSegments();
201eca5d33e4230cf6ac3acfe3fabf853f9275f98caErik            if(path.size() == 2 && path.get(0).equals("time")) {
2021ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                try {
2031ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                    millis = Long.valueOf(data.getLastPathSegment());
2041ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                } catch (NumberFormatException e) {
2051ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                    Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time " +
2061ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                            "found. Using current time.");
2071ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik                }
2081ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik            }
2091ef7f3ae2831dce8fa5e350f78ac4258c1a0a605Erik        }
21076727b7a9cf780f200414548b9d454bf9a701e3eErik        if (millis <= 0) {
211146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            millis = System.currentTimeMillis();
212146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
213146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return millis;
214146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
216146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static final void applyAlphaAnimation(ViewFlipper v) {
217146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        AlphaAnimation in = new AlphaAnimation(0.0f, 1.0f);
218146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
219146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        in.setStartOffset(0);
220146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        in.setDuration(500);
221146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
222146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        AlphaAnimation out = new AlphaAnimation(1.0f, 0.0f);
223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
224146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        out.setStartOffset(0);
225146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        out.setDuration(500);
226146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
227146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        v.setInAnimation(in);
228146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        v.setOutAnimation(out);
229146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
230146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
231ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    public static Drawable getColorChip(int color) {
232ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        /*
233ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * We want the color chip to have a nice gradient using
234ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * the color of the calendar. To do this we use a GradientDrawable.
235ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * The color supplied has an alpha of FF so we first do:
236ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * color & 0x00FFFFFF
237ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * to clear the alpha. Then we add our alpha to it.
238ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * We use 3 colors to get a step effect where it starts off very
239ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * light and quickly becomes dark and then a slow transition to
240ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         * be even darker.
241ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan         */
242ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        color &= CLEAR_ALPHA_MASK;
243ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int startColor = color | HIGH_ALPHA;
244ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int middleColor = color | MED_ALPHA;
245ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int endColor = color | LOW_ALPHA;
246ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        int[] colors = new int[] {startColor, middleColor, endColor};
247ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        GradientDrawable d = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
248ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        d.setCornerRadii(CORNERS);
249ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        return d;
250ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    }
251ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
252146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
253146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Formats the given Time object so that it gives the month and year
254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * (for example, "September 2007").
255146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     *
256146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @param time the time to format
257146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * @return the string containing the weekday and the date
258146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
259ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan    public static String formatMonthYear(Context context, Time time) {
260ad36a3c3cde7a2ec6d3a35d2529d46f03bd8d59dMichael Chan        return time.format(context.getResources().getString(R.string.month_year));
261146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
262146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
263146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    // TODO: replace this with the correct i18n way to do this
264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static final String englishNthDay[] = {
265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        "", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th",
266146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th",
267146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th",
268146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        "30th", "31st"
269146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
270146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
271146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public static String formatNth(int nth) {
272146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return "the " + englishNthDay[nth];
273146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
274146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
275146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    /**
276d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     * Returns a list joined together by the provided delimiter, for example,
277d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     * ["a", "b", "c"] could be joined into "a,b,c"
278d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     *
279d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     * @param things the things to join together
280d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     * @param delim the delimiter to use
281d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     * @return a string contained the things joined together
282d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang     */
283d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang    public static String join(List<?> things, String delim) {
284d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang        StringBuilder builder = new StringBuilder();
285d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang        boolean first = true;
286d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang        for (Object thing : things) {
287d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang            if (first) {
288d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang                first = false;
289d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang            } else {
290d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang                builder.append(delim);
291d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang            }
292d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang            builder.append(thing.toString());
293d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang        }
294d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang        return builder.toString();
295d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang    }
296d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang
297d7c7f2ab6fdb55451ead2d54819ba8f37af2d0a7Mason Tang    /**
298146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * Sets the time to the beginning of the day (midnight) by clearing the
299146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     * hour, minute, and second fields.
300146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project     */
301146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    static void setTimeToStartOfDay(Time time) {
302146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.second = 0;
303146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.minute = 0;
304146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        time.hour = 0;
305146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
30656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
30756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
30856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Get first day of week as android.text.format.Time constant.
30956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return the first day of week in android.text.format.Time
31056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
31156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static int getFirstDayOfWeek() {
31256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        int startDay = Calendar.getInstance().getFirstDayOfWeek();
31356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        if (startDay == Calendar.SATURDAY) {
31456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.SATURDAY;
31556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        } else if (startDay == Calendar.MONDAY) {
31656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.MONDAY;
31756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        } else {
31856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            return Time.SUNDAY;
31956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        }
32056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
32156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
32256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
32356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Determine whether the column position is Saturday or not.
32456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param column the column position
32556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param firstDayOfWeek the first day of week in android.text.format.Time
32656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return true if the column is Saturday position
32756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
32856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static boolean isSaturday(int column, int firstDayOfWeek) {
32956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        return (firstDayOfWeek == Time.SUNDAY && column == 6)
33056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            || (firstDayOfWeek == Time.MONDAY && column == 5)
33156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            || (firstDayOfWeek == Time.SATURDAY && column == 0);
33256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
33356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi
33456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    /**
33556adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * Determine whether the column position is Sunday or not.
33656adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param column the column position
33756adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @param firstDayOfWeek the first day of week in android.text.format.Time
33856adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     * @return true if the column is Sunday position
33956adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi     */
34056adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    public static boolean isSunday(int column, int firstDayOfWeek) {
34156adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi        return (firstDayOfWeek == Time.SUNDAY && column == 0)
34256adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            || (firstDayOfWeek == Time.MONDAY && column == 6)
34356adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi            || (firstDayOfWeek == Time.SATURDAY && column == 1);
34456adc7b3f9e62ada7f3708c5c7228e8ac5af1755Takaoka G. Tadashi    }
345ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan
346ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    /**
347ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * Scan through a cursor of calendars and check if names are duplicated.
348ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     *
349ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * This travels a cursor containing calendar display names and fills in the provided map with
350ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * whether or not each name is repeated.
351ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param isDuplicateName The map to put the duplicate check results in.
352ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param cursor The query of calendars to check
353ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     * @param nameIndex The column of the query that contains the display name
354ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan     */
355ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    public static void checkForDuplicateNames(Map<String, Boolean> isDuplicateName, Cursor cursor,
356ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            int nameIndex) {
357ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        isDuplicateName.clear();
358ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        cursor.moveToPosition(-1);
359ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        while (cursor.moveToNext()) {
360ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            String displayName = cursor.getString(nameIndex);
361ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            // Set it to true if we've seen this name before, false otherwise
362ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            if (displayName != null) {
363ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan                isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
364ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan            }
365ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan        }
366ff6be831fc682374be6b78c13ecf5daca81f86d9Michael Chan    }
367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
368