summaryrefslogtreecommitdiff
path: root/InCallUI
diff options
context:
space:
mode:
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);
+ }
+}