Home | History | Annotate | Download | only in interactions
      1 package com.android.contacts.interactions;
      2 
      3 import com.android.contacts.R;
      4 
      5 import android.content.Context;
      6 import android.content.res.Resources;
      7 import android.text.format.DateFormat;
      8 import android.text.format.DateUtils;
      9 import android.text.format.Time;
     10 
     11 import java.util.Formatter;
     12 import java.util.Locale;
     13 
     14 /**
     15  * The following methods were pulled from
     16  * {@link com.android.calendar.EventInfoFragment.updateEvent(View view)}
     17  * TODO: Move this to frameworks/opt
     18  */
     19 public class CalendarInteractionUtils {
     20 
     21     // Using int constants as a return value instead of an enum to minimize resources.
     22     private static final int TODAY = 1;
     23     private static final int TOMORROW = 2;
     24     private static final int NONE = 0;
     25 
     26     /**
     27      * Returns a string description of the specified time interval.
     28      */
     29     public static String getDisplayedDatetime(long startMillis, long endMillis, long currentMillis,
     30             String localTimezone, boolean allDay, Context context) {
     31         // Configure date/time formatting.
     32         int flagsDate = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY;
     33         int flagsTime = DateUtils.FORMAT_SHOW_TIME;
     34         if (DateFormat.is24HourFormat(context)) {
     35             flagsTime |= DateUtils.FORMAT_24HOUR;
     36         }
     37 
     38         Time currentTime = new Time(localTimezone);
     39         currentTime.set(currentMillis);
     40         Resources resources = context.getResources();
     41         String datetimeString = null;
     42         if (allDay) {
     43             // All day events require special timezone adjustment.
     44             long localStartMillis = convertAlldayUtcToLocal(null, startMillis, localTimezone);
     45             long localEndMillis = convertAlldayUtcToLocal(null, endMillis, localTimezone);
     46             if (singleDayEvent(localStartMillis, localEndMillis, currentTime.gmtoff)) {
     47                 // If possible, use "Today" or "Tomorrow" instead of a full date string.
     48                 int todayOrTomorrow = isTodayOrTomorrow(context.getResources(),
     49                         localStartMillis, currentMillis, currentTime.gmtoff);
     50                 if (TODAY == todayOrTomorrow) {
     51                     datetimeString = resources.getString(R.string.today);
     52                 } else if (TOMORROW == todayOrTomorrow) {
     53                     datetimeString = resources.getString(R.string.tomorrow);
     54                 }
     55             }
     56             if (datetimeString == null) {
     57                 // For multi-day allday events or single-day all-day events that are not
     58                 // today or tomorrow, use framework formatter.
     59                 Formatter f = new Formatter(new StringBuilder(50), Locale.getDefault());
     60                 datetimeString = DateUtils.formatDateRange(context, f, startMillis,
     61                         endMillis, flagsDate, Time.TIMEZONE_UTC).toString();
     62             }
     63         } else {
     64             if (singleDayEvent(startMillis, endMillis, currentTime.gmtoff)) {
     65                 // Format the time.
     66                 String timeString = formatDateRange(context, startMillis, endMillis,
     67                         flagsTime);
     68 
     69                 // If possible, use "Today" or "Tomorrow" instead of a full date string.
     70                 int todayOrTomorrow = isTodayOrTomorrow(context.getResources(), startMillis,
     71                         currentMillis, currentTime.gmtoff);
     72                 if (TODAY == todayOrTomorrow) {
     73                     // Example: "Today at 1:00pm - 2:00 pm"
     74                     datetimeString = resources.getString(R.string.today_at_time_fmt,
     75                             timeString);
     76                 } else if (TOMORROW == todayOrTomorrow) {
     77                     // Example: "Tomorrow at 1:00pm - 2:00 pm"
     78                     datetimeString = resources.getString(R.string.tomorrow_at_time_fmt,
     79                             timeString);
     80                 } else {
     81                     // Format the full date. Example: "Thursday, April 12, 1:00pm - 2:00pm"
     82                     String dateString = formatDateRange(context, startMillis, endMillis,
     83                             flagsDate);
     84                     datetimeString = resources.getString(R.string.date_time_fmt, dateString,
     85                             timeString);
     86                 }
     87             } else {
     88                 // For multiday events, shorten day/month names.
     89                 // Example format: "Fri Apr 6, 5:00pm - Sun, Apr 8, 6:00pm"
     90                 int flagsDatetime = flagsDate | flagsTime | DateUtils.FORMAT_ABBREV_MONTH |
     91                         DateUtils.FORMAT_ABBREV_WEEKDAY;
     92                 datetimeString = formatDateRange(context, startMillis, endMillis,
     93                         flagsDatetime);
     94             }
     95         }
     96         return datetimeString;
     97     }
     98 
     99     /**
    100      * Convert given UTC time into current local time. This assumes it is for an
    101      * allday event and will adjust the time to be on a midnight boundary.
    102      *
    103      * @param recycle Time object to recycle, otherwise null.
    104      * @param utcTime Time to convert, in UTC.
    105      * @param tz The time zone to convert this time to.
    106      */
    107     private static long convertAlldayUtcToLocal(Time recycle, long utcTime, String tz) {
    108         if (recycle == null) {
    109             recycle = new Time();
    110         }
    111         recycle.timezone = Time.TIMEZONE_UTC;
    112         recycle.set(utcTime);
    113         recycle.timezone = tz;
    114         return recycle.normalize(true);
    115     }
    116 
    117     public static long convertAlldayLocalToUTC(Time recycle, long localTime, String tz) {
    118         if (recycle == null) {
    119             recycle = new Time();
    120         }
    121         recycle.timezone = tz;
    122         recycle.set(localTime);
    123         recycle.timezone = Time.TIMEZONE_UTC;
    124         return recycle.normalize(true);
    125     }
    126 
    127     /**
    128      * Returns whether the specified time interval is in a single day.
    129      */
    130     private static boolean singleDayEvent(long startMillis, long endMillis, long localGmtOffset) {
    131         if (startMillis == endMillis) {
    132             return true;
    133         }
    134 
    135         // An event ending at midnight should still be a single-day event, so check
    136         // time end-1.
    137         int startDay = Time.getJulianDay(startMillis, localGmtOffset);
    138         int endDay = Time.getJulianDay(endMillis - 1, localGmtOffset);
    139         return startDay == endDay;
    140     }
    141 
    142     /**
    143      * Returns TODAY or TOMORROW if applicable.  Otherwise returns NONE.
    144      */
    145     private static int isTodayOrTomorrow(Resources r, long dayMillis,
    146             long currentMillis, long localGmtOffset) {
    147         int startDay = Time.getJulianDay(dayMillis, localGmtOffset);
    148         int currentDay = Time.getJulianDay(currentMillis, localGmtOffset);
    149 
    150         int days = startDay - currentDay;
    151         if (days == 1) {
    152             return TOMORROW;
    153         } else if (days == 0) {
    154             return TODAY;
    155         } else {
    156             return NONE;
    157         }
    158     }
    159 
    160     /**
    161      * Formats a date or a time range according to the local conventions.
    162      *
    163      * This formats a date/time range using Calendar's time zone and the
    164      * local conventions for the region of the device.
    165      *
    166      * If the {@link DateUtils#FORMAT_UTC} flag is used it will pass in
    167      * the UTC time zone instead.
    168      *
    169      * @param context the context is required only if the time is shown
    170      * @param startMillis the start time in UTC milliseconds
    171      * @param endMillis the end time in UTC milliseconds
    172      * @param flags a bit mask of options See
    173      * {@link DateUtils#formatDateRange(Context, Formatter, long, long, int, String) formatDateRange}
    174      * @return a string containing the formatted date/time range.
    175      */
    176     private static String formatDateRange(Context context, long startMillis,
    177             long endMillis, int flags) {
    178         String date;
    179         String tz;
    180         if ((flags & DateUtils.FORMAT_UTC) != 0) {
    181             tz = Time.TIMEZONE_UTC;
    182         } else {
    183             tz = Time.getCurrentTimezone();
    184         }
    185         StringBuilder sb = new StringBuilder(50);
    186         Formatter f = new Formatter(sb, Locale.getDefault());
    187         sb.setLength(0);
    188         date = DateUtils.formatDateRange(context, f, startMillis, endMillis, flags,
    189                 tz).toString();
    190         return date;
    191     }
    192 }
    193