• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.calendar;
18 
19 import static android.provider.Calendar.EVENT_BEGIN_TIME;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.database.Cursor;
25 import android.database.MatrixCursor;
26 import android.graphics.drawable.Drawable;
27 import android.graphics.drawable.GradientDrawable;
28 import android.net.Uri;
29 import android.text.TextUtils;
30 import android.text.format.Time;
31 import android.util.CalendarUtils.TimeZoneUtils;
32 import android.util.Log;
33 import android.view.animation.AlphaAnimation;
34 import android.widget.ViewFlipper;
35 
36 import java.util.Calendar;
37 import java.util.Formatter;
38 import java.util.List;
39 import java.util.Map;
40 
41 public class Utils {
42     private static final boolean DEBUG = true;
43     private static final String TAG = "CalUtils";
44     private static final int CLEAR_ALPHA_MASK = 0x00FFFFFF;
45     private static final int HIGH_ALPHA = 255 << 24;
46     private static final int MED_ALPHA = 180 << 24;
47     private static final int LOW_ALPHA = 150 << 24;
48 
49     protected static final String OPEN_EMAIL_MARKER = " <";
50     protected static final String CLOSE_EMAIL_MARKER = ">";
51     /* The corner should be rounded on the top right and bottom right */
52     private static final float[] CORNERS = new float[] {0, 0, 5, 5, 5, 5, 0, 0};
53 
54     // The name of the shared preferences file. This name must be maintained for historical
55     // reasons, as it's what PreferenceManager assigned the first time the file was created.
56     private static final String SHARED_PREFS_NAME = "com.android.calendar_preferences";
57 
58     private static final TimeZoneUtils mTZUtils = new TimeZoneUtils(SHARED_PREFS_NAME);
59 
startActivity(Context context, String className, long time)60     public static void startActivity(Context context, String className, long time) {
61         Intent intent = new Intent(Intent.ACTION_VIEW);
62 
63         intent.setClassName(context, className);
64         intent.putExtra(EVENT_BEGIN_TIME, time);
65         intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
66 
67         context.startActivity(intent);
68     }
69 
getSharedPreference(Context context, String key, String defaultValue)70     static String getSharedPreference(Context context, String key, String defaultValue) {
71         SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
72         return prefs.getString(key, defaultValue);
73     }
74 
75     /**
76      * Writes a new home time zone to the db.
77      *
78      * Updates the home time zone in the db asynchronously and updates
79      * the local cache. Sending a time zone of **tbd** will cause it to
80      * be set to the device's time zone. null or empty tz will be ignored.
81      *
82      * @param context The calling activity
83      * @param timeZone The time zone to set Calendar to, or **tbd**
84      */
setTimeZone(Context context, String timeZone)85     public static void setTimeZone(Context context, String timeZone) {
86         mTZUtils.setTimeZone(context, timeZone);
87     }
88 
89     /**
90      * Gets the time zone that Calendar should be displayed in
91      *
92      * This is a helper method to get the appropriate time zone for Calendar. If this
93      * is the first time this method has been called it will initiate an asynchronous
94      * query to verify that the data in preferences is correct. The callback supplied
95      * will only be called if this query returns a value other than what is stored in
96      * preferences and should cause the calling activity to refresh anything that
97      * depends on calling this method.
98      *
99      * @param context The calling activity
100      * @param callback The runnable that should execute if a query returns new values
101      * @return The string value representing the time zone Calendar should display
102      */
getTimeZone(Context context, Runnable callback)103     public static String getTimeZone(Context context, Runnable callback) {
104         return mTZUtils.getTimeZone(context, callback);
105     }
106 
107     /**
108      * Formats a date or a time range according to the local conventions.
109      *
110      * @param context the context is required only if the time is shown
111      * @param startMillis the start time in UTC milliseconds
112      * @param endMillis the end time in UTC milliseconds
113      * @param flags a bit mask of options See
114      * {@link #formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
115      * @return a string containing the formatted date/time range.
116      */
formatDateRange(Context context, long startMillis, long endMillis, int flags)117     public static String formatDateRange(Context context, long startMillis,
118             long endMillis, int flags) {
119         return mTZUtils.formatDateRange(context, startMillis, endMillis, flags);
120     }
121 
setSharedPreference(Context context, String key, String value)122     static void setSharedPreference(Context context, String key, String value) {
123         SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
124         SharedPreferences.Editor editor = prefs.edit();
125         editor.putString(key, value);
126         editor.apply();
127     }
128 
setDefaultView(Context context, int viewId)129     static void setDefaultView(Context context, int viewId) {
130         String activityString = CalendarApplication.ACTIVITY_NAMES[viewId];
131 
132         SharedPreferences prefs = CalendarPreferenceActivity.getSharedPreferences(context);
133         SharedPreferences.Editor editor = prefs.edit();
134         if (viewId == CalendarApplication.AGENDA_VIEW_ID ||
135                 viewId == CalendarApplication.DAY_VIEW_ID) {
136             // Record the (new) detail start view only for Agenda and Day
137             editor.putString(CalendarPreferenceActivity.KEY_DETAILED_VIEW, activityString);
138         }
139 
140         // Record the (new) start view
141         editor.putString(CalendarPreferenceActivity.KEY_START_VIEW, activityString);
142         editor.apply();
143     }
144 
timeFromIntent(Intent intent)145     public static final Time timeFromIntent(Intent intent) {
146         Time time = new Time();
147         time.set(timeFromIntentInMillis(intent));
148         return time;
149     }
150 
matrixCursorFromCursor(Cursor cursor)151     public static MatrixCursor matrixCursorFromCursor(Cursor cursor) {
152         MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames());
153         int numColumns = cursor.getColumnCount();
154         String data[] = new String[numColumns];
155         cursor.moveToPosition(-1);
156         while (cursor.moveToNext()) {
157             for (int i = 0; i < numColumns; i++) {
158                 data[i] = cursor.getString(i);
159             }
160             newCursor.addRow(data);
161         }
162         return newCursor;
163     }
164 
165     /**
166      * Compares two cursors to see if they contain the same data.
167      *
168      * @return Returns true of the cursors contain the same data and are not null, false
169      * otherwise
170      */
compareCursors(Cursor c1, Cursor c2)171     public static boolean compareCursors(Cursor c1, Cursor c2) {
172         if(c1 == null || c2 == null) {
173             return false;
174         }
175 
176         int numColumns = c1.getColumnCount();
177         if (numColumns != c2.getColumnCount()) {
178             return false;
179         }
180 
181         if (c1.getCount() != c2.getCount()) {
182             return false;
183         }
184 
185         c1.moveToPosition(-1);
186         c2.moveToPosition(-1);
187         while(c1.moveToNext() && c2.moveToNext()) {
188             for(int i = 0; i < numColumns; i++) {
189                 if(!TextUtils.equals(c1.getString(i), c2.getString(i))) {
190                     return false;
191                 }
192             }
193         }
194 
195         return true;
196     }
197 
198     /**
199      * If the given intent specifies a time (in milliseconds since the epoch),
200      * then that time is returned. Otherwise, the current time is returned.
201      */
timeFromIntentInMillis(Intent intent)202     public static final long timeFromIntentInMillis(Intent intent) {
203         // If the time was specified, then use that.  Otherwise, use the current time.
204         Uri data = intent.getData();
205         long millis = intent.getLongExtra(EVENT_BEGIN_TIME, -1);
206         if (millis == -1 && data != null && data.isHierarchical()) {
207             List<String> path = data.getPathSegments();
208             if(path.size() == 2 && path.get(0).equals("time")) {
209                 try {
210                     millis = Long.valueOf(data.getLastPathSegment());
211                 } catch (NumberFormatException e) {
212                     Log.i("Calendar", "timeFromIntentInMillis: Data existed but no valid time " +
213                             "found. Using current time.");
214                 }
215             }
216         }
217         if (millis <= 0) {
218             millis = System.currentTimeMillis();
219         }
220         return millis;
221     }
222 
applyAlphaAnimation(ViewFlipper v)223     public static final void applyAlphaAnimation(ViewFlipper v) {
224         AlphaAnimation in = new AlphaAnimation(0.0f, 1.0f);
225 
226         in.setStartOffset(0);
227         in.setDuration(500);
228 
229         AlphaAnimation out = new AlphaAnimation(1.0f, 0.0f);
230 
231         out.setStartOffset(0);
232         out.setDuration(500);
233 
234         v.setInAnimation(in);
235         v.setOutAnimation(out);
236     }
237 
getColorChip(int color)238     public static Drawable getColorChip(int color) {
239         /*
240          * We want the color chip to have a nice gradient using
241          * the color of the calendar. To do this we use a GradientDrawable.
242          * The color supplied has an alpha of FF so we first do:
243          * color & 0x00FFFFFF
244          * to clear the alpha. Then we add our alpha to it.
245          * We use 3 colors to get a step effect where it starts off very
246          * light and quickly becomes dark and then a slow transition to
247          * be even darker.
248          */
249         color &= CLEAR_ALPHA_MASK;
250         int startColor = color | HIGH_ALPHA;
251         int middleColor = color | MED_ALPHA;
252         int endColor = color | LOW_ALPHA;
253         int[] colors = new int[] {startColor, middleColor, endColor};
254         GradientDrawable d = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
255         d.setCornerRadii(CORNERS);
256         return d;
257     }
258 
259     /**
260      * Formats the given Time object so that it gives the month and year
261      * (for example, "September 2007").
262      *
263      * @param time the time to format
264      * @return the string containing the weekday and the date
265      */
formatMonthYear(Context context, Time time)266     public static String formatMonthYear(Context context, Time time) {
267         return time.format(context.getResources().getString(R.string.month_year));
268     }
269 
270     // TODO: replace this with the correct i18n way to do this
271     public static final String englishNthDay[] = {
272         "", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th",
273         "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th",
274         "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "29th",
275         "30th", "31st"
276     };
277 
formatNth(int nth)278     public static String formatNth(int nth) {
279         return "the " + englishNthDay[nth];
280     }
281 
282     /**
283      * Returns a list joined together by the provided delimiter, for example,
284      * ["a", "b", "c"] could be joined into "a,b,c"
285      *
286      * @param things the things to join together
287      * @param delim the delimiter to use
288      * @return a string contained the things joined together
289      */
join(List<?> things, String delim)290     public static String join(List<?> things, String delim) {
291         StringBuilder builder = new StringBuilder();
292         boolean first = true;
293         for (Object thing : things) {
294             if (first) {
295                 first = false;
296             } else {
297                 builder.append(delim);
298             }
299             builder.append(thing.toString());
300         }
301         return builder.toString();
302     }
303 
304     /**
305      * Sets the time to the beginning of the day (midnight) by clearing the
306      * hour, minute, and second fields.
307      */
setTimeToStartOfDay(Time time)308     static void setTimeToStartOfDay(Time time) {
309         time.second = 0;
310         time.minute = 0;
311         time.hour = 0;
312     }
313 
314     /**
315      * Get first day of week as android.text.format.Time constant.
316      * @return the first day of week in android.text.format.Time
317      */
getFirstDayOfWeek()318     public static int getFirstDayOfWeek() {
319         int startDay = Calendar.getInstance().getFirstDayOfWeek();
320         if (startDay == Calendar.SATURDAY) {
321             return Time.SATURDAY;
322         } else if (startDay == Calendar.MONDAY) {
323             return Time.MONDAY;
324         } else {
325             return Time.SUNDAY;
326         }
327     }
328 
329     /**
330      * Determine whether the column position is Saturday or not.
331      * @param column the column position
332      * @param firstDayOfWeek the first day of week in android.text.format.Time
333      * @return true if the column is Saturday position
334      */
isSaturday(int column, int firstDayOfWeek)335     public static boolean isSaturday(int column, int firstDayOfWeek) {
336         return (firstDayOfWeek == Time.SUNDAY && column == 6)
337             || (firstDayOfWeek == Time.MONDAY && column == 5)
338             || (firstDayOfWeek == Time.SATURDAY && column == 0);
339     }
340 
341     /**
342      * Determine whether the column position is Sunday or not.
343      * @param column the column position
344      * @param firstDayOfWeek the first day of week in android.text.format.Time
345      * @return true if the column is Sunday position
346      */
isSunday(int column, int firstDayOfWeek)347     public static boolean isSunday(int column, int firstDayOfWeek) {
348         return (firstDayOfWeek == Time.SUNDAY && column == 0)
349             || (firstDayOfWeek == Time.MONDAY && column == 6)
350             || (firstDayOfWeek == Time.SATURDAY && column == 1);
351     }
352 
353     /**
354      * Scan through a cursor of calendars and check if names are duplicated.
355      *
356      * This travels a cursor containing calendar display names and fills in the provided map with
357      * whether or not each name is repeated.
358      * @param isDuplicateName The map to put the duplicate check results in.
359      * @param cursor The query of calendars to check
360      * @param nameIndex The column of the query that contains the display name
361      */
checkForDuplicateNames(Map<String, Boolean> isDuplicateName, Cursor cursor, int nameIndex)362     public static void checkForDuplicateNames(Map<String, Boolean> isDuplicateName, Cursor cursor,
363             int nameIndex) {
364         isDuplicateName.clear();
365         cursor.moveToPosition(-1);
366         while (cursor.moveToNext()) {
367             String displayName = cursor.getString(nameIndex);
368             // Set it to true if we've seen this name before, false otherwise
369             if (displayName != null) {
370                 isDuplicateName.put(displayName, isDuplicateName.containsKey(displayName));
371             }
372         }
373     }
374 }
375