From 47249fc61a2cd39b44c157a1f8ba481d25e99577 Mon Sep 17 00:00:00 2001 From: Nancy Chen Date: Mon, 9 Nov 2015 13:05:05 -0800 Subject: Account for multiple open times for business contacts. Sometimes businesses will close in the middle of the day and reopen. We want to correctly represent the "open now"/"closed now" text for these breaks. Update tests accordingly. Bug: 25488385 Change-Id: I7ea96b1c037770261389297cb405a5e93d8171e4 --- InCallUI/res/values/strings.xml | 10 +- .../src/com/android/incallui/ContactInfoCache.java | 7 +- .../src/com/android/incallui/ContactUtils.java | 6 +- .../incallui/InCallContactInteractions.java | 94 +++-------- .../incallui/InCallContactInteractionsTest.java | 181 ++++++++++++++++----- 5 files changed, 189 insertions(+), 109 deletions(-) (limited to 'InCallUI') diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml index 2f8ef8a41..54d68c9d2 100644 --- a/InCallUI/res/values/strings.xml +++ b/InCallUI/res/values/strings.xml @@ -479,8 +479,14 @@ %.1f km away %1$s, %2$s - - %1$s - %2$s + + %1$s - %2$s + + %1$s, %2$s Open now diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java index 098f82b81..c5176b1a1 100644 --- a/InCallUI/src/com/android/incallui/ContactInfoCache.java +++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java @@ -49,7 +49,9 @@ import com.android.incalluibind.ObjectFactory; import org.json.JSONException; import org.json.JSONObject; +import java.util.Calendar; import java.util.HashMap; +import java.util.List; import java.util.Set; /** @@ -324,7 +326,8 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete } @Override - public void onContactInteractionsFound(Address address, Pair openingHours) { + public void onContactInteractionsFound(Address address, + List> openingHours) { final ContactCacheEntry entry = mInfoMap.get(mCallId); entry.locationAddress = address; entry.openingHours = openingHours; @@ -621,7 +624,7 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete public Uri lookupUri; // Sent to NotificationMananger public String lookupKey; public Address locationAddress; - public Pair openingHours; + public List> openingHours; public int contactLookupResult = LogState.LOOKUP_NOT_FOUND; @Override diff --git a/InCallUI/src/com/android/incallui/ContactUtils.java b/InCallUI/src/com/android/incallui/ContactUtils.java index dfacade8a..0750af731 100644 --- a/InCallUI/src/com/android/incallui/ContactUtils.java +++ b/InCallUI/src/com/android/incallui/ContactUtils.java @@ -21,6 +21,9 @@ import android.util.Pair; import com.android.incalluibind.ObjectFactory; +import java.util.Calendar; +import java.util.List; + /** * Utility functions to help manipulate contact data. */ @@ -36,7 +39,8 @@ public abstract class ContactUtils { } public interface Listener { - public void onContactInteractionsFound(Address address, Pair openingHours); + public void onContactInteractionsFound(Address address, + List> openingHours); } public abstract boolean retrieveContactInteractionsFromLookupKey(String lookupKey, diff --git a/InCallUI/src/com/android/incallui/InCallContactInteractions.java b/InCallUI/src/com/android/incallui/InCallContactInteractions.java index 21660cbce..275243e4d 100644 --- a/InCallUI/src/com/android/incallui/InCallContactInteractions.java +++ b/InCallUI/src/com/android/incallui/InCallContactInteractions.java @@ -49,7 +49,6 @@ import java.util.Locale; * is a business contact or not and logic for the manipulation of data for the call context. */ public class InCallContactInteractions { - private static final String TAG = InCallContactInteractions.class.getSimpleName(); private Context mContext; private InCallContactInteractionsListAdapter mListAdapter; private boolean mIsBusiness; @@ -95,7 +94,7 @@ public class InCallContactInteractions { } public void setBusinessInfo(Address address, float distance, - Pair openingHours) { + List> openingHours) { mListAdapter.clear(); List info = new ArrayList(); @@ -126,7 +125,7 @@ public class InCallContactInteractions { * @return BusinessContextInfo object with the schedule icon, the heading set to whether the * business is open or not and the details set to the hours of operation. */ - private BusinessContextInfo constructHoursInfo(Pair openingHours) { + private BusinessContextInfo constructHoursInfo(List> openingHours) { return constructHoursInfo(Calendar.getInstance(), openingHours); } @@ -135,26 +134,38 @@ public class InCallContactInteractions { */ @VisibleForTesting BusinessContextInfo constructHoursInfo(Calendar currentTime, - Pair openingHours) { + List> openingHours) { + if (currentTime == null || openingHours == null || openingHours.size() == 0) { + return null; + } + BusinessContextInfo hoursInfo = new BusinessContextInfo(); hoursInfo.iconId = R.drawable.ic_schedule_white_24dp; - // Note: the date of these {@link Date}s are set to January 1, 1970. The object is just - // used as a storage for the time. - Date openingDateTime = getSimpleDateTime(openingHours.first); - Date closingDateTime = getSimpleDateTime(openingHours.second); + boolean isOpen = false; + for (Pair 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; + } - if (openingDateTime == null || closingDateTime == null) { - return null; + String openTimeSpan = mContext.getString(R.string.open_time_span, + DateFormat.getTimeFormat(mContext).format(hours.first.getTime()), + DateFormat.getTimeFormat(mContext).format(hours.second.getTime())); + + if (TextUtils.isEmpty(hoursInfo.detail)) { + hoursInfo.detail = openTimeSpan; + } else { + hoursInfo.detail = mContext.getString(R.string.opening_hours, hoursInfo.detail, + openTimeSpan); + } } - hoursInfo.heading = isOpen(openingDateTime, closingDateTime, currentTime) - ? mContext.getString(R.string.open_now) : mContext.getString(R.string.closed_now); + hoursInfo.heading = isOpen ? mContext.getString(R.string.open_now) + : mContext.getString(R.string.closed_now); - hoursInfo.detail = mContext.getString( - R.string.opening_hours, - DateFormat.getTimeFormat(mContext).format(openingDateTime), - DateFormat.getTimeFormat(mContext).format(closingDateTime)); return hoursInfo; } @@ -203,57 +214,6 @@ public class InCallContactInteractions { return locationInfo; } - /** - * Get a {@link Date} object corresponding to a particular time. - * - * @param time A string containing a time in the format "hhmm". - * @return A {@link Date} object with the time set to the parsed value of the "time" parameter - * and the date set to January 1, 1970. Or {@code null} if the input string is not able to be - * parsed. - */ - private Date getSimpleDateTime(String time) { - try { - return new SimpleDateFormat("hhmm").parse(time); - } catch (ParseException e) { - Log.w(TAG, "Could not parse time string " + time); - } - return null; - } - - /** - * Check whether the current time falls between the opening time and the closing time. - * - * @param openingTime A {@link Date} object with the time set to the opening time and the date - * set to January 1, 1970. - * @param closingTime A {@link Date} object with the time set to the closing time and the date - * set to January 1, 1970. - * @param currentDateTime A {@link Calendar} object with the current date and time. - * @return {@code true} if the current time falls within the opening and closing time bounds and - * {@code false} otherwise. - */ - private boolean isOpen(Date openingTime, Date closingTime, Calendar currentDateTime) { - Calendar openTimeCalendar = Calendar.getInstance(); - openTimeCalendar.setTime(openingTime); - - Calendar closeTimeCalendar = Calendar.getInstance(); - closeTimeCalendar.setTime(closingTime); - - if (openTimeCalendar.compareTo(closeTimeCalendar) >= 0) { - // If the open time is the same or after the close time, add a day to the close time - // calendar. - closeTimeCalendar.add(Calendar.DATE, 1); - } - - // Since the date doesn't actually matter, it's easier to set the current date to the - // opening date rather than change both the calendars for the open time and the close time. - currentDateTime.set( - openTimeCalendar.get(Calendar.YEAR), - openTimeCalendar.get(Calendar.MONTH), - openTimeCalendar.get(Calendar.DATE)); - - return currentDateTime.after(openTimeCalendar) && currentDateTime.before(closeTimeCalendar); - } - /** * Get the appropriate title for the context. * @return The "Business info" title for a business contact and the "Recent messages" title for diff --git a/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java b/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java index 50d0aaf6c..0d03848b6 100644 --- a/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java +++ b/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java @@ -22,9 +22,18 @@ import android.util.Pair; import com.android.incallui.InCallContactInteractions.BusinessContextInfo; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Locale; +/** + * Tests for InCallContactInteractions class methods for formatting info for display. + * + * NOTE: tests assume system settings are set to 12hr time format and US locale. This means that + * the output of InCallContactInteractions methods are compared against strings in 12hr time format + * and US locale address formatting unless otherwise specified. + */ public class InCallContactInteractionsTest extends AndroidTestCase { private InCallContactInteractions mInCallContactInteractions; private static final float TEST_DISTANCE = (float) 1234.56; @@ -34,64 +43,147 @@ public class InCallContactInteractionsTest extends AndroidTestCase { mInCallContactInteractions = new InCallContactInteractions(mContext, true /* isBusiness */); } - public void testIsOpenNow() { - Calendar currentTimeForTest = Calendar.getInstance(); - currentTimeForTest.set(Calendar.HOUR_OF_DAY, 10); - BusinessContextInfo info = + public void testIsOpenNow_NowMatchesOpenTime() { + assertEquals(mContext.getString(R.string.open_now), mInCallContactInteractions.constructHoursInfo( - currentTimeForTest, - Pair.create("0800", "2000")); - assertEquals(mContext.getString(R.string.open_now), info.heading); + getTestCalendarWithHour(8), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(20)))) + .heading); } public void testIsOpenNow_ClosingAfterMidnight() { - Calendar currentTimeForTest = Calendar.getInstance(); - currentTimeForTest.set(Calendar.HOUR_OF_DAY, 10); - BusinessContextInfo info = + assertEquals(mContext.getString(R.string.open_now), mInCallContactInteractions.constructHoursInfo( - currentTimeForTest, - Pair.create("0800", "0100")); - assertEquals(mContext.getString(R.string.open_now), info.heading); + getTestCalendarWithHour(10), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHourAndDaysFromToday(1, 1)))) + .heading); } public void testIsOpenNow_Open24Hours() { - Calendar currentTimeForTest = Calendar.getInstance(); - currentTimeForTest.set(Calendar.HOUR_OF_DAY, 10); - BusinessContextInfo info = + assertEquals(mContext.getString(R.string.open_now), + mInCallContactInteractions.constructHoursInfo( + getTestCalendarWithHour(10), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHourAndDaysFromToday(8, 1)))) + .heading); + } + + public void testIsOpenNow_AfterMiddayBreak() { + assertEquals(mContext.getString(R.string.open_now), mInCallContactInteractions.constructHoursInfo( - currentTimeForTest, - Pair.create("0800", "0800")); - assertEquals(mContext.getString(R.string.open_now), info.heading); + getTestCalendarWithHour(13), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(10)), + Pair.create( + getTestCalendarWithHour(12), + getTestCalendarWithHour(15)))) + .heading); + } + + public void testIsClosedNow_DuringMiddayBreak() { + assertEquals(mContext.getString(R.string.closed_now), + mInCallContactInteractions.constructHoursInfo( + getTestCalendarWithHour(11), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(10)), + Pair.create( + getTestCalendarWithHour(12), + getTestCalendarWithHour(15)))) + .heading); } public void testIsClosedNow_BeforeOpen() { - Calendar currentTimeForTest = Calendar.getInstance(); - currentTimeForTest.set(Calendar.HOUR_OF_DAY, 6); - BusinessContextInfo info = + assertEquals(mContext.getString(R.string.closed_now), mInCallContactInteractions.constructHoursInfo( - currentTimeForTest, - Pair.create("0800", "2000")); - assertEquals(mContext.getString(R.string.closed_now), info.heading); + getTestCalendarWithHour(6), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(20)))) + .heading); + } + + public void testIsClosedNow_NowMatchesClosedTime() { + assertEquals(mContext.getString(R.string.closed_now), + mInCallContactInteractions.constructHoursInfo( + getTestCalendarWithHour(20), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(20)))) + .heading); } public void testIsClosedNow_AfterClosed() { - Calendar currentTimeForTest = Calendar.getInstance(); - currentTimeForTest.set(Calendar.HOUR_OF_DAY, 21); - BusinessContextInfo info = + assertEquals(mContext.getString(R.string.closed_now), mInCallContactInteractions.constructHoursInfo( - currentTimeForTest, - Pair.create("0800", "2000")); - assertEquals(mContext.getString(R.string.closed_now), info.heading); + getTestCalendarWithHour(21), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(20)))) + .heading); + } + + public void testOpeningHours_SingleOpenRange() { + assertEquals("8:00 AM - 8:00 PM", + mInCallContactInteractions.constructHoursInfo( + getTestCalendarWithHour(21), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(20)))) + .detail); + } + + public void testOpeningHours_TwoOpenRanges() { + assertEquals("8:00 AM - 10:00 AM, 12:00 PM - 3:00 PM", + mInCallContactInteractions.constructHoursInfo( + getTestCalendarWithHour(13), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(10)), + Pair.create( + getTestCalendarWithHour(12), + getTestCalendarWithHour(15)))) + .detail); + } + + public void testOpeningHours_MultipleOpenRanges() { + assertEquals("8:00 AM - 10:00 AM, 12:00 PM - 3:00 PM, 5:00 PM - 9:00 PM", + mInCallContactInteractions.constructHoursInfo( + getTestCalendarWithHour(13), + Arrays.asList( + Pair.create( + getTestCalendarWithHour(8), + getTestCalendarWithHour(10)), + Pair.create( + getTestCalendarWithHour(12), + getTestCalendarWithHour(15)), + Pair.create( + getTestCalendarWithHour(17), + getTestCalendarWithHour(21)))) + .detail); } public void testInvalidOpeningHours() { - Calendar currentTimeForTest = Calendar.getInstance(); - currentTimeForTest.set(Calendar.HOUR_OF_DAY, 21); - BusinessContextInfo info = + assertEquals(null, mInCallContactInteractions.constructHoursInfo( - currentTimeForTest, - Pair.create("", "2000")); - assertEquals(null, info); + getTestCalendarWithHour(21), + new ArrayList>())); } public void testLocationInfo_ForUS() { @@ -150,4 +242,19 @@ public class InCallContactInteractionsTest extends AndroidTestCase { address.setLocality("Test locality"); return address; } + + private Calendar getTestCalendarWithHour(int hour) { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + return calendar; + } + + private Calendar getTestCalendarWithHourAndDaysFromToday(int hour, int daysFromToday) { + Calendar calendar = getTestCalendarWithHour(hour); + calendar.add(Calendar.DATE, daysFromToday); + return calendar; + } } -- cgit v1.2.3