Home | History | Annotate | Download | only in calendar
      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 
     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 
     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      */
     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      */
    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      */
    117     public static String formatDateRange(Context context, long startMillis,
    118             long endMillis, int flags) {
    119         return mTZUtils.formatDateRange(context, startMillis, endMillis, flags);
    120     }
    121 
    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 
    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 
    145     public static final Time timeFromIntent(Intent intent) {
    146         Time time = new Time();
    147         time.set(timeFromIntentInMillis(intent));
    148         return time;
    149     }
    150 
    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      */
    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      */
    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 
    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 
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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