Merge "Modify the hours of operation display text for multiple intervals." into ub-contactsdialer-a-dev
diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml
index 54d68c9..b30ca65 100644
--- a/InCallUI/res/values/strings.xml
+++ b/InCallUI/res/values/strings.xml
@@ -487,6 +487,14 @@
          The string is used to build a list of opening hours.
          [CHAR LIMIT=NONE] -->
     <string name="opening_hours"><xliff:g id="earlier_times">%1$s</xliff:g>, <xliff:g id="later_time">%2$s</xliff:g></string>
+    <!-- Used to express when a location will open the next day. [CHAR LIMIT=NONE] -->
+    <string name="opens_tomorrow_at">Opens tomorrow at <xliff:g id="open_time">%s</xliff:g></string>
+    <!-- Used to express the next time at which a location will be open today. [CHAR LIMIT=NONE] -->
+    <string name="opens_today_at">Opens today at <xliff:g id="open_time">%s</xliff:g></string>
+    <!-- Used to express the next time at which a location will close today. [CHAR LIMIT=NONE] -->
+    <string name="closes_today_at">Closes at <xliff:g id="close_time">%s</xliff:g></string>
+    <!-- Used to express the next time at which a location closed today if it is already closed. [CHAR LIMIT=NONE] -->
+    <string name="closed_today_at">Closed today at <xliff:g id="close_time">%s</xliff:g></string>
     <!-- Displayed when a place is open. -->
     <string name="open_now">Open now</string>
     <!-- Displayed when a place is closed. -->
diff --git a/InCallUI/src/com/android/incallui/InCallContactInteractions.java b/InCallUI/src/com/android/incallui/InCallContactInteractions.java
index 275243e..6fade9b 100644
--- a/InCallUI/src/com/android/incallui/InCallContactInteractions.java
+++ b/InCallUI/src/com/android/incallui/InCallContactInteractions.java
@@ -142,33 +142,82 @@
         BusinessContextInfo hoursInfo = new BusinessContextInfo();
         hoursInfo.iconId = R.drawable.ic_schedule_white_24dp;
 
-        boolean isOpen = false;
+        boolean isOpenNow = false;
+        // This variable records which interval the current time is after. 0 denotes none of the
+        // intervals, 1 after the first interval, etc.
+        int afterInterval = 0;
+        // This variable records counts the number of time intervals in today's opening hours.
+        int todaysIntervalCount = 0;
         for (Pair<Calendar, Calendar> hours : openingHours) {
             if (hours.first.compareTo(currentTime) <= 0
                     && currentTime.compareTo(hours.second) < 0) {
                 // If the current time is on or after the opening time and strictly before the
                 // closing time, then this business is open.
-                isOpen = true;
+                isOpenNow = true;
             }
 
-            String openTimeSpan = mContext.getString(R.string.open_time_span,
-                    DateFormat.getTimeFormat(mContext).format(hours.first.getTime()),
-                    DateFormat.getTimeFormat(mContext).format(hours.second.getTime()));
+            if (currentTime.get(Calendar.DAY_OF_YEAR) == hours.first.get(Calendar.DAY_OF_YEAR)) {
+                todaysIntervalCount += 1;
+            }
 
-            if (TextUtils.isEmpty(hoursInfo.detail)) {
-                hoursInfo.detail = openTimeSpan;
-            } else {
-                hoursInfo.detail = mContext.getString(R.string.opening_hours, hoursInfo.detail,
-                        openTimeSpan);
+            if (currentTime.compareTo(hours.second) > 0) {
+                // This assumes that the list of intervals is sorted by time.
+                afterInterval += 1;
             }
         }
 
-        hoursInfo.heading = isOpen ? mContext.getString(R.string.open_now)
+        hoursInfo.heading = isOpenNow ? mContext.getString(R.string.open_now)
                 : mContext.getString(R.string.closed_now);
 
+        /*
+         * The following logic determines what to display in various cases for hours of operation.
+         *
+         * - Display all intervals if open now and number of intervals is <=2.
+         * - Display next closing time if open now and number of intervals is >2.
+         * - Display next opening time if currently closed but opens later today.
+         * - Display last time it closed today if closed now and tomorrow's hours are unknown.
+         * - Display tomorrow's first open time if closed today and tomorrow's hours are known.
+         */
+        if (isOpenNow) {
+            if (todaysIntervalCount == 1) {
+                hoursInfo.detail = getTimeSpanStringForHours(openingHours.get(0));
+            } else if (todaysIntervalCount == 2) {
+                hoursInfo.detail = mContext.getString(R.string.opening_hours,
+                        getTimeSpanStringForHours(openingHours.get(0)),
+                        getTimeSpanStringForHours(openingHours.get(1)));
+            } else {
+                hoursInfo.detail = mContext.getString(R.string.closes_today_at,
+                        getFormattedTimeForCalendar(openingHours.get(afterInterval).second));
+            }
+        } else {
+            // Currently closed
+            final int lastIntervalToday = todaysIntervalCount - 1;
+            if (currentTime.before(openingHours.get(lastIntervalToday).first)) {
+                hoursInfo.detail = mContext.getString(R.string.opens_today_at,
+                        getFormattedTimeForCalendar(openingHours.get(afterInterval).first));
+            } else if (todaysIntervalCount < openingHours.size()){
+                // Assuming all intervals after today's intervals are exhausted are tomorrow's.
+                hoursInfo.detail = mContext.getString(R.string.opens_tomorrow_at,
+                        getFormattedTimeForCalendar(openingHours.get(todaysIntervalCount).first));
+            } else {
+                hoursInfo.detail = mContext.getString(R.string.closed_today_at,
+                        getFormattedTimeForCalendar(openingHours.get(lastIntervalToday).second));
+            }
+        }
+
         return hoursInfo;
     }
 
+    String getFormattedTimeForCalendar(Calendar calendar) {
+        return DateFormat.getTimeFormat(mContext).format(calendar.getTime());
+    }
+
+    String getTimeSpanStringForHours(Pair<Calendar, Calendar> hours) {
+        return mContext.getString(R.string.open_time_span,
+                getFormattedTimeForCalendar(hours.first),
+                getFormattedTimeForCalendar(hours.second));
+    }
+
     /**
      * Construct a BusinessContextInfo object with the location information of the business.
      * The format is:
diff --git a/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java b/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java
index 0d03848..1c2e9de 100644
--- a/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java
+++ b/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java
@@ -25,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -137,10 +138,10 @@
                 .heading);
     }
 
-    public void testOpeningHours_SingleOpenRange() {
+    public void testOpeningHours_SingleOpenRangeWhileOpen() {
         assertEquals("8:00 AM - 8:00 PM",
                 mInCallContactInteractions.constructHoursInfo(
-                        getTestCalendarWithHour(21),
+                        getTestCalendarWithHour(12),
                         Arrays.asList(
                                 Pair.create(
                                         getTestCalendarWithHour(8),
@@ -148,10 +149,10 @@
                 .detail);
     }
 
-    public void testOpeningHours_TwoOpenRanges() {
+    public void testOpeningHours_TwoOpenRangesWhileOpen() {
         assertEquals("8:00 AM - 10:00 AM, 12:00 PM - 3:00 PM",
                 mInCallContactInteractions.constructHoursInfo(
-                        getTestCalendarWithHour(13),
+                        getTestCalendarWithHour(12),
                         Arrays.asList(
                                 Pair.create(
                                     getTestCalendarWithHour(8),
@@ -162,20 +163,54 @@
                 .detail);
     }
 
-    public void testOpeningHours_MultipleOpenRanges() {
-        assertEquals("8:00 AM - 10:00 AM, 12:00 PM - 3:00 PM, 5:00 PM - 9:00 PM",
+    public void testOpeningHours_AfterClosedNoTomorrow() {
+        assertEquals("Closed today at 8:00 PM",
                 mInCallContactInteractions.constructHoursInfo(
-                        getTestCalendarWithHour(13),
+                        getTestCalendarWithHour(21),
                         Arrays.asList(
                                 Pair.create(
-                                    getTestCalendarWithHour(8),
-                                    getTestCalendarWithHour(10)),
-                                Pair.create(
-                                        getTestCalendarWithHour(12),
-                                        getTestCalendarWithHour(15)),
-                                Pair.create(
-                                        getTestCalendarWithHour(17),
-                                        getTestCalendarWithHour(21))))
+                                        getTestCalendarWithHour(8),
+                                        getTestCalendarWithHour(20))))
+                .detail);
+    }
+
+    public void testMultipleOpenRanges_BeforeOpen() {
+        assertEquals("Opens today at 8:00 AM",
+                mInCallContactInteractions.constructHoursInfo(
+                        getTestCalendarWithHour(7),
+                        getMultipleOpeningHours())
+                .detail);
+    }
+
+    public void testMultipleOpenRanges_DuringFirstRange() {
+        assertEquals("Closes at 10:00 AM",
+                mInCallContactInteractions.constructHoursInfo(
+                        getTestCalendarWithHour(9),
+                        getMultipleOpeningHours())
+                .detail);
+    }
+
+    public void testMultipleOpenRanges_BeforeMiddleRange() {
+        assertEquals("Opens today at 12:00 PM",
+                mInCallContactInteractions.constructHoursInfo(
+                        getTestCalendarWithHour(11),
+                        getMultipleOpeningHours())
+                .detail);
+    }
+
+    public void testMultipleOpeningHours_DuringLastRange() {
+        assertEquals("Closes at 9:00 PM",
+                mInCallContactInteractions.constructHoursInfo(
+                        getTestCalendarWithHour(19),
+                        getMultipleOpeningHours())
+                .detail);
+    }
+
+    public void testMultipleOpeningHours_AfterClose() {
+        assertEquals("Opens tomorrow at 8:00 AM",
+                mInCallContactInteractions.constructHoursInfo(
+                        getTestCalendarWithHour(22),
+                        getMultipleOpeningHours())
                 .detail);
     }
 
@@ -257,4 +292,23 @@
         calendar.add(Calendar.DATE, daysFromToday);
         return calendar;
     }
+
+    private List<Pair<Calendar, Calendar>> getMultipleOpeningHours() {
+        return Arrays.asList(
+                Pair.create(
+                    getTestCalendarWithHour(8),
+                    getTestCalendarWithHour(10)),
+                Pair.create(
+                        getTestCalendarWithHour(12),
+                        getTestCalendarWithHour(15)),
+                Pair.create(
+                        getTestCalendarWithHour(17),
+                        getTestCalendarWithHour(21)),
+                Pair.create(
+                        getTestCalendarWithHourAndDaysFromToday(8, 1),
+                        getTestCalendarWithHourAndDaysFromToday(10, 1)),
+                Pair.create(
+                        getTestCalendarWithHourAndDaysFromToday(12, 1),
+                        getTestCalendarWithHourAndDaysFromToday(8, 1)));
+    }
 }