Home | History | Annotate | Download | only in mail
      1 /*
      2  * Copyright (C) 2012 Google Inc.
      3  * Licensed to The Android Open Source Project.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 package com.android.mail;
     18 
     19 import android.content.Context;
     20 import android.text.format.DateUtils;
     21 
     22 import java.util.Calendar;
     23 import java.util.Formatter;
     24 
     25 /**
     26  * Convenience class to efficiently make multiple short date strings. Instantiating and reusing
     27  * one of these builders is faster than repeatedly bringing up all the locale stuff.
     28  *
     29  */
     30 public class FormattedDateBuilder {
     31 
     32     private final StringBuilder sb;
     33     private final Formatter dateFormatter;
     34     private final Context mContext;
     35 
     36     public FormattedDateBuilder(Context context) {
     37         mContext = context;
     38         sb = new StringBuilder();
     39         dateFormatter = new Formatter(sb);
     40     }
     41 
     42     /**
     43      * This is used in the conversation list, and headers of collapsed messages in
     44      * threaded conversations.
     45      * Times on today's date will just display time, e.g. 8:15 AM
     46      * Times not today, but within the same calendar year will display absolute date, e.g. Nov 6
     47      * Times not in the same year display a numeric absolute date, e.g. 11/18/12
     48      *
     49      * @param when The time to generate a formatted date for
     50      * @return The formatted date
     51      */
     52     public CharSequence formatShortDateTime(long when) {
     53         if (DateUtils.isToday(when)) {
     54             return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME);
     55         } else if (isCurrentYear(when)) {
     56             return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH);
     57         } else {
     58             return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE);
     59         }
     60     }
     61 
     62     /**
     63      * This is used in regular message headers.
     64      * Times on today's date will just display time, e.g. 8:15 AM
     65      * Times not today, but within two weeks ago will display relative date and time,
     66      * e.g. 6 days ago, 8:15 AM
     67      * Times more than two weeks ago but within the same calendar year will display
     68      * absolute date and time, e.g. Nov 6, 8:15 AM
     69      * Times not in the same year display a numeric absolute date, e.g. 11/18/12
     70      *
     71      * @param when The time to generate a formatted date for
     72      * @return The formatted date
     73      */
     74     public CharSequence formatLongDateTime(long when) {
     75         if (DateUtils.isToday(when)) {
     76             return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME);
     77         } else if (isCurrentYear(when)) {
     78             return getRelativeDateTimeString(mContext, when, DateUtils.DAY_IN_MILLIS,
     79                     2 * DateUtils.WEEK_IN_MILLIS,
     80                     DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH);
     81         } else {
     82             return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE);
     83         }
     84     }
     85 
     86     /**
     87      * This is used in expanded details headers.
     88      * Displays full date and time e.g. Tue, Nov 18, 2012, 8:15 AM, or
     89      * Yesterday, Nov 18, 2012, 8:15 AM
     90      *
     91      * @param when The time to generate a formatted date for
     92      * @return The formatted date
     93      */
     94     public CharSequence formatFullDateTime(long when) {
     95         sb.setLength(0);
     96         DateUtils.formatDateRange(mContext, dateFormatter, when, when,
     97                 DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
     98                 DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL);
     99         return sb.toString();
    100     }
    101 
    102     /**
    103      * This is used for displaying dates when printing.
    104      * Displays the full date, e.g. Tue, Nov 18, 2012 at 8:15 PM
    105      *
    106      * @param when The time to generate a formatted date for
    107      * @return The formatted date
    108      */
    109     public String formatDateTimeForPrinting(long when) {
    110         return mContext.getString(R.string.date_message_received_print,
    111                 formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY |
    112                         DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL),
    113                         formatDateTime(when, DateUtils.FORMAT_SHOW_TIME));
    114     }
    115 
    116     private boolean isCurrentYear(long when) {
    117         final Calendar nowCal = Calendar.getInstance();
    118         final Calendar whenCal = Calendar.getInstance();
    119         whenCal.setTimeInMillis(when);
    120         return (nowCal.get(Calendar.YEAR) == whenCal.get(Calendar.YEAR));
    121     }
    122 
    123     private CharSequence formatDateTime(long when, int flags) {
    124         sb.setLength(0);
    125         DateUtils.formatDateRange(mContext, dateFormatter, when, when, flags);
    126         return sb.toString();
    127     }
    128 
    129     /**
    130      * A port of
    131      * {@link DateUtils#getRelativeDateTimeString(android.content.Context, long, long, long, int)}
    132      * that does not include the time in strings like "2 days ago".
    133      */
    134     private static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
    135             long transitionResolution, int flags) {
    136         final long now = System.currentTimeMillis();
    137         final long duration = Math.abs(now - time);
    138 
    139         // getRelativeTimeSpanString() doesn't correctly format relative dates
    140         // above a week or exact dates below a day, so clamp
    141         // transitionResolution as needed.
    142         if (transitionResolution > DateUtils.WEEK_IN_MILLIS) {
    143             transitionResolution = DateUtils.WEEK_IN_MILLIS;
    144         } else if (transitionResolution < DateUtils.DAY_IN_MILLIS) {
    145             transitionResolution = DateUtils.DAY_IN_MILLIS;
    146         }
    147 
    148         if (duration < transitionResolution) {
    149             return DateUtils.getRelativeTimeSpanString(time, now, minResolution, flags);
    150         } else {
    151             return DateUtils.getRelativeTimeSpanString(c, time, false);
    152         }
    153     }
    154 }
    155