summaryrefslogtreecommitdiff
path: root/InCallUI
diff options
context:
space:
mode:
authorNancy Chen <nancychen@google.com>2015-10-20 17:12:01 -0700
committerNancy Chen <nancychen@google.com>2015-10-21 18:03:37 -0700
commitd2fda4ab69205fc672c02141f9b62c1958f73ace (patch)
treeff3cdd32f5bb937cb04f69fa12f146594ea04d31 /InCallUI
parent3867a0ac286d0c9cc457b81e9db5d36019e786e4 (diff)
Add hours of operation info to incall business context.
Display hours of operation information if it is available. If hours of operation are available, also determine whether it is currently open or closed. Display in the InCallUI when making a business call. Also add tests to make sure that the business context object is constructed correctly. Bug: 23351559 Change-Id: Ic2846e54e15ade37ccf0b916651cc3388da3cc23
Diffstat (limited to 'InCallUI')
-rw-r--r--InCallUI/res/drawable-hdpi/ic_schedule_white_24dp.pngbin0 -> 575 bytes
-rw-r--r--InCallUI/res/drawable-mdpi/ic_schedule_white_24dp.pngbin0 -> 377 bytes
-rw-r--r--InCallUI/res/drawable-xhdpi/ic_schedule_white_24dp.pngbin0 -> 737 bytes
-rw-r--r--InCallUI/res/drawable-xxhdpi/ic_schedule_white_24dp.pngbin0 -> 1107 bytes
-rw-r--r--InCallUI/res/drawable-xxxhdpi/ic_schedule_white_24dp.pngbin0 -> 1478 bytes
-rw-r--r--InCallUI/res/values/strings.xml6
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java7
-rw-r--r--InCallUI/src/com/android/incallui/ContactInfoCache.java15
-rw-r--r--InCallUI/src/com/android/incallui/ContactUtils.java6
-rw-r--r--InCallUI/src/com/android/incallui/InCallContactInteractions.java127
-rw-r--r--InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java73
11 files changed, 208 insertions, 26 deletions
diff --git a/InCallUI/res/drawable-hdpi/ic_schedule_white_24dp.png b/InCallUI/res/drawable-hdpi/ic_schedule_white_24dp.png
new file mode 100644
index 000000000..f3581d104
--- /dev/null
+++ b/InCallUI/res/drawable-hdpi/ic_schedule_white_24dp.png
Binary files differ
diff --git a/InCallUI/res/drawable-mdpi/ic_schedule_white_24dp.png b/InCallUI/res/drawable-mdpi/ic_schedule_white_24dp.png
new file mode 100644
index 000000000..501ee842e
--- /dev/null
+++ b/InCallUI/res/drawable-mdpi/ic_schedule_white_24dp.png
Binary files differ
diff --git a/InCallUI/res/drawable-xhdpi/ic_schedule_white_24dp.png b/InCallUI/res/drawable-xhdpi/ic_schedule_white_24dp.png
new file mode 100644
index 000000000..2e27936a4
--- /dev/null
+++ b/InCallUI/res/drawable-xhdpi/ic_schedule_white_24dp.png
Binary files differ
diff --git a/InCallUI/res/drawable-xxhdpi/ic_schedule_white_24dp.png b/InCallUI/res/drawable-xxhdpi/ic_schedule_white_24dp.png
new file mode 100644
index 000000000..bfc72736a
--- /dev/null
+++ b/InCallUI/res/drawable-xxhdpi/ic_schedule_white_24dp.png
Binary files differ
diff --git a/InCallUI/res/drawable-xxxhdpi/ic_schedule_white_24dp.png b/InCallUI/res/drawable-xxxhdpi/ic_schedule_white_24dp.png
new file mode 100644
index 000000000..b94f4dfa1
--- /dev/null
+++ b/InCallUI/res/drawable-xxxhdpi/ic_schedule_white_24dp.png
Binary files differ
diff --git a/InCallUI/res/values/strings.xml b/InCallUI/res/values/strings.xml
index 7a90953f4..20a724cd6 100644
--- a/InCallUI/res/values/strings.xml
+++ b/InCallUI/res/values/strings.xml
@@ -477,4 +477,10 @@
<string name="distance_imperial_away"><xliff:g id="distance">%.1f</xliff:g> mi away</string>
<!-- Used to inform the user how far away a location is in kilometers. [CHAR LIMIT=NONE] -->
<string name="distance_metric_away"><xliff:g id="distance">%.1f</xliff:g> km away</string>
+ <!-- Used to indicate the opening hours for a location as a time span. [CHAR LIMIT=NONE] -->
+ <string name="opening_hours"><xliff:g id="open_time">%s</xliff:g> - <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. -->
+ <string name="closed_now">Closed now</string>
</resources>
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index aa022f448..e7d6f0c3e 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -595,8 +595,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
private void updateContactInteractions() {
if (mPrimary != null && mPrimaryContactInfo != null
- && mPrimaryContactInfo.locationAddress != null) {
-
+ && (mPrimaryContactInfo.locationAddress != null
+ || mPrimaryContactInfo.openingHours != null)) {
// TODO: This is hardcoded to "isBusiness" because functionality to differentiate
// between business and personal has not yet been added.
if (setInCallContactInteractionsType(true /* isBusiness */)) {
@@ -606,7 +606,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
mInCallContactInteractions.setBusinessInfo(
mPrimaryContactInfo.locationAddress,
- mDistanceHelper.calculateDistance(mPrimaryContactInfo.locationAddress));
+ mDistanceHelper.calculateDistance(mPrimaryContactInfo.locationAddress),
+ mPrimaryContactInfo.openingHours);
getUi().setContactContextContent(mInCallContactInteractions.getListAdapter());
getUi().showContactContext(mPrimary.getState() != State.INCOMING);
}
diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java
index 0e6a3d4e0..e3457d5cb 100644
--- a/InCallUI/src/com/android/incallui/ContactInfoCache.java
+++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java
@@ -30,6 +30,7 @@ import android.provider.ContactsContract.DisplayNameSources;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telecom.TelecomManager;
import android.text.TextUtils;
+import android.util.Pair;
import com.android.contacts.common.util.PhoneNumberHelper;
import com.android.dialer.calllog.ContactInfo;
@@ -299,10 +300,11 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete
entry.photo = mContext.getResources().getDrawable(R.drawable.img_business);
}
- String address = null;
+ boolean hasContactInteractions = false;
if (mContactUtils != null) {
- // This method will callback "onAddressDetailsFound".
- address = mContactUtils.getAddressFromLookupKey(info.getLookupKey(), this);
+ // This method will callback "onContactInteractionsFound".
+ hasContactInteractions = mContactUtils.retrieveContactInteractionsFromLookupKey(
+ info.getLookupKey(), this);
}
// Add the contact info to the cache.
@@ -310,7 +312,7 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete
sendInfoNotifications(mCallId, entry);
// If there is no image then we should not expect another callback.
- if (info.getImageUrl() == null && address == null) {
+ if (info.getImageUrl() == null && !hasContactInteractions) {
// We're done, so clear callbacks
clearCallbacks(mCallId);
}
@@ -322,9 +324,10 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete
}
@Override
- public void onAddressDetailsFound(Address address) {
+ public void onContactInteractionsFound(Address address, Pair<String, String> openingHours) {
final ContactCacheEntry entry = mInfoMap.get(mCallId);
entry.locationAddress = address;
+ entry.openingHours = openingHours;
sendContactInteractionsNotifications(mCallId, entry);
clearCallbacks(mCallId);
}
@@ -614,6 +617,7 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete
public Uri lookupUri; // Sent to NotificationMananger
public String lookupKey;
public Address locationAddress;
+ public Pair<String, String> openingHours;
public int contactLookupResult = LogState.LOOKUP_NOT_FOUND;
@Override
@@ -628,6 +632,7 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete
.add("contactUri", contactUri)
.add("displayPhotoUri", displayPhotoUri)
.add("locationAddress", locationAddress)
+ .add("openingHours", openingHours)
.add("contactLookupResult", contactLookupResult)
.toString();
}
diff --git a/InCallUI/src/com/android/incallui/ContactUtils.java b/InCallUI/src/com/android/incallui/ContactUtils.java
index eac748494..dfacade8a 100644
--- a/InCallUI/src/com/android/incallui/ContactUtils.java
+++ b/InCallUI/src/com/android/incallui/ContactUtils.java
@@ -17,6 +17,7 @@ package com.android.incallui;
import android.content.Context;
import android.location.Address;
+import android.util.Pair;
import com.android.incalluibind.ObjectFactory;
@@ -35,8 +36,9 @@ public abstract class ContactUtils {
}
public interface Listener {
- public void onAddressDetailsFound(Address address);
+ public void onContactInteractionsFound(Address address, Pair<String, String> openingHours);
}
- public abstract String getAddressFromLookupKey(String lookupKey, Listener listener);
+ public abstract boolean retrieveContactInteractionsFromLookupKey(String lookupKey,
+ Listener listener);
}
diff --git a/InCallUI/src/com/android/incallui/InCallContactInteractions.java b/InCallUI/src/com/android/incallui/InCallContactInteractions.java
index 04caecc13..6d1c9fc8f 100644
--- a/InCallUI/src/com/android/incallui/InCallContactInteractions.java
+++ b/InCallUI/src/com/android/incallui/InCallContactInteractions.java
@@ -16,9 +16,13 @@
package com.android.incallui;
+import com.google.common.annotations.VisibleForTesting;
+
import android.content.Context;
import android.location.Address;
import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -29,7 +33,11 @@ import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -41,6 +49,7 @@ 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;
@@ -77,11 +86,6 @@ public class InCallContactInteractions {
return false;
}
- public void setBusinessInfo(Address address, float distance) {
- mListAdapter.clear();
- mListAdapter.addAll(constructBusinessContextInfo(address, distance));
- }
-
public View getBusinessListHeaderView() {
if (mBusinessHeaderView == null) {
mBusinessHeaderView = mInflater.inflate(
@@ -90,30 +94,121 @@ public class InCallContactInteractions {
return mBusinessHeaderView;
}
- private List<ContactContextInfo> constructBusinessContextInfo(Address address, float distance) {
+ public void setBusinessInfo(Address address, float distance,
+ Pair<String, String> openingHours) {
+ mListAdapter.clear();
List<ContactContextInfo> info = new ArrayList<ContactContextInfo>();
- //TODO: hours of operation information
+ // Hours of operation
+ if (openingHours != null) {
+ BusinessContextInfo hoursInfo = constructHoursInfo(openingHours);
+ if (hoursInfo != null) {
+ info.add(hoursInfo);
+ }
+ }
// Location information
- BusinessContextInfo distanceInfo = new BusinessContextInfo();
- distanceInfo.iconId = R.drawable.ic_location_on_white_24dp;
+ if (address != null) {
+ BusinessContextInfo locationInfo = constructLocationInfo(address, distance);
+ info.add(locationInfo);
+ }
+
+ mListAdapter.addAll(info);
+ }
+
+ /**
+ * Construct a BusinessContextInfo object containing hours of operation information.
+ * The format is:
+ * [Open now/Closed now]
+ * [Hours]
+ *
+ * @param openingHours
+ * @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<String, String> openingHours) {
+ return constructHoursInfoByTime(Calendar.getInstance(), openingHours);
+ }
+
+ /**
+ * Pass in arbitrary current calendar time.
+ */
+ @VisibleForTesting
+ BusinessContextInfo constructHoursInfoByTime(
+ Calendar currentTime, Pair<String, String> openingHours) {
+ BusinessContextInfo hoursInfo = new BusinessContextInfo();
+ hoursInfo.iconId = R.drawable.ic_schedule_white_24dp;
+
+ Calendar openTime = getCalendarFromTime(currentTime, openingHours.first);
+ Calendar closeTime = getCalendarFromTime(currentTime, openingHours.second);
+
+ if (openTime == null || closeTime == null) {
+ return null;
+ }
+
+ if (currentTime.after(openTime) && currentTime.before(closeTime)) {
+ hoursInfo.heading = mContext.getString(R.string.open_now);
+ } else {
+ hoursInfo.heading = mContext.getString(R.string.closed_now);
+ }
+
+ hoursInfo.detail = mContext.getString(
+ R.string.opening_hours,
+ DateFormat.getTimeFormat(mContext).format(openTime.getTime()),
+ DateFormat.getTimeFormat(mContext).format(closeTime.getTime()));
+ return hoursInfo;
+ }
+
+ /**
+ * Construct a BusinessContextInfo object with the location information of the business.
+ * The format is:
+ * [Straight line distance in miles or kilometers]
+ * [Address without state/country/etc.]
+ *
+ * @param address An Address object containing address details of the business
+ * @param distance The distance to the location in meters
+ * @return A BusinessContextInfo object with the location icon, the heading as the distance to
+ * the business and the details containing the address.
+ */
+ @VisibleForTesting
+ BusinessContextInfo constructLocationInfo(Address address, float distance) {
+ if (address == null) {
+ return null;
+ }
+
+ BusinessContextInfo locationInfo = new BusinessContextInfo();
+ locationInfo.iconId = R.drawable.ic_location_on_white_24dp;
if (distance != DistanceHelper.DISTANCE_NOT_FOUND) {
//TODO: add a setting to allow the user to select "KM" or "MI" as their distance units.
if (Locale.US.equals(Locale.getDefault())) {
- distanceInfo.heading = mContext.getString(R.string.distance_imperial_away,
+ locationInfo.heading = mContext.getString(R.string.distance_imperial_away,
distance * DistanceHelper.MILES_PER_METER);
} else {
- distanceInfo.heading = mContext.getString(R.string.distance_metric_away,
+ locationInfo.heading = mContext.getString(R.string.distance_metric_away,
distance * DistanceHelper.KILOMETERS_PER_METER);
}
}
- if (address != null) {
- distanceInfo.detail = address.getAddressLine(0);
- }
- info.add(distanceInfo);
+ locationInfo.detail = address.getAddressLine(0);
+ return locationInfo;
+ }
- return info;
+ /**
+ * Get a calendar object set to the current calendar date and the time set to the "hhmm" string
+ * passed in.
+ */
+ private Calendar getCalendarFromTime(Calendar currentTime, String time) {
+ try {
+ Calendar newCalendar = Calendar.getInstance();
+ newCalendar.setTime(new SimpleDateFormat("hhmm").parse(time));
+ newCalendar.set(
+ currentTime.get(Calendar.YEAR),
+ currentTime.get(Calendar.MONTH),
+ currentTime.get(Calendar.DATE));
+ return newCalendar;
+ } catch (ParseException e) {
+ Log.w(TAG, "Could not parse time string" + time);
+ }
+ return null;
}
/**
diff --git a/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java b/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java
new file mode 100644
index 000000000..c3ec08d69
--- /dev/null
+++ b/InCallUI/tests/src/com/android/incallui/InCallContactInteractionsTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.incallui;
+
+import android.test.AndroidTestCase;
+import android.util.Pair;
+
+import com.android.incallui.InCallContactInteractions.BusinessContextInfo;
+
+import java.util.Calendar;
+
+public class InCallContactInteractionsTest extends AndroidTestCase {
+ private InCallContactInteractions mInCallContactInteractions;
+
+ @Override
+ protected void setUp() {
+ mInCallContactInteractions = new InCallContactInteractions(mContext, true /* isBusiness */);
+ }
+
+ public void testIsOpenNow() {
+ Calendar currentTimeForTest = Calendar.getInstance();
+ currentTimeForTest.set(Calendar.HOUR_OF_DAY, 10);
+ BusinessContextInfo info =
+ mInCallContactInteractions.constructHoursInfoByTime(
+ currentTimeForTest,
+ Pair.create("0800", "2000"));
+ assertEquals(mContext.getString(R.string.open_now), info.heading);
+ }
+
+ public void testIsClosedNow_BeforeOpen() {
+ Calendar currentTimeForTest = Calendar.getInstance();
+ currentTimeForTest.set(Calendar.HOUR_OF_DAY, 6);
+ BusinessContextInfo info =
+ mInCallContactInteractions.constructHoursInfoByTime(
+ currentTimeForTest,
+ Pair.create("0800", "2000"));
+ assertEquals(mContext.getString(R.string.closed_now), info.heading);
+ }
+
+ public void testIsClosedNow_AfterClosed() {
+ Calendar currentTimeForTest = Calendar.getInstance();
+ currentTimeForTest.set(Calendar.HOUR_OF_DAY, 21);
+ BusinessContextInfo info =
+ mInCallContactInteractions.constructHoursInfoByTime(
+ currentTimeForTest,
+ Pair.create("0800", "2000"));
+ assertEquals(mContext.getString(R.string.closed_now), info.heading);
+ }
+
+ public void testInvalidOpeningHours() {
+ Calendar currentTimeForTest = Calendar.getInstance();
+ currentTimeForTest.set(Calendar.HOUR_OF_DAY, 21);
+ BusinessContextInfo info =
+ mInCallContactInteractions.constructHoursInfoByTime(
+ currentTimeForTest,
+ Pair.create("", "2000"));
+ assertEquals(null, info);
+ }
+}