Utils.java revision d6734dbbd704cdb1bc331d1bd74b7a3be58f69ff
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendar;
18
19import static android.provider.Calendar.EVENT_BEGIN_TIME;
20
21import com.android.calendar.CalendarController.ViewType;
22
23import android.app.Activity;
24import android.content.Context;
25import android.content.Intent;
26import android.content.SharedPreferences;
27import android.database.Cursor;
28import android.database.MatrixCursor;
29import android.graphics.drawable.Drawable;
30import android.graphics.drawable.GradientDrawable;
31import android.net.Uri;
32import android.os.Bundle;
33import android.text.TextUtils;
34import android.text.format.Time;
35import android.util.Log;
36import android.view.animation.AlphaAnimation;
37import android.widget.ViewFlipper;
38
39import java.util.Calendar;
40import java.util.List;
41import java.util.Map;
42
43public class Utils {
44    // Set to 0 until we have UI to perform undo
45    public static final long UNDO_DELAY = 0;
46
47    // For recurring events which instances of the series are being modified
48    public static final int MODIFY_UNINITIALIZED = 0;
49    public static final int MODIFY_SELECTED = 1;
50    public static final int MODIFY_ALL_FOLLOWING = 2;
51    public static final int MODIFY_ALL = 3;
52
53    // When the edit event view finishes it passes back the appropriate exit code.
54    public static final int DONE_REVERT = 0;
55    public static final int DONE_SAVE = 1;
56    public static final int DONE_DELETE = 2;
57
58    private static final int CLEAR_ALPHA_MASK = 0x00FFFFFF;
59    private static final int HIGH_ALPHA = 255 << 24;
60    private static final int MED_ALPHA = 180 << 24;
61    private static final int LOW_ALPHA = 150 << 24;
62
63    protected static final String OPEN_EMAIL_MARKER = " <";
64    protected static final String CLOSE_EMAIL_MARKER = ">";
65
66    /* The corner should be rounded on the top right and bottom right */
67    private static final float[] CORNERS = new float[] {0, 0, 5, 5, 5, 5, 0, 0};
68
69    public static final String INTENT_KEY_DETAIL_VIEW = "DETAIL_VIEW";
70    public static final String INTENT_KEY_VIEW_TYPE = "VIEW";
71    public static final String INTENT_VALUE_VIEW_TYPE_DAY = "DAY";
72
73    public static int getViewTypeFromIntentAndSharedPref(Activity activity) {
74        Bundle extras = activity.getIntent().getExtras();
75        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(activity);
76
77        if (extras != null) {
78            if (extras.getBoolean(INTENT_KEY_DETAIL_VIEW, false)) {
79                // This is the "detail" view which is either agenda or day view
80                return prefs.getInt(CalendarPreferenceActivity.KEY_DETAILED_VIEW,
81                        CalendarPreferenceActivity.DEFAULT_DETAILED_VIEW);
82            } else if (INTENT_VALUE_VIEW_TYPE_DAY.equals(extras.getString(INTENT_KEY_VIEW_TYPE))) {
83                // Not sure who uses this. This logic came from LaunchActivity
84                return ViewType.DAY;
85            }
86        }
87
88        // Default to the last view
89        return prefs.getInt(CalendarPreferenceActivity.KEY_START_VIEW,
90                CalendarPreferenceActivity.DEFAULT_START_VIEW);
91    }
92
93    public static void startActivity(Context context, String className, long time) {
94        Intent intent = new Intent(Intent.ACTION_VIEW);
95
96        intent.setClassName(context, className);
97        intent.putExtra(EVENT_BEGIN_TIME, time);
98        intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
99
100        context.startActivity(intent);
101    }
102
103    static String getSharedPreference(Context context, String key, String defaultValue) {
104        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
105        return prefs.getString(key, defaultValue);
106    }
107
108    public static int getSharedPreference(Context context, String key, int defaultValue) {
109        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
110        return prefs.getInt(key, defaultValue);
111    }
112
113    static void setSharedPreference(Context context, String key, String value) {
114        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
115        SharedPreferences.Editor editor = prefs.edit();
116        editor.putString(key, value);
117        editor.commit();
118    }
119
120    /**
121     * Save default agenda/day/week/month view for next time
122     *
123     * @param context
124     * @param viewId {@link CalendarController.ViewType}
125     */
126    static void setDefaultView(Context context, int viewId) {
127        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
128        SharedPreferences.Editor editor = prefs.edit();
129        if (viewId == CalendarController.ViewType.AGENDA
130                || viewId == CalendarController.ViewType.DAY) {
131            // Record the (new) detail start view only for Agenda and Day
132            editor.putInt(CalendarPreferenceActivity.KEY_DETAILED_VIEW, viewId);
133        }
134
135        // Record the (new) start view
136        editor.putInt(CalendarPreferenceActivity.KEY_START_VIEW, viewId);
137        editor.commit();
138    }
139
140    public static final Time timeFromIntent(Intent intent) {
141        Time time = new Time();
142        time.set(timeFromIntentInMillis(intent));
143        return time;
144    }
145
146    public static MatrixCursor matrixCursorFromCursor(Cursor cursor) {
147        MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames());
148        int numColumns = cursor.getColumnCount();
149        String data[] = new String[numColumns];
150        cursor.moveToPosition(-1);
151        while (cursor.moveToNext()) {
152            for (int i = 0; i < numColumns; i++) {
153                data[i] = cursor.getString(i);
154            }
155            newCursor.addRow(data);
156        }
157        return newCursor;
158    }
159
160    /**
161     * Compares two cursors to see if they contain the same data.
162     *
163     * @return Returns true of the cursors contain the same data and are not null, false
164     * otherwise
165     */
166    public static boolean compareCursors(Cursor c1, Cursor c2) {
167        if(c1 == null || c2 == null) {
168            return false;
169        }
170
171        int numColumns = c1.getColumnCount();
172        if (numColumns != c2.getColumnCount()) {
173            return false;
174        }
175
176        if (c1.getCount() != c2.getCount()) {
177            return false;
178        }
179
180        c1.moveToPosition(-1);
181        c2.moveToPosition(-1);
182        while(c1.moveToNext() && c2.moveToNext()) {
183            for(int i = 0; i < numColumns; i++) {
184                if(!TextUtils.equals(c1.getString(i), c2.getString(i))) {
185                    return false;
186                }
187            }
188        }
189
190        return true;
191    }
192
193    /**
194     * If the given intent specifies a time (in milliseconds since the epoch),
195     * then that time is returned. Otherwise, the current time is returned.
196     */
197    public static final long timeFromIntentInMillis(Intent intent) {
198        // If the time was specified, then use that.  Otherwise, use the current time.
199        Uri data = intent.getData();
200        long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
201        if (millis == -1 && data != null && data.isHierarchical()) {
202            List<String> path = data.getPathSegments();
203            if(path.size() == 2 && path.get(0).equals("time")) {
204                try {
205                    millis = Long.valueOf(data.getLastPathSegment());
206                } catch (NumberFormatException e) {
207                    Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time " +
208                            "found. Using current time.");
209                }
210            }
211        }
212        if (millis <= 0) {
213            millis = System.currentTimeMillis();
214        }
215        return millis;
216    }
217
218    public static final void applyAlphaAnimation(ViewFlipper v) {
219        AlphaAnimation in = new AlphaAnimation(0.0f, 1.0f);
220
221        in.setStartOffset(0);
222        in.setDuration(500);
223
224        AlphaAnimation out = new AlphaAnimation(1.0f, 0.0f);
225
226        out.setStartOffset(0);
227        out.setDuration(500);
228
229        v.setInAnimation(in);
230        v.setOutAnimation(out);
231    }
232
233    public static Drawable getColorChip(int color) {
234        /*
235         * We want the color chip to have a nice gradient using
236         * the color of the calendar. To do this we use a GradientDrawable.
237         * The color supplied has an alpha of FF so we first do:
238         * color & 0x00FFFFFF
239         * to clear the alpha. Then we add our alpha to it.
240         * We use 3 colors to get a step effect where it starts off very
241         * light and quickly becomes dark and then a slow transition to
242         * be even darker.
243         */
244        color &= CLEAR_ALPHA_MASK;
245        int startColor = color | HIGH_ALPHA;
246        int middleColor = color | MED_ALPHA;
247        int endColor = color | LOW_ALPHA;
248        int[] colors = new int[] {startColor, middleColor, endColor};
249        GradientDrawable d = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
250        d.setCornerRadii(CORNERS);
251        return d;
252    }
253
254    /**
255     * Formats the given Time object so that it gives the month and year
256     * (for example, "September 2007").
257     *
258     * @param time the time to format
259     * @return the string containing the weekday and the date
260     */
261    public static String formatMonthYear(Context context, Time time) {
262        return time.format(context.getResources().getString(R.string.month_year));
263    }
264
265    /**
266     * Sets the time to the beginning of the day (midnight) by clearing the
267     * hour, minute, and second fields.
268     */
269    static void setTimeToStartOfDay(Time time) {
270        time.second = 0;
271        time.minute = 0;
272        time.hour = 0;
273    }
274
275    /**
276     * Get first day of week as android.text.format.Time constant.
277     * @return the first day of week in android.text.format.Time
278     */
279    public static int getFirstDayOfWeek(Context context) {
280        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
281        String pref = prefs.getString(CalendarPreferenceActivity.KEY_WEEK_START_DAY,
282                CalendarPreferenceActivity.WEEK_START_DEFAULT);
283
284        int startDay;
285        if (CalendarPreferenceActivity.WEEK_START_DEFAULT.equals(pref)) {
286            startDay = Calendar.getInstance().getFirstDayOfWeek();
287        } else {
288            startDay = Integer.parseInt(pref);
289        }
290
291        if (startDay == Calendar.SATURDAY) {
292            return Time.SATURDAY;
293        } else if (startDay == Calendar.MONDAY) {
294            return Time.MONDAY;
295        } else {
296            return Time.SUNDAY;
297        }
298    }
299
300    /**
301     * Determine whether the column position is Saturday or not.
302     * @param column the column position
303     * @param firstDayOfWeek the first day of week in android.text.format.Time
304     * @return true if the column is Saturday position
305     */
306    public static boolean isSaturday(int column, int firstDayOfWeek) {
307        return (firstDayOfWeek == Time.SUNDAY && column == 6)
308            || (firstDayOfWeek == Time.MONDAY && column == 5)
309            || (firstDayOfWeek == Time.SATURDAY && column == 0);
310    }
311
312    /**
313     * Determine whether the column position is Sunday or not.
314     * @param column the column position
315     * @param firstDayOfWeek the first day of week in android.text.format.Time
316     * @return true if the column is Sunday position
317     */
318    public static boolean isSunday(int column, int firstDayOfWeek) {
319        return (firstDayOfWeek == Time.SUNDAY && column == 0)
320            || (firstDayOfWeek == Time.MONDAY && column == 6)
321            || (firstDayOfWeek == Time.SATURDAY && column == 1);
322    }
323
324    /**
325     * Scan through a cursor of calendars and check if names are duplicated.
326     *
327     * This travels a cursor containing calendar display names and fills in the provided map with
328     * whether or not each name is repeated.
329     * @param isDuplicateName The map to put the duplicate check results in.
330     * @param cursor The query of calendars to check
331     * @param nameIndex The column of the query that contains the display name
332     */
333    public static void checkForDuplicateNames(Map<String, Boolean> isDuplicateName, Cursor cursor,
334            int nameIndex) {
335        isDuplicateName.clear();
336        cursor.moveToPosition(-1);
337        while (cursor.moveToNext()) {
338            String displayName = cursor.getString(nameIndex);
339            // Set it to true if we've seen this name before, false otherwise
340            if (displayName != null) {
341                isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
342            }
343        }
344    }
345
346    /**
347     * Null-safe object comparison
348     * @param s1
349     * @param s2
350     * @return
351     */
352    public static boolean equals(Object o1, Object o2) {
353        return o1 == null ? o2 == null : o1.equals(o2);
354    }
355}
356