Merge "Remove deprecated ExtendedBlockingButtonRenderer."
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java
index 2bd3629..6757268 100644
--- a/InCallUI/src/com/android/incallui/AnswerPresenter.java
+++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java
@@ -57,6 +57,7 @@
call = calls.getVideoUpgradeRequestCall();
Log.d(this, "getVideoUpgradeRequestCall call =" + call);
if (call != null) {
+ showAnswerUi(true);
processVideoUpgradeRequestCall(call);
}
} else {
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index 3973fdf..a27efec 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -376,6 +376,7 @@
private int mRequestedVideoState = VideoProfile.STATE_AUDIO_ONLY;
private InCallVideoCallCallback mVideoCallCallback;
+ private boolean mIsVideoCallCallbackRegistered;
private String mChildNumber;
private String mLastForwardedNumber;
private String mCallSubject;
@@ -478,6 +479,7 @@
mVideoCallCallback = new InCallVideoCallCallback(this);
}
mTelecomCall.getVideoCall().registerCallback(mVideoCallCallback);
+ mIsVideoCallCallbackRegistered = true;
}
mChildCallIds.clear();
@@ -784,8 +786,14 @@
return mTelecomCall == null ? null : mTelecomCall.getDetails().getAccountHandle();
}
+ /**
+ * @return The {@link VideoCall} instance associated with the {@link android.telecom.Call}.
+ * Will return {@code null} until {@link #updateFromTelecomCall()} has registered a valid
+ * callback on the {@link VideoCall}.
+ */
public VideoCall getVideoCall() {
- return mTelecomCall == null ? null : mTelecomCall.getVideoCall();
+ return mTelecomCall == null || !mIsVideoCallCallbackRegistered ? null
+ : mTelecomCall.getVideoCall();
}
public List<String> getChildCallIds() {
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index 5cc6bc0..a7d4dd4 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -498,7 +498,7 @@
}
return mPrimary.can(android.telecom.Call.Details.CAPABILITY_MANAGE_CONFERENCE)
- && !mPrimary.isVideoCall(mContext);
+ && !mIsFullscreen;
}
private void setCallbackNumber() {
@@ -1036,6 +1036,7 @@
}
ui.setCallCardVisible(!isFullscreenMode);
ui.setSecondaryInfoVisible(!isFullscreenMode);
+ maybeShowManageConferenceCallButton();
}
@Override
diff --git a/InCallUI/tests/src/com/android/incallui/ExternalCallListTest.java b/InCallUI/tests/src/com/android/incallui/ExternalCallListTest.java
new file mode 100644
index 0000000..070bdf5
--- /dev/null
+++ b/InCallUI/tests/src/com/android/incallui/ExternalCallListTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 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.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.telecom.*;
+import android.telecom.Call;
+import android.test.AndroidTestCase;
+
+import java.lang.reflect.Constructor;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ExternalCallListTest extends AndroidTestCase {
+
+ private static class Listener implements ExternalCallList.ExternalCallListener {
+ private CountDownLatch mCallAddedLatch = new CountDownLatch(1);
+ private CountDownLatch mCallRemovedLatch = new CountDownLatch(1);
+ private CountDownLatch mCallUpdatedLatch = new CountDownLatch(1);
+
+ @Override
+ public void onExternalCallAdded(Call call) {
+ mCallAddedLatch.countDown();
+ }
+
+ @Override
+ public void onExternalCallRemoved(Call call) {
+ mCallRemovedLatch.countDown();
+ }
+
+ @Override
+ public void onExternalCallUpdated(Call call) {
+ mCallUpdatedLatch.countDown();
+ }
+
+ public boolean awaitCallAdded() {
+ try {
+ return mCallAddedLatch.await(WAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ public boolean awaitCallRemoved() {
+ try {
+ return mCallRemovedLatch.await(WAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+
+ public boolean awaitCallUpdated() {
+ try {
+ return mCallUpdatedLatch.await(WAIT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+ }
+
+ private static final int WAIT_TIMEOUT_MILLIS = 5000;
+
+ private ExternalCallList mExternalCallList = new ExternalCallList();
+ private Listener mExternalCallListener = new Listener();
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mExternalCallList.addExternalCallListener(mExternalCallListener);
+ }
+
+ public void testAddCallSuccess() {
+ TestTelecomCall call = getTestCall(Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+ mExternalCallList.onCallAdded(call.getCall());
+ assertTrue(mExternalCallListener.awaitCallAdded());
+ }
+
+ public void testAddCallFail() {
+ TestTelecomCall call = getTestCall(0 /* no properties */);
+ try {
+ mExternalCallList.onCallAdded(call.getCall());
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ public void testUpdateCall() {
+ TestTelecomCall call = getTestCall(Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+ mExternalCallList.onCallAdded(call.getCall());
+ assertTrue(mExternalCallListener.awaitCallAdded());
+
+ call.forceDetailsUpdate();
+ assertTrue(mExternalCallListener.awaitCallUpdated());
+ }
+
+ public void testRemoveCall() {
+ TestTelecomCall call = getTestCall(Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+ mExternalCallList.onCallAdded(call.getCall());
+ assertTrue(mExternalCallListener.awaitCallAdded());
+
+ mExternalCallList.onCallRemoved(call.getCall());
+ assertTrue(mExternalCallListener.awaitCallRemoved());
+ }
+
+ private TestTelecomCall getTestCall(int properties) {
+ TestTelecomCall testCall = TestTelecomCall.createInstance(
+ "1",
+ Uri.parse("tel:650-555-1212"), /* handle */
+ TelecomManager.PRESENTATION_ALLOWED, /* handlePresentation */
+ "Joe", /* callerDisplayName */
+ TelecomManager.PRESENTATION_ALLOWED, /* callerDisplayNamePresentation */
+ new PhoneAccountHandle(new ComponentName("test", "class"),
+ "handle"), /* accountHandle */
+ Call.Details.CAPABILITY_CAN_PULL_CALL, /* capabilities */
+ properties, /* properties */
+ null, /* disconnectCause */
+ 0, /* connectTimeMillis */
+ null, /* GatewayInfo */
+ VideoProfile.STATE_AUDIO_ONLY, /* videoState */
+ null, /* statusHints */
+ null, /* extras */
+ null /* intentExtras */);
+ return testCall;
+ }
+}
diff --git a/InCallUI/tests/src/com/android/incallui/ExternalCallNotifierTest.java b/InCallUI/tests/src/com/android/incallui/ExternalCallNotifierTest.java
new file mode 100644
index 0000000..e57efef
--- /dev/null
+++ b/InCallUI/tests/src/com/android/incallui/ExternalCallNotifierTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 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 static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.android.contacts.common.preference.ContactsPreferences;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.telecom.*;
+import android.telecom.Call;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContext;
+
+/**
+ * Unit tests for {@link ExternalCallNotifier}.
+ */
+public class ExternalCallNotifierTest extends AndroidTestCase {
+ private static final int TIMEOUT_MILLIS = 5000;
+ private static final String NAME_PRIMARY = "Full Name";
+ private static final String NAME_ALTERNATIVE = "Name, Full";
+ private static final String LOCATION = "US";
+ private static final String NUMBER = "6505551212";
+
+ @Mock private ContactsPreferences mContactsPreferences;
+ @Mock private NotificationManager mNotificationManager;
+ @Mock private MockContext mMockContext;
+ @Mock private Resources mResources;
+ @Mock private StatusBarNotifier mStatusBarNotifier;
+ @Mock private ContactInfoCache mContactInfoCache;
+ @Mock private TelecomManager mTelecomManager;
+ @Mock private TelephonyManager mTelephonyManager;
+ @Mock private ProximitySensor mProximitySensor;
+ @Mock private CallList mCallList;
+ private InCallPresenter mInCallPresenter;
+ private ExternalCallNotifier mExternalCallNotifier;
+ private ContactInfoCache.ContactCacheEntry mContactInfo;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+
+ when(mContactsPreferences.getDisplayOrder())
+ .thenReturn(ContactsPreferences.DISPLAY_ORDER_PRIMARY);
+
+ // Setup the mock context to return mocks for some of the needed services; the notification
+ // service is especially important as we want to be able to intercept calls into it and
+ // validate the notifcations.
+ when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
+ .thenReturn(mNotificationManager);
+ when(mMockContext.getSystemService(eq(Context.TELECOM_SERVICE)))
+ .thenReturn(mTelecomManager);
+ when(mMockContext.getSystemService(eq(Context.TELEPHONY_SERVICE)))
+ .thenReturn(mTelephonyManager);
+
+ // These aspects of the context are used by the notification builder to build the actual
+ // notification; we will rely on the actual implementations of these.
+ when(mMockContext.getPackageManager()).thenReturn(mContext.getPackageManager());
+ when(mMockContext.getResources()).thenReturn(mContext.getResources());
+ when(mMockContext.getApplicationInfo()).thenReturn(mContext.getApplicationInfo());
+ when(mMockContext.getContentResolver()).thenReturn(mContext.getContentResolver());
+ when(mMockContext.getPackageName()).thenReturn(mContext.getPackageName());
+
+ ContactsPreferencesFactory.setTestInstance(null);
+ mExternalCallNotifier = new ExternalCallNotifier(mMockContext, mContactInfoCache);
+
+ // We don't directly use the InCallPresenter in the test, or even in ExternalCallNotifier
+ // itself. However, ExternalCallNotifier needs to make instances of
+ // com.android.incallui.Call for the purpose of performing contact cache lookups. The
+ // Call class depends on the static InCallPresenter for a number of things, so we need to
+ // set it up here to prevent crashes.
+ mInCallPresenter = InCallPresenter.getInstance();
+ mInCallPresenter.setUp(mMockContext, mCallList, new ExternalCallList(),
+ null, mStatusBarNotifier, mExternalCallNotifier, mContactInfoCache,
+ mProximitySensor);
+
+ // Unlocked all contact info is available
+ mContactInfo = new ContactInfoCache.ContactCacheEntry();
+ mContactInfo.namePrimary = NAME_PRIMARY;
+ mContactInfo.nameAlternative = NAME_ALTERNATIVE;
+ mContactInfo.location = LOCATION;
+ mContactInfo.number = NUMBER;
+
+ // Given the mock ContactInfoCache cache, we need to mock out what happens when the
+ // ExternalCallNotifier calls into the contact info cache to do a lookup. We will always
+ // return mock info stored in mContactInfo.
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ com.android.incallui.Call call = (com.android.incallui.Call) args[0];
+ ContactInfoCache.ContactInfoCacheCallback callback
+ = (ContactInfoCache.ContactInfoCacheCallback) args[2];
+ callback.onContactInfoComplete(call.getId(), mContactInfo);
+ return null;
+ }
+ }).when(mContactInfoCache).findInfo(any(com.android.incallui.Call.class), anyBoolean(),
+ any(ContactInfoCache.ContactInfoCacheCallback.class));
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ ContactsPreferencesFactory.setTestInstance(null);
+ mInCallPresenter.tearDown();
+ }
+
+ public void testPostNonPullable() {
+ TestTelecomCall call = getTestCall(false);
+ mExternalCallNotifier.onExternalCallAdded(call.getCall());
+ Notification notification = verifyNotificationPosted();
+ assertNull(notification.actions);
+ }
+
+ public void testPostPullable() {
+ TestTelecomCall call = getTestCall(true);
+ mExternalCallNotifier.onExternalCallAdded(call.getCall());
+ Notification notification = verifyNotificationPosted();
+ assertEquals(1, notification.actions.length);
+ }
+
+ public void testNotificationDismissed() {
+ TestTelecomCall call = getTestCall(false);
+ mExternalCallNotifier.onExternalCallAdded(call.getCall());
+ verifyNotificationPosted();
+
+ mExternalCallNotifier.onExternalCallRemoved(call.getCall());
+ verify(mNotificationManager, timeout(TIMEOUT_MILLIS)).cancel(eq("EXTERNAL_CALL"), eq(0));
+ }
+
+ public void testNotificationUpdated() {
+ TestTelecomCall call = getTestCall(false);
+ mExternalCallNotifier.onExternalCallAdded(call.getCall());
+ verifyNotificationPosted();
+
+ call.setCapabilities(android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL);
+ mExternalCallNotifier.onExternalCallUpdated(call.getCall());
+
+ ArgumentCaptor<Notification> notificationCaptor =
+ ArgumentCaptor.forClass(Notification.class);
+ verify(mNotificationManager, timeout(TIMEOUT_MILLIS).times(2))
+ .notify(eq("EXTERNAL_CALL"), eq(0), notificationCaptor.capture());
+ Notification notification1 = notificationCaptor.getAllValues().get(0);
+ assertNull(notification1.actions);
+ Notification notification2 = notificationCaptor.getAllValues().get(1);
+ assertEquals(1, notification2.actions.length);
+ }
+
+ private Notification verifyNotificationPosted() {
+ ArgumentCaptor<Notification> notificationCaptor =
+ ArgumentCaptor.forClass(Notification.class);
+ verify(mNotificationManager, timeout(TIMEOUT_MILLIS))
+ .notify(eq("EXTERNAL_CALL"), eq(0), notificationCaptor.capture());
+ return notificationCaptor.getValue();
+ }
+
+ private TestTelecomCall getTestCall(boolean canPull) {
+ TestTelecomCall testCall = TestTelecomCall.createInstance(
+ "1",
+ Uri.parse("tel:650-555-1212"), /* handle */
+ TelecomManager.PRESENTATION_ALLOWED, /* handlePresentation */
+ "Joe", /* callerDisplayName */
+ TelecomManager.PRESENTATION_ALLOWED, /* callerDisplayNamePresentation */
+ new PhoneAccountHandle(new ComponentName("test", "class"),
+ "handle"), /* accountHandle */
+ canPull ? android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL : 0, /* capabilities */
+ Call.Details.PROPERTY_IS_EXTERNAL_CALL, /* properties */
+ null, /* disconnectCause */
+ 0, /* connectTimeMillis */
+ null, /* GatewayInfo */
+ VideoProfile.STATE_AUDIO_ONLY, /* videoState */
+ null, /* statusHints */
+ null, /* extras */
+ null /* intentExtras */);
+ return testCall;
+ }
+}
diff --git a/InCallUI/tests/src/com/android/incallui/TestTelecomCall.java b/InCallUI/tests/src/com/android/incallui/TestTelecomCall.java
new file mode 100644
index 0000000..48ac6e1
--- /dev/null
+++ b/InCallUI/tests/src/com/android/incallui/TestTelecomCall.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2016 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 com.google.common.base.Preconditions;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.telecom.DisconnectCause;
+import android.telecom.GatewayInfo;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.StatusHints;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Wrapper class which uses reflection to create instances of {@link android.telecom.Call} for use
+ * with unit testing. Since {@link android.telecom.Call} is final, it cannot be mocked using
+ * mockito, and since all setter methods are hidden, it is necessary to use reflection. In the
+ * future, it would be desirable to replace this if a different mocking solution is used.
+ */
+public class TestTelecomCall {
+
+ private android.telecom.Call mCall;
+
+ public static @Nullable TestTelecomCall createInstance(String callId,
+ Uri handle,
+ int handlePresentation,
+ String callerDisplayName,
+ int callerDisplayNamePresentation,
+ PhoneAccountHandle accountHandle,
+ int capabilities,
+ int properties,
+ DisconnectCause disconnectCause,
+ long connectTimeMillis,
+ GatewayInfo gatewayInfo,
+ int videoState,
+ StatusHints statusHints,
+ Bundle extras,
+ Bundle intentExtras) {
+
+ try {
+ // Phone and InCall adapter are @hide, so we cannot refer to them directly.
+ Class<?> phoneClass = Class.forName("android.telecom.Phone");
+ Class<?> incallAdapterClass = Class.forName("android.telecom.InCallAdapter");
+ Class<?> callClass = android.telecom.Call.class;
+ Constructor<?> cons = callClass
+ .getDeclaredConstructor(phoneClass, String.class, incallAdapterClass);
+ cons.setAccessible(true);
+
+ android.telecom.Call call = (android.telecom.Call) cons.newInstance(null, callId, null);
+
+ // Create an instance of the call details.
+ Class<?> callDetailsClass = android.telecom.Call.Details.class;
+ Constructor<?> detailsCons = callDetailsClass.getDeclaredConstructor(
+ String.class, /* telecomCallId */
+ Uri.class, /* handle */
+ int.class, /* handlePresentation */
+ String.class, /* callerDisplayName */
+ int.class, /* callerDisplayNamePresentation */
+ PhoneAccountHandle.class, /* accountHandle */
+ int.class, /* capabilities */
+ int.class, /* properties */
+ DisconnectCause.class, /* disconnectCause */
+ long.class, /* connectTimeMillis */
+ GatewayInfo.class, /* gatewayInfo */
+ int.class, /* videoState */
+ StatusHints.class, /* statusHints */
+ Bundle.class, /* extras */
+ Bundle.class /* intentExtras */);
+ detailsCons.setAccessible(true);
+
+ android.telecom.Call.Details details = (android.telecom.Call.Details)
+ detailsCons.newInstance(callId, handle, handlePresentation, callerDisplayName,
+ callerDisplayNamePresentation, accountHandle, capabilities, properties,
+ disconnectCause, connectTimeMillis, gatewayInfo, videoState,
+ statusHints,
+ extras, intentExtras);
+
+ // Finally, set this as the details of the call.
+ Field detailsField = call.getClass().getDeclaredField("mDetails");
+ detailsField.setAccessible(true);
+ detailsField.set(call, details);
+
+ return new TestTelecomCall(call);
+ } catch (NoSuchMethodException nsm) {
+ return null;
+ } catch (ClassNotFoundException cnf) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ } catch (InstantiationException e) {
+ return null;
+ } catch (InvocationTargetException e) {
+ return null;
+ } catch (NoSuchFieldException e) {
+ return null;
+ }
+ }
+
+ private TestTelecomCall(android.telecom.Call call) {
+ mCall = call;
+ }
+
+ public android.telecom.Call getCall() {
+ return mCall;
+ }
+
+ public void forceDetailsUpdate() {
+ Preconditions.checkNotNull(mCall);
+
+ try {
+ Method method = mCall.getClass().getDeclaredMethod("fireDetailsChanged",
+ android.telecom.Call.Details.class);
+ method.setAccessible(true);
+ method.invoke(mCall, mCall.getDetails());
+ } catch (NoSuchMethodException e) {
+ Log.e(this, "forceDetailsUpdate", e);
+ } catch (InvocationTargetException e) {
+ Log.e(this, "forceDetailsUpdate", e);
+ } catch (IllegalAccessException e) {
+ Log.e(this, "forceDetailsUpdate", e);
+ }
+ }
+
+ public void setCapabilities(int capabilities) {
+ Preconditions.checkNotNull(mCall);
+ try {
+ Field field = mCall.getDetails().getClass().getDeclaredField("mCallCapabilities");
+ field.setAccessible(true);
+ field.set(mCall.getDetails(), capabilities);
+ } catch (IllegalAccessException e) {
+ Log.e(this, "setProperties", e);
+ } catch (NoSuchFieldException e) {
+ Log.e(this, "setProperties", e);
+ }
+ }
+
+ public void setCall(android.telecom.Call call) {
+ mCall = call;
+ }
+}
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index 469e72a..660bca3 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -125,6 +125,7 @@
android:id="@+id/call_account_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/call_log_call_account_margin_bottom"
android:layout_marginEnd="@dimen/call_log_icon_margin"
android:textColor="?attr/call_log_secondary_text_color"
android:textSize="@dimen/call_log_detail_text_size"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a9f2702..371a1c6 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -34,6 +34,7 @@
<dimen name="call_log_start_margin">8dp</dimen>
<dimen name="call_log_indent_margin">24dp</dimen>
<dimen name="call_log_name_margin_bottom">2dp</dimen>
+ <dimen name="call_log_call_account_margin_bottom">2dp</dimen>
<dimen name="call_log_vertical_padding">12dp</dimen>
<dimen name="call_log_list_item_height">56dp</dimen>
<dimen name="call_log_list_item_info_margin_start">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2907615..9407059 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -731,6 +731,26 @@
[CHAR LIMIT=NONE] -->
<string name="description_phone_account">on <xliff:g id="phoneAccount" example="SIM 1">^1</xliff:g></string>
+ <!-- String describing the secondary line number the call was received via.
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ [CHAR LIMIT=NONE]-->
+ <string name="description_via_number">via <xliff:g id="number" example="(555) 555-5555">%1$s</xliff:g></string>
+
+ <!-- TextView text item showing the secondary line number the call was received via.
+ [CHAR LIMIT=NONE]-->
+ <string name="call_log_via_number">via <xliff:g id="number" example="(555) 555-5555">%1$s</xliff:g></string>
+
+ <!-- String describing the PhoneAccount and via number that a call was received on, if both are
+ visible.
+ Note: AccessibilityServices use this attribute to announce what the view represents.
+ [CHAR LIMIT=NONE]-->
+ <string name="description_via_number_phone_account">on <xliff:g id="phoneAccount" example="SIM 1">%1$s</xliff:g>, via <xliff:g id="number" example="(555) 555-5555">%2$s</xliff:g></string>
+
+ <!-- The order of the PhoneAccount and via number that a call was received on,
+ if both are visible.
+ [CHAR LIMIT=NONE]-->
+ <string name="call_log_via_number_phone_account"><xliff:g id="phoneAccount" example="SIM 1">%1$s</xliff:g> via <xliff:g id="number" example="(555) 555-5555">%2$s</xliff:g></string>
+
<!-- String describing the phone icon on a call log list item. When tapped, it will place a
call to the number represented by that call log entry. [CHAR LIMIT=NONE]-->
<string name="description_call_log_call_action">Call</string>
diff --git a/src-N/com/android/dialer/compat/CallsSdkCompat.java b/src-N/com/android/dialer/compat/CallsSdkCompat.java
index 3d72e35..a428ca3 100644
--- a/src-N/com/android/dialer/compat/CallsSdkCompat.java
+++ b/src-N/com/android/dialer/compat/CallsSdkCompat.java
@@ -21,4 +21,5 @@
public class CallsSdkCompat {
public static final String POST_DIAL_DIGITS = CallLog.Calls.POST_DIAL_DIGITS;
+ public static final String VIA_NUMBER = CallLog.Calls.VIA_NUMBER;
}
diff --git a/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java b/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java
index 836f091..60d3ca1 100644
--- a/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java
+++ b/src-pre-N/com/android/dialer/compat/CallsSdkCompat.java
@@ -21,4 +21,5 @@
public class CallsSdkCompat {
@Nullable public static final String POST_DIAL_DIGITS = null;
+ @Nullable public static final String VIA_NUMBER = null;
}
diff --git a/src/com/android/dialer/CallDetailActivity.java b/src/com/android/dialer/CallDetailActivity.java
index 42bee1e..94c2f00 100644
--- a/src/com/android/dialer/CallDetailActivity.java
+++ b/src/com/android/dialer/CallDetailActivity.java
@@ -142,10 +142,23 @@
}
}
- String accountLabel =
- PhoneAccountUtils.getAccountLabel(mContext, mDetails.accountHandle);
+ CharSequence accountLabel = PhoneAccountUtils.getAccountLabel(mContext,
+ mDetails.accountHandle);
+ CharSequence accountContentDescription =
+ PhoneCallDetails.createAccountLabelDescription(mResources, mDetails.viaNumber,
+ accountLabel);
+ if (!TextUtils.isEmpty(mDetails.viaNumber)) {
+ if (!TextUtils.isEmpty(accountLabel)) {
+ accountLabel = mResources.getString(R.string.call_log_via_number_phone_account,
+ accountLabel, mDetails.viaNumber);
+ } else {
+ accountLabel = mResources.getString(R.string.call_log_via_number,
+ mDetails.viaNumber);
+ }
+ }
if (!TextUtils.isEmpty(accountLabel)) {
mAccountLabel.setText(accountLabel);
+ mAccountLabel.setContentDescription(accountContentDescription);
mAccountLabel.setVisibility(View.VISIBLE);
} else {
mAccountLabel.setVisibility(View.GONE);
diff --git a/src/com/android/dialer/PhoneCallDetails.java b/src/com/android/dialer/PhoneCallDetails.java
index 16192fc..8a2e520 100644
--- a/src/com/android/dialer/PhoneCallDetails.java
+++ b/src/com/android/dialer/PhoneCallDetails.java
@@ -18,11 +18,14 @@
import com.android.contacts.common.ContactsUtils.UserType;
import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.dialer.calllog.PhoneNumberDisplayUtil;
import android.content.Context;
+import android.content.res.Resources;
import android.net.Uri;
import android.provider.CallLog.Calls;
+import android.support.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
@@ -34,6 +37,8 @@
public CharSequence number;
// Post-dial digits associated with the outgoing call.
public String postDialDigits;
+ // The secondary line number the call was received via.
+ public String viaNumber;
// The number presenting rules set by the network, e.g., {@link Calls#PRESENTATION_ALLOWED}
public int numberPresentation;
// The formatted version of {@link #number}.
@@ -152,4 +157,31 @@
}
return nameAlternative;
}
+
+ /**
+ * Construct the "on {accountLabel} via {viaNumber}" accessibility description for the account
+ * list item, depending on the existence of the accountLabel and viaNumber.
+ * @param viaNumber The number that this call is being placed via.
+ * @param accountLabel The {@link PhoneAccount} label that this call is being placed with.
+ * @return The description of the account that this call has been placed on.
+ */
+ public static CharSequence createAccountLabelDescription(Resources resources,
+ @Nullable String viaNumber, @Nullable CharSequence accountLabel) {
+
+ if((!TextUtils.isEmpty(viaNumber)) && !TextUtils.isEmpty(accountLabel)) {
+ String msg = resources.getString(R.string.description_via_number_phone_account,
+ accountLabel, viaNumber);
+ CharSequence accountNumberLabel = ContactDisplayUtils.getTelephoneTtsSpannable(msg,
+ viaNumber);
+ return (accountNumberLabel == null) ? msg : accountNumberLabel;
+ } else if (!TextUtils.isEmpty(viaNumber)) {
+ CharSequence viaNumberLabel = ContactDisplayUtils.getTtsSpannedPhoneNumber(resources,
+ R.string.description_via_number, viaNumber);
+ return (viaNumberLabel == null) ? viaNumber : viaNumberLabel;
+ } else if (!TextUtils.isEmpty(accountLabel)) {
+ return TextUtils.expandTemplate(
+ resources.getString(R.string.description_phone_account), accountLabel);
+ }
+ return "";
+ }
}
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 506dafd..aa0b7c9 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -485,13 +485,11 @@
final String number = c.getString(CallLogQuery.NUMBER);
final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
-
- mFilteredNumberAsyncQueryHandler.isBlockedNumber(
+ final CallLogListItemViewHolder views = (CallLogListItemViewHolder) viewHolder;
+ boolean success = mFilteredNumberAsyncQueryHandler.isBlockedNumber(
new FilteredNumberAsyncQueryHandler.OnCheckBlockedListener() {
@Override
public void onCheckComplete(Integer id) {
- final CallLogListItemViewHolder views =
- (CallLogListItemViewHolder) viewHolder;
views.blockId = id;
if (mExtendedCallInfoService == null) {
loadDataAndRender(views);
@@ -507,6 +505,9 @@
}
}
}, number, countryIso);
+ if (!success) {
+ loadDataAndRender(views);
+ }
}
private void loadDataAndRender(CallLogListItemViewHolder views) {
@@ -519,15 +520,17 @@
int count = getGroupSize(position);
final String number = c.getString(CallLogQuery.NUMBER);
+ final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
final String postDialDigits = CompatUtils.isNCompatible()
&& mActivityType != ACTIVITY_TYPE_ARCHIVE ?
c.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
-
+ final String viaNumber = CompatUtils.isNCompatible()
+ && mActivityType != ACTIVITY_TYPE_ARCHIVE ?
+ c.getString(CallLogQuery.VIA_NUMBER) : "";
final int numberPresentation = c.getInt(CallLogQuery.NUMBER_PRESENTATION);
final PhoneAccountHandle accountHandle = PhoneAccountUtils.getAccount(
c.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME),
c.getString(CallLogQuery.ACCOUNT_ID));
- final String countryIso = c.getString(CallLogQuery.COUNTRY_ISO);
final ContactInfo cachedContactInfo = ContactInfoHelper.getContactInfo(c);
final boolean isVoicemailNumber =
mCallLogCache.isVoicemailNumber(accountHandle, number);
@@ -547,6 +550,7 @@
final PhoneCallDetails details = new PhoneCallDetails(
mContext, number, numberPresentation, formattedNumber,
postDialDigits, isVoicemailNumber);
+ details.viaNumber = viaNumber;
details.accountHandle = accountHandle;
details.countryIso = countryIso;
details.date = c.getLong(CallLogQuery.DATE);
diff --git a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
index 7cb35f5..34b2f0e 100644
--- a/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
+++ b/src/com/android/dialer/calllog/CallLogAsyncTaskUtil.java
@@ -28,6 +28,7 @@
import android.provider.CallLog;
import android.provider.VoicemailContract.Voicemails;
import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
@@ -44,6 +45,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Locale;
public class CallLogAsyncTaskUtil {
private static String TAG = CallLogAsyncTaskUtil.class.getSimpleName();
@@ -90,12 +92,14 @@
static final int DATA_USAGE = 10;
static final int TRANSCRIPTION_COLUMN_INDEX = 11;
static final int POST_DIAL_DIGITS = 12;
+ static final int VIA_NUMBER = 13;
static {
ArrayList<String> projectionList = new ArrayList<>();
projectionList.addAll(Arrays.asList(CALL_LOG_PROJECTION_INTERNAL));
if (CompatUtils.isNCompatible()) {
projectionList.add(CallsSdkCompat.POST_DIAL_DIGITS);
+ projectionList.add(CallsSdkCompat.VIA_NUMBER);
}
projectionList.trimToSize();
CALL_LOG_PROJECTION = projectionList.toArray(new String[projectionList.size()]);
@@ -187,6 +191,8 @@
final String number = cursor.getString(CallDetailQuery.NUMBER_COLUMN_INDEX);
final String postDialDigits = CompatUtils.isNCompatible()
? cursor.getString(CallDetailQuery.POST_DIAL_DIGITS) : "";
+ final String viaNumber = CompatUtils.isNCompatible() ?
+ cursor.getString(CallDetailQuery.VIA_NUMBER) : "";
final int numberPresentation =
cursor.getInt(CallDetailQuery.NUMBER_PRESENTATION_COLUMN_INDEX);
@@ -211,6 +217,7 @@
context, number, numberPresentation, info.formattedNumber,
postDialDigits, isVoicemail);
+ details.viaNumber = viaNumber;
details.accountHandle = accountHandle;
details.contactUri = info.lookupUri;
details.namePrimary = info.name;
diff --git a/src/com/android/dialer/calllog/CallLogGroupBuilder.java b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
index 0931e06..aa45029 100644
--- a/src/com/android/dialer/calllog/CallLogGroupBuilder.java
+++ b/src/com/android/dialer/calllog/CallLogGroupBuilder.java
@@ -125,6 +125,8 @@
String groupNumber = cursor.getString(CallLogQuery.NUMBER);
String groupPostDialDigits = CompatUtils.isNCompatible()
? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+ String groupViaNumbers = CompatUtils.isNCompatible()
+ ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
int groupCallType = cursor.getInt(CallLogQuery.CALL_TYPE);
String groupAccountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
String groupAccountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
@@ -132,6 +134,7 @@
String number;
String numberPostDialDigits;
+ String numberViaNumbers;
int callType;
String accountComponentName;
String accountId;
@@ -141,18 +144,21 @@
number = cursor.getString(CallLogQuery.NUMBER);
numberPostDialDigits = CompatUtils.isNCompatible()
? cursor.getString(CallLogQuery.POST_DIAL_DIGITS) : "";
+ numberViaNumbers = CompatUtils.isNCompatible()
+ ? cursor.getString(CallLogQuery.VIA_NUMBER) : "";
callType = cursor.getInt(CallLogQuery.CALL_TYPE);
accountComponentName = cursor.getString(CallLogQuery.ACCOUNT_COMPONENT_NAME);
accountId = cursor.getString(CallLogQuery.ACCOUNT_ID);
final boolean isSameNumber = equalNumbers(groupNumber, number);
final boolean isSamePostDialDigits = groupPostDialDigits.equals(numberPostDialDigits);
+ final boolean isSameViaNumbers = groupViaNumbers.equals(numberViaNumbers);
final boolean isSameAccount = isSameAccount(
groupAccountComponentName, accountComponentName, groupAccountId, accountId);
// Group with the same number and account. Never group voicemails. Only group blocked
// calls with other blocked calls.
- if (isSameNumber && isSameAccount && isSamePostDialDigits
+ if (isSameNumber && isSameAccount && isSamePostDialDigits && isSameViaNumbers
&& areBothNotVoicemail(callType, groupCallType)
&& (areBothNotBlocked(callType, groupCallType)
|| areBothBlocked(callType, groupCallType))) {
@@ -174,6 +180,7 @@
// Update the group values to those of the current call.
groupNumber = number;
groupPostDialDigits = numberPostDialDigits;
+ groupViaNumbers = numberViaNumbers;
groupCallType = callType;
groupAccountComponentName = accountComponentName;
groupAccountId = accountId;
diff --git a/src/com/android/dialer/calllog/CallLogListItemHelper.java b/src/com/android/dialer/calllog/CallLogListItemHelper.java
index 7919a09..18b6ff5 100644
--- a/src/com/android/dialer/calllog/CallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/CallLogListItemHelper.java
@@ -190,20 +190,15 @@
callDescription.append(mResources.getString(R.string.description_video_call));
}
- int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
+ CharSequence onAccountLabel = PhoneCallDetails.createAccountLabelDescription(mResources,
+ details.viaNumber, accountLabel);
- // Use chosen string resource to build up the message.
- CharSequence onAccountLabel = accountLabel == null
- ? ""
- : TextUtils.expandTemplate(
- mResources.getString(R.string.description_phone_account),
- accountLabel);
+ int stringID = getCallDescriptionStringID(details.callTypes, details.isRead);
callDescription.append(
TextUtils.expandTemplate(
mResources.getString(stringID),
nameOrNumber,
- // If no type or location can be determined, sub in empty string.
typeOrLocation == null ? "" : typeOrLocation,
timeOfCall,
onAccountLabel));
diff --git a/src/com/android/dialer/calllog/CallLogQuery.java b/src/com/android/dialer/calllog/CallLogQuery.java
index 4900354..e1a4119 100644
--- a/src/com/android/dialer/calllog/CallLogQuery.java
+++ b/src/com/android/dialer/calllog/CallLogQuery.java
@@ -93,6 +93,7 @@
* Call {@link CompatUtils#isNCompatible()} prior to use
*/
public static int POST_DIAL_DIGITS = -1;
+ public static int VIA_NUMBER = -1;
public static final String[] _PROJECTION;
@@ -105,6 +106,8 @@
if (CompatUtils.isNCompatible()) {
projectionList.add(CallsSdkCompat.POST_DIAL_DIGITS);
POST_DIAL_DIGITS = projectionList.size() - 1;
+ projectionList.add(CallsSdkCompat.VIA_NUMBER);
+ VIA_NUMBER = projectionList.size() - 1;
}
_PROJECTION = projectionList.toArray(new String[projectionList.size()]);
}
diff --git a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
index ff1a44f..5312161 100644
--- a/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
+++ b/src/com/android/dialer/calllog/PhoneCallDetailsHelper.java
@@ -116,8 +116,16 @@
// Set the account label if it exists.
String accountLabel = mCallLogCache.getAccountLabel(details.accountHandle);
-
- if (accountLabel != null) {
+ if (!TextUtils.isEmpty(details.viaNumber)) {
+ if (!TextUtils.isEmpty(accountLabel)) {
+ accountLabel = mResources.getString(R.string.call_log_via_number_phone_account,
+ accountLabel, details.viaNumber);
+ } else {
+ accountLabel = mResources.getString(R.string.call_log_via_number,
+ details.viaNumber);
+ }
+ }
+ if (!TextUtils.isEmpty(accountLabel)) {
views.callAccountLabel.setVisibility(View.VISIBLE);
views.callAccountLabel.setText(accountLabel);
int color = mCallLogCache.getAccountColor(details.accountHandle);
diff --git a/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java b/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java
index e3f8c59..52ef49a 100644
--- a/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java
+++ b/src/com/android/dialer/database/FilteredNumberAsyncQueryHandler.java
@@ -151,7 +151,6 @@
final OnCheckBlockedListener listener, String number, String countryIso) {
final String e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso);
if (TextUtils.isEmpty(e164Number)) {
- listener.onCheckComplete(null);
return false;
}
diff --git a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
index f6ef7ef..3b1dd2c 100644
--- a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
@@ -21,11 +21,13 @@
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
import android.database.MatrixCursor;
import android.net.Uri;
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.VoicemailContract;
+import android.telephony.PhoneNumberUtils;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.text.TextUtils;
@@ -37,6 +39,7 @@
import com.android.dialer.database.VoicemailArchiveContract;
import com.android.dialer.util.AppCompatConstants;
import com.android.dialer.util.TestConstants;
+import com.android.dialer.R;
import java.util.Date;
import java.util.List;
@@ -63,26 +66,30 @@
private static final String TEST_COUNTRY_ISO = "US";
private static final String TEST_DEFAULT_CUSTOM_LABEL = "myLabel";
private static final Uri TEST_LOOKUP_URI = Uri.parse("content://contacts/2");
+ private static final String TEST_ACCOUNT_ID_LABEL = "label";
private static final String TEST_NUMBER = "12125551000";
private static final String TEST_NUMBER_1 = "12345678";
private static final String TEST_NUMBER_2 = "87654321";
private static final String TEST_NUMBER_3 = "18273645";
private static final String TEST_POST_DIAL_DIGITS = ";12345";
+ private static final String TEST_VIA_NUMBER = "+16505551234";
private static final String TEST_FORMATTED_NUMBER = "1 212-555-1000";
// The object under test.
private TestCallLogAdapter mAdapter;
private MatrixCursor mCursor;
+ private Resources mResources;
- private View mView;
private CallLogListItemViewHolder mViewHolder;
private final Random mRandom = new Random();
@Override
protected void setUp() throws Exception {
super.setUp();
+ mContext = getContext();
+ mResources = mContext.getResources();
// Use a call fetcher that does not do anything.
CallLogAdapter.CallFetcher fakeCallFetcher = new CallLogAdapter.CallFetcher() {
@@ -281,6 +288,36 @@
}
@MediumTest
+ public void testBindView_CallLogWithViaNumber() {
+ createCallLogEntry(TEST_NUMBER, EMPTY_STRING, TEST_VIA_NUMBER, NO_VALUE_SET, NO_VALUE_SET);
+
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(mViewHolder, 0);
+
+ // Copy format of Resource String
+ String formattedNumber = mResources.getString(R.string.description_via_number,
+ TEST_VIA_NUMBER);
+
+ if (CompatUtils.isNCompatible()) {
+ assertEquals(formattedNumber,
+ mViewHolder.phoneCallDetailsViews.callAccountLabel.getText());
+ }
+ }
+
+ @MediumTest
+ public void testBindView_CallLogWithoutViaNumber() {
+ createCallLogEntry(TEST_NUMBER, EMPTY_STRING, EMPTY_STRING, NO_VALUE_SET, NO_VALUE_SET);
+
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(mViewHolder, 0);
+
+ if (CompatUtils.isNCompatible()) {
+ assertEquals(View.GONE,
+ mViewHolder.phoneCallDetailsViews.callAccountLabel.getVisibility());
+ }
+ }
+
+ @MediumTest
public void testPresentationAfterRebindingViewHolders() {
final int increment = 10;
final int size = increment * 4;
@@ -589,11 +626,18 @@
createCallLogEntry(TEST_NUMBER, EMPTY_STRING, NO_VALUE_SET, ARCHIVE_TYPE);
}
- private void createCallLogEntry(String number, String postDialDigits, int presentation, int type) {
+ private void createCallLogEntry(String number, String postDialDigits, int presentation,
+ int type) {
Object[] values = getValues(number, postDialDigits, presentation, type);
mCursor.addRow(values);
}
+ private void createCallLogEntry(String number, String postDialDigits, String viaNumber,
+ int presentation, int type) {
+ Object[] values = getValues(number, postDialDigits, viaNumber, presentation, type);
+ mCursor.addRow(values);
+ }
+
private void createCallLogEntryWithCachedValues(boolean inject) {
createCallLogEntryWithCachedValues(
TEST_NUMBER,
@@ -665,6 +709,23 @@
String postDialDigits,
int presentation,
int type) {
+ return getValues(number, postDialDigits, "", presentation, type);
+ }
+
+ /**
+ * @param number The phone number.
+ * @param postDialDigits The post dial digits dialed (if any)
+ * @param viaNumber The secondary number that the call was placed via
+ * @param presentation Number representing display rules for "allowed",
+ * "payphone", "restricted", or "unknown".
+ * @param type The type of the call (outgoing/ingoing)
+ */
+ private Object[] getValues(
+ String number,
+ String postDialDigits,
+ String viaNumber,
+ int presentation,
+ int type) {
Object[] values = CallLogQueryTestUtils.createTestValues();
values[CallLogQuery.ID] = mCursor.getCount();
@@ -678,6 +739,9 @@
if (!TextUtils.isEmpty(postDialDigits) && CompatUtils.isNCompatible()) {
values[CallLogQuery.POST_DIAL_DIGITS] = postDialDigits;
}
+ if (!TextUtils.isEmpty(viaNumber) && CompatUtils.isNCompatible()) {
+ values[CallLogQuery.VIA_NUMBER] = viaNumber;
+ }
if (presentation != NO_VALUE_SET) {
values[CallLogQuery.NUMBER_PRESENTATION] = presentation;
}
diff --git a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
index 107cf75..beb83b1 100644
--- a/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogGroupBuilderTest.java
@@ -109,6 +109,26 @@
}
}
+ public void testAddGroups_WithViaNumberMatching() {
+ addCallLogEntryWithViaNumber(TEST_NUMBER1, TEST_NUMBER2,
+ AppCompatConstants.CALLS_OUTGOING_TYPE);
+ addCallLogEntryWithViaNumber(TEST_NUMBER1, TEST_NUMBER2,
+ AppCompatConstants.CALLS_OUTGOING_TYPE);
+ addCallLogEntryWithViaNumber(TEST_NUMBER1, "",
+ AppCompatConstants.CALLS_OUTGOING_TYPE);
+
+ mBuilder.addGroups(mCursor);
+
+ if (CompatUtils.isNCompatible()) {
+ assertEquals(2, mFakeGroupCreator.groups.size());
+ assertGroupIs(0, 2, mFakeGroupCreator.groups.get(0));
+ assertGroupIs(2, 1, mFakeGroupCreator.groups.get(1));
+ } else {
+ assertEquals(1, mFakeGroupCreator.groups.size());
+ assertGroupIs(0, 3, mFakeGroupCreator.groups.get(0));
+ }
+ }
+
public void testAddGroups_MatchingIncomingAndOutgoing() {
addCallLogEntry(TEST_NUMBER1, AppCompatConstants.CALLS_INCOMING_TYPE);
addCallLogEntry(TEST_NUMBER1, AppCompatConstants.CALLS_OUTGOING_TYPE);
@@ -387,6 +407,19 @@
mCursor.addRow(values);
}
+ /** Adds a call log entry with the given number, post-dial digits, and type to the cursor. */
+ private void addCallLogEntryWithViaNumber(String number, String viaNumber, int type) {
+ mCursor.moveToNext();
+ Object[] values = CallLogQueryTestUtils.createTestValues();
+ values[CallLogQuery.ID] = mCursor.getPosition();
+ values[CallLogQuery.NUMBER] = number;
+ values[CallLogQuery.CALL_TYPE] = type;
+ if (CompatUtils.isNCompatible()) {
+ values[CallLogQuery.VIA_NUMBER] = viaNumber;
+ }
+ mCursor.addRow(values);
+ }
+
/** Adds a call log entry with a header to the cursor. */
private void addCallLogHeader(int section) {
mCursor.moveToNext();
diff --git a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
index 28caed4..daba428 100644
--- a/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogListItemHelperTest.java
@@ -64,7 +64,7 @@
mContext = getContext();
mResources = mContext.getResources();
final TestTelecomCallLogCache phoneUtils =
- new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER);
+ new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER, "");
PhoneCallDetailsHelper phoneCallDetailsHelper =
new PhoneCallDetailsHelper(mContext, mResources, phoneUtils);
mHelper = new CallLogListItemHelper(phoneCallDetailsHelper, mResources, phoneUtils);
diff --git a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
index f1b1a9a..c2cfedb 100644
--- a/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
+++ b/tests/src/com/android/dialer/calllog/CallLogQueryTestUtils.java
@@ -32,7 +32,7 @@
values = new Object[]{
0L, "", 0L, 0L, Calls.INCOMING_TYPE, "", "", "", null, 0, null, null, null,
null, 0L, null, 0, Calls.PRESENTATION_ALLOWED, null, null, 0, null, null,
- null, ""
+ null, "", ""
};
} else {
values = new Object[]{
diff --git a/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java b/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
index c0d1203..0c57fde 100644
--- a/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/dialer/calllog/PhoneCallDetailsHelperTest.java
@@ -16,9 +16,11 @@
package com.android.dialer.calllog;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccountHandle;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.text.Html;
@@ -63,6 +65,10 @@
private static final String EMPTY_GEOCODE = "";
/** Empty post-dial digits label */
private static final String EMPTY_POSTDIAL = "";
+ /** The number that the call was received via */
+ private static final String TEST_VIA_NUMBER = "+16505551234";
+ /** The Phone Account name that the Call was received on */
+ private static final String TEST_ACCOUNT_LABEL = "T-Stationary";
/** The object under test. */
private PhoneCallDetailsHelper mHelper;
@@ -79,10 +85,9 @@
super.setUp();
mContext = getContext();
Resources resources = mContext.getResources();
- mPhoneUtils = new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER);
- final TestTelecomCallLogCache phoneUtils = new TestTelecomCallLogCache(
- mContext, TEST_VOICEMAIL_NUMBER);
- mHelper = new PhoneCallDetailsHelper(mContext, resources, phoneUtils);
+ mPhoneUtils = new TestTelecomCallLogCache(mContext, TEST_VOICEMAIL_NUMBER,
+ TEST_ACCOUNT_LABEL);
+ mHelper = new PhoneCallDetailsHelper(mContext, resources, mPhoneUtils);
mHelper.setCurrentTimeForTest(INJECTED_CURRENT_DATE);
mViews = PhoneCallDetailsViews.createForTest(mContext);
mNameView = new TextView(mContext);
@@ -120,6 +125,26 @@
assertNameEqualsResource(R.string.voicemail);
}
+ public void testSetPhoneCallDetails_ViaNumber() {
+ setPhoneCallDetailsWithViaNumber(TEST_VIA_NUMBER);
+ assertViaNumberEquals(TEST_VIA_NUMBER);
+ }
+
+ public void testSetPhoneCallDetails_NoViaNumber() {
+ setDefaultPhoneCallDetailsNoViaNumber();
+ assertCallAccountInvisible();
+ }
+
+ public void testSetPhoneCallDetails_AccountLabel() {
+ setPhoneCallDetailsWithAccountHandle();
+ assertAccountLabelEquals(TEST_ACCOUNT_LABEL);
+ }
+
+ public void testSetPhoneCallDetails_AccountHandleViaNumber() {
+ setPhoneCallDetailsWithAccountLabelViaNumber(TEST_VIA_NUMBER);
+ assertAccountLabelEquals(TEST_VIA_NUMBER, TEST_ACCOUNT_LABEL);
+ }
+
// Voicemail date string has 3 different formats depending on how long ago the call was placed
public void testSetVoicemailPhoneCallDetails_Today() {
setVoicemailPhoneCallDetailsWithDate(System.currentTimeMillis());
@@ -368,6 +393,30 @@
assertEquals(text, mViews.callLocationAndDate.getText());
}
+ /** Asserts that the via number is correct. */
+ private void assertViaNumberEquals(String text) {
+ final String callAccountText =
+ mContext.getResources().getString(R.string.description_via_number, text);
+ assertEquals(callAccountText, mViews.callAccountLabel.getText());
+ }
+
+ /** Asserts that the account label is correct. */
+ private void assertAccountLabelEquals(String text) {
+ assertEquals(text, mViews.callAccountLabel.getText());
+ }
+
+ /** Asserts that the account label is correct when also showing the via number. */
+ private void assertAccountLabelEquals(String viaNumber, String accountLabel) {
+ final String viaNumberText =
+ mContext.getResources().getString(R.string.description_via_number, viaNumber);
+ assertEquals(accountLabel + " " + viaNumberText, mViews.callAccountLabel.getText());
+ }
+
+ /** Asserts that the call account label is invisible. */
+ private void assertCallAccountInvisible() {
+ assertEquals(mViews.callAccountLabel.getVisibility(), View.GONE);
+ }
+
/** Asserts that the duration is exactly as included in the location and date text field. */
private void assertDurationExactEquals(String text) {
Matcher matcher = Pattern.compile("(.*) (\\u2022) (\\d{2}:\\d{2})").matcher(
@@ -414,6 +463,36 @@
mHelper.setPhoneCallDetails(mViews, details);
}
+ /** Sets the phone call details with default values and the given via number. */
+ private void setPhoneCallDetailsWithViaNumber(String viaNumber) {
+ PhoneCallDetails details = getPhoneCallDetails();
+ mPhoneUtils.setAccountLabel("");
+ details.viaNumber = viaNumber;
+ mHelper.setPhoneCallDetails(mViews, details);
+ }
+
+ /** Sets the phone call details with an account handle. */
+ private void setPhoneCallDetailsWithAccountHandle() {
+ PhoneCallDetails details = getPhoneCallDetails();
+ details.accountHandle = new PhoneAccountHandle(new ComponentName("",""), "");
+ mHelper.setPhoneCallDetails(mViews, details);
+ }
+
+ /** Sets the phone call details with an account handle and via number */
+ private void setPhoneCallDetailsWithAccountLabelViaNumber(String viaNumber) {
+ PhoneCallDetails details = getPhoneCallDetails();
+ details.viaNumber = viaNumber;
+ details.accountHandle = new PhoneAccountHandle(new ComponentName("",""), "");
+ mHelper.setPhoneCallDetails(mViews, details);
+ }
+
+ /** Populates the phone call details with the Defaults. */
+ private void setDefaultPhoneCallDetailsNoViaNumber() {
+ PhoneCallDetails details = getPhoneCallDetails();
+ mPhoneUtils.setAccountLabel("");
+ mHelper.setPhoneCallDetails(mViews, details);
+ }
+
/** Sets the phone call details with default values and the given number. */
private void setPhoneCallDetailsWithNumberAndGeocode(
String number, String formattedNumber, String geocodedLocation) {
diff --git a/tests/src/com/android/dialer/calllog/PhoneCallDetailsTest.java b/tests/src/com/android/dialer/calllog/PhoneCallDetailsTest.java
new file mode 100644
index 0000000..5c500d8
--- /dev/null
+++ b/tests/src/com/android/dialer/calllog/PhoneCallDetailsTest.java
@@ -0,0 +1,63 @@
+package com.android.dialer.calllog;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.TtsSpan;
+
+import com.android.dialer.PhoneCallDetails;
+import com.android.dialer.R;
+import com.android.contacts.common.util.ContactDisplayUtils;
+
+/**
+ * Unit tests for {@link PhoneCallDetails}.
+ */
+public class PhoneCallDetailsTest extends AndroidTestCase {
+ private static final String VIA_NUMBER = "+16505551212";
+ private static final String PHONE_ACCOUNT_LABEL = "TEST";
+
+ private Resources mResources;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ }
+
+ @SmallTest
+ public void testCreateAccountLabelDescription_NoViaNumberNoAccountLabel() {
+ CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, "","");
+ assertEquals("", result);
+ }
+
+ @SmallTest
+ public void testCreateAccountLabelDescription_ViaNumberAccountLabel() {
+ String msg = mResources.getString(R.string.description_via_number_phone_account,
+ PHONE_ACCOUNT_LABEL, VIA_NUMBER);
+ CharSequence accountNumberLabel = ContactDisplayUtils.getTelephoneTtsSpannable(msg,
+ VIA_NUMBER);
+ CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, VIA_NUMBER,
+ PHONE_ACCOUNT_LABEL);
+ assertEquals(accountNumberLabel.toString(), result.toString());
+ }
+
+ @SmallTest
+ public void testCreateAccountLabelDescription_ViaNumber() {
+ CharSequence viaNumberLabel = ContactDisplayUtils.getTtsSpannedPhoneNumber(mResources,
+ R.string.description_via_number, VIA_NUMBER);
+ CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, VIA_NUMBER,
+ "");
+ assertEquals(viaNumberLabel.toString(), result.toString());
+ }
+
+ @SmallTest
+ public void testCreateAccountLabelDescription_AccountLabel() {
+ CharSequence accountLabel = TextUtils.expandTemplate(
+ mResources.getString(R.string.description_phone_account), PHONE_ACCOUNT_LABEL);
+ CharSequence result = PhoneCallDetails.createAccountLabelDescription(mResources, "",
+ PHONE_ACCOUNT_LABEL);
+ assertEquals(accountLabel, result);
+ }
+}
diff --git a/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java b/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java
index 077a498..270019a 100644
--- a/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java
+++ b/tests/src/com/android/dialer/calllog/calllogcache/TestTelecomCallLogCache.java
@@ -28,12 +28,15 @@
* but...
* TODO: write tests to test multi-SIM functionality in TelecomCallLogCache.
*/
-public final class TestTelecomCallLogCache extends CallLogCache {
+public class TestTelecomCallLogCache extends CallLogCache {
private CharSequence mVoicemailNumber;
+ private String mAccountLabel;
- public TestTelecomCallLogCache(Context context, CharSequence voicemailNumber) {
+ public TestTelecomCallLogCache(Context context, CharSequence voicemailNumber,
+ String accountLabel) {
super(context);
mVoicemailNumber = voicemailNumber;
+ mAccountLabel = accountLabel;
}
@Override
@@ -43,7 +46,11 @@
@Override
public String getAccountLabel(PhoneAccountHandle accountHandle) {
- return null;
+ return mAccountLabel;
+ }
+
+ public void setAccountLabel(String accountLabel) {
+ mAccountLabel = accountLabel;
}
@Override
diff --git a/tests/src/com/android/dialer/database/DatabaseTestUtils.java b/tests/src/com/android/dialer/database/DatabaseTestUtils.java
index 03b4938..19fff7f 100644
--- a/tests/src/com/android/dialer/database/DatabaseTestUtils.java
+++ b/tests/src/com/android/dialer/database/DatabaseTestUtils.java
@@ -47,20 +47,21 @@
Contacts.STARRED, // 10
Data.IS_SUPER_PRIMARY, // 11
Contacts.IN_VISIBLE_GROUP, // 12
- Data.IS_PRIMARY}); // 13
+ Data.IS_PRIMARY, // 13
+ Data.CARRIER_PRESENCE}); // 14
return cursor;
}
public static ContactNumber constructNewContactWithDummyIds(MatrixCursor contactCursor,
MatrixCursor nameCursor, String number, int id, String displayName) {
return constructNewContact(contactCursor, nameCursor, id, number, id, String.valueOf(id),
- displayName, 0, 0, 0, 0, 0, 0, 0);
+ displayName, 0, 0, 0, 0, 0, 0, 0, 0);
}
public static ContactNumber constructNewContact(MatrixCursor contactCursor,
MatrixCursor nameCursor, int id, String number, int contactId, String lookupKey,
String displayName, int photoId, int lastTimeUsed, int timesUsed, int starred,
- int isSuperPrimary, int inVisibleGroup, int isPrimary) {
+ int isSuperPrimary, int inVisibleGroup, int isPrimary, int carrierPresence) {
if (contactCursor == null || nameCursor == null) {
throw new IllegalArgumentException("Provided MatrixCursors cannot be null");
}
@@ -73,7 +74,7 @@
contactCursor.addRow(new Object[]{id, "", "", number, contactId, lookupKey, displayName,
photoId, lastTimeUsed, timesUsed, starred, isSuperPrimary, inVisibleGroup,
- isPrimary});
+ isPrimary, carrierPresence});
nameCursor.addRow(new Object[]{displayName, contactId});
return new ContactNumber(contactId, id, displayName, number, lookupKey, 0, 0);