Utils.java revision 124d08889f978b9108cfce8a777dcf2e8bbc96a6
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;
36
37import java.util.Calendar;
38import java.util.List;
39import java.util.Map;
40
41public class Utils {
42    // Set to 0 until we have UI to perform undo
43    public static final long UNDO_DELAY = 0;
44
45    // For recurring events which instances of the series are being modified
46    public static final int MODIFY_UNINITIALIZED = 0;
47    public static final int MODIFY_SELECTED = 1;
48    public static final int MODIFY_ALL_FOLLOWING = 2;
49    public static final int MODIFY_ALL = 3;
50
51    // When the edit event view finishes it passes back the appropriate exit code.
52    public static final int DONE_REVERT = 0;
53    public static final int DONE_SAVE = 1;
54    public static final int DONE_DELETE = 2;
55
56    private static final int CLEAR_ALPHA_MASK = 0x00FFFFFF;
57    private static final int HIGH_ALPHA = 255 << 24;
58    private static final int MED_ALPHA = 180 << 24;
59    private static final int LOW_ALPHA = 150 << 24;
60
61    protected static final String OPEN_EMAIL_MARKER = " <";
62    protected static final String CLOSE_EMAIL_MARKER = ">";
63
64    /* The corner should be rounded on the top right and bottom right */
65    private static final float[] CORNERS = new float[] {0, 0, 5, 5, 5, 5, 0, 0};
66
67    public static final String INTENT_KEY_DETAIL_VIEW = "DETAIL_VIEW";
68    public static final String INTENT_KEY_VIEW_TYPE = "VIEW";
69    public static final String INTENT_VALUE_VIEW_TYPE_DAY = "DAY";
70
71    public static int getViewTypeFromIntentAndSharedPref(Activity activity) {
72        Bundle extras = activity.getIntent().getExtras();
73        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(activity);
74
75        if (extras != null) {
76            if (extras.getBoolean(INTENT_KEY_DETAIL_VIEW, false)) {
77                // This is the "detail" view which is either agenda or day view
78                return prefs.getInt(CalendarPreferenceActivity.KEY_DETAILED_VIEW,
79                        CalendarPreferenceActivity.DEFAULT_DETAILED_VIEW);
80            } else if (INTENT_VALUE_VIEW_TYPE_DAY.equals(extras.getString(INTENT_KEY_VIEW_TYPE))) {
81                // Not sure who uses this. This logic came from LaunchActivity
82                return ViewType.DAY;
83            }
84        }
85
86        // Default to the last view
87        return prefs.getInt(CalendarPreferenceActivity.KEY_START_VIEW,
88                CalendarPreferenceActivity.DEFAULT_START_VIEW);
89    }
90
91    static String getSharedPreference(Context context, String key, String defaultValue) {
92        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
93        return prefs.getString(key, defaultValue);
94    }
95
96    public static int getSharedPreference(Context context, String key, int defaultValue) {
97        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
98        return prefs.getInt(key, defaultValue);
99    }
100
101    static void setSharedPreference(Context context, String key, String value) {
102        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
103        SharedPreferences.Editor editor = prefs.edit();
104        editor.putString(key, value);
105        editor.commit();
106    }
107
108    /**
109     * Save default agenda/day/week/month view for next time
110     *
111     * @param context
112     * @param viewId {@link CalendarController.ViewType}
113     */
114    static void setDefaultView(Context context, int viewId) {
115        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
116        SharedPreferences.Editor editor = prefs.edit();
117        if (viewId == CalendarController.ViewType.AGENDA
118                || viewId == CalendarController.ViewType.DAY) {
119            // Record the (new) detail start view only for Agenda and Day
120            editor.putInt(CalendarPreferenceActivity.KEY_DETAILED_VIEW, viewId);
121        }
122
123        // Record the (new) start view
124        editor.putInt(CalendarPreferenceActivity.KEY_START_VIEW, viewId);
125        editor.commit();
126    }
127
128    public static MatrixCursor matrixCursorFromCursor(Cursor cursor) {
129        MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames());
130        int numColumns = cursor.getColumnCount();
131        String data[] = new String[numColumns];
132        cursor.moveToPosition(-1);
133        while (cursor.moveToNext()) {
134            for (int i = 0; i < numColumns; i++) {
135                data[i] = cursor.getString(i);
136            }
137            newCursor.addRow(data);
138        }
139        return newCursor;
140    }
141
142    /**
143     * Compares two cursors to see if they contain the same data.
144     *
145     * @return Returns true of the cursors contain the same data and are not null, false
146     * otherwise
147     */
148    public static boolean compareCursors(Cursor c1, Cursor c2) {
149        if(c1 == null || c2 == null) {
150            return false;
151        }
152
153        int numColumns = c1.getColumnCount();
154        if (numColumns != c2.getColumnCount()) {
155            return false;
156        }
157
158        if (c1.getCount() != c2.getCount()) {
159            return false;
160        }
161
162        c1.moveToPosition(-1);
163        c2.moveToPosition(-1);
164        while(c1.moveToNext() && c2.moveToNext()) {
165            for(int i = 0; i < numColumns; i++) {
166                if(!TextUtils.equals(c1.getString(i), c2.getString(i))) {
167                    return false;
168                }
169            }
170        }
171
172        return true;
173    }
174
175    /**
176     * If the given intent specifies a time (in milliseconds since the epoch),
177     * then that time is returned. Otherwise, the current time is returned.
178     */
179    public static final long timeFromIntentInMillis(Intent intent) {
180        // If the time was specified, then use that.  Otherwise, use the current time.
181        Uri data = intent.getData();
182        long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
183        if (millis == -1 && data != null && data.isHierarchical()) {
184            List<String> path = data.getPathSegments();
185            if(path.size() == 2 && path.get(0).equals("time")) {
186                try {
187                    millis = Long.valueOf(data.getLastPathSegment());
188                } catch (NumberFormatException e) {
189                    Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time " +
190                            "found. Using current time.");
191                }
192            }
193        }
194        if (millis <= 0) {
195            millis = System.currentTimeMillis();
196        }
197        return millis;
198    }
199
200    public static Drawable getColorChip(int color) {
201        /*
202         * We want the color chip to have a nice gradient using
203         * the color of the calendar. To do this we use a GradientDrawable.
204         * The color supplied has an alpha of FF so we first do:
205         * color & 0x00FFFFFF
206         * to clear the alpha. Then we add our alpha to it.
207         * We use 3 colors to get a step effect where it starts off very
208         * light and quickly becomes dark and then a slow transition to
209         * be even darker.
210         */
211        color &= CLEAR_ALPHA_MASK;
212        int startColor = color | HIGH_ALPHA;
213        int middleColor = color | MED_ALPHA;
214        int endColor = color | LOW_ALPHA;
215        int[] colors = new int[] {startColor, middleColor, endColor};
216        GradientDrawable d = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
217        d.setCornerRadii(CORNERS);
218        return d;
219    }
220
221    /**
222     * Formats the given Time object so that it gives the month and year
223     * (for example, "September 2007").
224     *
225     * @param time the time to format
226     * @return the string containing the weekday and the date
227     */
228    public static String formatMonthYear(Context context, Time time) {
229        return time.format(context.getResources().getString(R.string.month_year));
230    }
231
232    /**
233     * Get first day of week as android.text.format.Time constant.
234     * @return the first day of week in android.text.format.Time
235     */
236    public static int getFirstDayOfWeek(Context context) {
237        SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
238        String pref = prefs.getString(CalendarPreferenceActivity.KEY_WEEK_START_DAY,
239                CalendarPreferenceActivity.WEEK_START_DEFAULT);
240
241        int startDay;
242        if (CalendarPreferenceActivity.WEEK_START_DEFAULT.equals(pref)) {
243            startDay = Calendar.getInstance().getFirstDayOfWeek();
244        } else {
245            startDay = Integer.parseInt(pref);
246        }
247
248        if (startDay == Calendar.SATURDAY) {
249            return Time.SATURDAY;
250        } else if (startDay == Calendar.MONDAY) {
251            return Time.MONDAY;
252        } else {
253            return Time.SUNDAY;
254        }
255    }
256
257    /**
258     * Determine whether the column position is Saturday or not.
259     * @param column the column position
260     * @param firstDayOfWeek the first day of week in android.text.format.Time
261     * @return true if the column is Saturday position
262     */
263    public static boolean isSaturday(int column, int firstDayOfWeek) {
264        return (firstDayOfWeek == Time.SUNDAY && column == 6)
265            || (firstDayOfWeek == Time.MONDAY && column == 5)
266            || (firstDayOfWeek == Time.SATURDAY && column == 0);
267    }
268
269    /**
270     * Determine whether the column position is Sunday or not.
271     * @param column the column position
272     * @param firstDayOfWeek the first day of week in android.text.format.Time
273     * @return true if the column is Sunday position
274     */
275    public static boolean isSunday(int column, int firstDayOfWeek) {
276        return (firstDayOfWeek == Time.SUNDAY && column == 0)
277            || (firstDayOfWeek == Time.MONDAY && column == 6)
278            || (firstDayOfWeek == Time.SATURDAY && column == 1);
279    }
280
281    /**
282     * Scan through a cursor of calendars and check if names are duplicated.
283     *
284     * This travels a cursor containing calendar display names and fills in the provided map with
285     * whether or not each name is repeated.
286     * @param isDuplicateName The map to put the duplicate check results in.
287     * @param cursor The query of calendars to check
288     * @param nameIndex The column of the query that contains the display name
289     */
290    public static void checkForDuplicateNames(Map<String, Boolean> isDuplicateName, Cursor cursor,
291            int nameIndex) {
292        isDuplicateName.clear();
293        cursor.moveToPosition(-1);
294        while (cursor.moveToNext()) {
295            String displayName = cursor.getString(nameIndex);
296            // Set it to true if we've seen this name before, false otherwise
297            if (displayName != null) {
298                isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
299            }
300        }
301    }
302
303    /**
304     * Null-safe object comparison
305     * @param s1
306     * @param s2
307     * @return
308     */
309    public static boolean equals(Object o1, Object o2) {
310        return o1 == null ? o2 == null : o1.equals(o2);
311    }
312}
313