summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--InCallUI/src/com/android/incallui/AudioModeProvider.java2
-rw-r--r--InCallUI/src/com/android/incallui/Call.java19
-rw-r--r--InCallUI/src/com/android/incallui/InCallPresenter.java26
-rw-r--r--InCallUI/src/com/android/incallui/InCallServiceImpl.java9
-rw-r--r--InCallUI/tests/src/com/android/incallui/InCallPresenterTest.java177
5 files changed, 223 insertions, 10 deletions
diff --git a/InCallUI/src/com/android/incallui/AudioModeProvider.java b/InCallUI/src/com/android/incallui/AudioModeProvider.java
index c823fda3c..a26766126 100644
--- a/InCallUI/src/com/android/incallui/AudioModeProvider.java
+++ b/InCallUI/src/com/android/incallui/AudioModeProvider.java
@@ -26,7 +26,7 @@ import java.util.List;
/**
* Proxy class for getting and setting the audio mode.
*/
-/* package */ class AudioModeProvider implements InCallPhoneListener {
+public class AudioModeProvider implements InCallPhoneListener {
static final int AUDIO_MODE_INVALID = 0;
diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java
index 663c4120a..16e4a2c76 100644
--- a/InCallUI/src/com/android/incallui/Call.java
+++ b/InCallUI/src/com/android/incallui/Call.java
@@ -17,6 +17,7 @@
package com.android.incallui;
import com.android.contacts.common.CallUtil;
+import com.android.contacts.common.testing.NeededForTesting;
import android.content.Context;
import android.net.Uri;
@@ -187,6 +188,16 @@ public final class Call {
private InCallVideoCallListener mVideoCallListener;
+ /**
+ * Used only to create mock calls for testing
+ */
+ @NeededForTesting
+ Call(int state) {
+ mTelecommCall = null;
+ mId = ID_PREFIX + Integer.toString(sIdCounter++);
+ setState(state);
+ }
+
public Call(android.telecom.Call telecommCall) {
mTelecommCall = telecommCall;
mId = ID_PREFIX + Integer.toString(sIdCounter++);
@@ -270,7 +281,7 @@ public final class Call {
}
public int getState() {
- if (mTelecommCall.getParent() != null) {
+ if (mTelecommCall != null && mTelecommCall.getParent() != null) {
return State.CONFERENCED;
} else {
return mState;
@@ -401,6 +412,12 @@ public final class Call {
@Override
public String toString() {
+ if (mTelecommCall == null) {
+ // This should happen only in testing since otherwise we would never have a null
+ // Telecom call.
+ return String.valueOf(mId);
+ }
+
return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s, conferenceable:%s, " +
"videoState:%d]",
mId,
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index 0343ed6ca..e90dc99a5 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -37,6 +37,7 @@ import android.view.View;
import com.google.common.base.Preconditions;
import com.android.contacts.common.interactions.TouchPointManager;
+import com.android.contacts.common.testing.NeededForTesting;
import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
import com.android.incalluibind.ObjectFactory;
@@ -187,6 +188,11 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener,
return sInCallPresenter;
}
+ @NeededForTesting
+ static synchronized void setInstance(InCallPresenter inCallPresenter) {
+ sInCallPresenter = inCallPresenter;
+ }
+
@Override
public void setPhone(Phone phone) {
mPhone = phone;
@@ -207,7 +213,12 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener,
return mCallList;
}
- public void setUp(Context context, CallList callList, AudioModeProvider audioModeProvider) {
+ public void setUp(Context context,
+ CallList callList,
+ AudioModeProvider audioModeProvider,
+ StatusBarNotifier statusBarNotifier,
+ ContactInfoCache contactInfoCache,
+ ProximitySensor proximitySensor) {
if (mServiceConnected) {
Log.i(this, "New service connection replacing existing one.");
// retain the current resources, no need to create new ones.
@@ -220,14 +231,14 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener,
Preconditions.checkNotNull(context);
mContext = context;
- mContactInfoCache = ContactInfoCache.getInstance(context);
+ mContactInfoCache = contactInfoCache;
- mStatusBarNotifier = new StatusBarNotifier(context, mContactInfoCache);
+ mStatusBarNotifier = statusBarNotifier;
addListener(mStatusBarNotifier);
mAudioModeProvider = audioModeProvider;
- mProximitySensor = new ProximitySensor(context, mAudioModeProvider);
+ mProximitySensor = proximitySensor;
addListener(mProximitySensor);
mCallList = callList;
@@ -918,8 +929,9 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener,
// [ AND NOW YOU'RE IN THE CALL. voila! ]
//
// Our app is started using a fullScreen notification. We need to do this whenever
- // we get an incoming call.
- final boolean startStartupSequence = (InCallState.INCOMING == newState);
+ // we get an incoming call. Depending on the current context of the device, either a
+ // incoming call HUN or the actual InCallActivity will be shown.
+ final boolean startIncomingCallSequence = (InCallState.INCOMING == newState);
// A dialog to show on top of the InCallUI to select a PhoneAccount
final boolean showAccountPicker = (InCallState.WAITING_FOR_ACCOUNT == newState);
@@ -967,7 +979,7 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener,
if (showCallUi || showAccountPicker) {
Log.i(this, "Start in call UI");
showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
- } else if (startStartupSequence) {
+ } else if (startIncomingCallSequence) {
Log.i(this, "Start Full Screen in call UI");
// We're about the bring up the in-call UI for an incoming call. If we still have
diff --git a/InCallUI/src/com/android/incallui/InCallServiceImpl.java b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
index 17f4e174d..adb069784 100644
--- a/InCallUI/src/com/android/incallui/InCallServiceImpl.java
+++ b/InCallUI/src/com/android/incallui/InCallServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.incallui;
+import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.telecom.InCallService;
@@ -53,10 +54,16 @@ public class InCallServiceImpl extends InCallService {
@Override
public IBinder onBind(Intent intent) {
+ final Context context = getApplicationContext();
+ final ContactInfoCache contactInfoCache = ContactInfoCache.getInstance(context);
InCallPresenter.getInstance().setUp(
getApplicationContext(),
CallList.getInstance(),
- AudioModeProvider.getInstance());
+ AudioModeProvider.getInstance(),
+ new StatusBarNotifier(context, contactInfoCache),
+ contactInfoCache,
+ new ProximitySensor(context, AudioModeProvider.getInstance())
+ );
InCallPresenter.getInstance().onServiceBind();
InCallPresenter.getInstance().maybeStartRevealAnimation(intent);
return super.onBind(intent);
diff --git a/InCallUI/tests/src/com/android/incallui/InCallPresenterTest.java b/InCallUI/tests/src/com/android/incallui/InCallPresenterTest.java
new file mode 100644
index 000000000..6d6087615
--- /dev/null
+++ b/InCallUI/tests/src/com/android/incallui/InCallPresenterTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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 static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.test.InstrumentationTestCase;
+
+import com.android.incallui.InCallPresenter.InCallState;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+public class InCallPresenterTest extends InstrumentationTestCase {
+ private static final Call TEST_INCOMING_CALL = new Call(Call.State.INCOMING);
+ private static final Call TEST_ACTIVE_CALL = new Call(Call.State.ACTIVE);
+ private static final Call TEST_PENDING_CALL = new Call(Call.State.CONNECTING);
+ private static final Call TEST_WAITING_FOR_ACCOUNT_CALL = new Call(Call.State.PRE_DIAL_WAIT);
+
+ @Mock private InCallActivity mInCallActivity;
+ @Mock private AudioModeProvider mAudioModeProvider;
+ @Mock private CallList mCallList;
+ @Mock private StatusBarNotifier mStatusBarNotifier;
+ @Mock private ContactInfoCache mContactInfoCache;
+ @Mock private ProximitySensor mProximitySensor;
+
+ InCallPresenter mInCallPresenter;
+ @Mock private Context mContext;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ System.setProperty("dexmaker.dexcache",
+ getInstrumentation().getTargetContext().getCacheDir().getPath());
+ MockitoAnnotations.initMocks(this);
+ mInCallPresenter = InCallPresenter.getInstance();
+ mInCallPresenter.setUp(mContext, mCallList, mAudioModeProvider, mStatusBarNotifier,
+ mContactInfoCache, mProximitySensor);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ // The tear down method needs to run in the main thread since there is an explicit check
+ // inside TelecomAdapter.getInstance().
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mInCallPresenter.unsetActivity(mInCallActivity);
+ mInCallPresenter.tearDown();
+ InCallPresenter.setInstance(null);
+ }
+ });
+ }
+
+ public void testOnActivitySet_finishesActivityWhenNoCalls() {
+ mInCallPresenter.setActivity(mInCallActivity);
+
+ verify(mInCallActivity).finish();
+ }
+
+ public void testOnCallListChange_sendsNotificationWhenInCall() {
+ when(mCallList.getIncomingCall()).thenReturn(TEST_INCOMING_CALL);
+
+ mInCallPresenter.onCallListChange(mCallList);
+
+ verify(mStatusBarNotifier).updateNotification(InCallState.INCOMING, mCallList);
+ verifyInCallActivityNotStarted();
+ }
+
+ /**
+ * This behavior is required to ensure that the screen is turned on again by the restarting
+ * activity.
+ */
+ public void testOnCallListChange_handlesCallWaitingWhenScreenOffShouldRestartActivity() {
+ when(mCallList.getActiveCall()).thenReturn(TEST_ACTIVE_CALL);
+
+ mInCallPresenter.onCallListChange(mCallList);
+ mInCallPresenter.setActivity(mInCallActivity);
+
+ // Pretend that there is a call waiting and the screen is off
+ when(mInCallActivity.isDestroyed()).thenReturn(false);
+ when(mInCallActivity.isFinishing()).thenReturn(false);
+ when(mProximitySensor.isScreenReallyOff()).thenReturn(true);
+ when(mCallList.getIncomingCall()).thenReturn(TEST_INCOMING_CALL);
+
+ mInCallPresenter.onCallListChange(mCallList);
+ verify(mInCallActivity).finish();
+ }
+
+ /**
+ * Verifies that the PENDING_OUTGOING -> IN_CALL transition brings up InCallActivity so
+ * that it can display an error dialog.
+ */
+ public void testOnCallListChange_pendingOutgoingToInCallTransitionShowsUiForErrorDialog() {
+ when(mCallList.getPendingOutgoingCall()).thenReturn(TEST_PENDING_CALL);
+
+ mInCallPresenter.onCallListChange(mCallList);
+
+ when(mCallList.getPendingOutgoingCall()).thenReturn(null);
+ when(mCallList.getActiveCall()).thenReturn(TEST_ACTIVE_CALL);
+
+ mInCallPresenter.onCallListChange(mCallList);
+
+ verify(mContext).startActivity(InCallPresenter.getInstance().getInCallIntent(false, false));
+ verifyIncomingCallNotificationNotSent();
+ }
+
+ /**
+ * Verifies that if there is a call in the PRE_DIAL_WAIT state, InCallActivity is displayed
+ * to display the account picker.
+ */
+ public void testOnCallListChange_noAccountProvidedForCallShowsUiForAccountPicker() {
+ when(mCallList.getWaitingForAccountCall()).thenReturn(TEST_WAITING_FOR_ACCOUNT_CALL);
+ mInCallPresenter.onCallListChange(mCallList);
+
+ verify(mContext).startActivity(InCallPresenter.getInstance().getInCallIntent(false, false));
+ verifyIncomingCallNotificationNotSent();
+ }
+
+ /**
+ * Verifies that for an expected call state change (e.g. NO_CALLS -> PENDING_OUTGOING),
+ * InCallActivity is not displayed.
+ */
+ public void testOnCallListChange_noCallsToPendingOutgoingDoesNotShowUi() {
+ when(mCallList.getPendingOutgoingCall()).thenReturn(TEST_PENDING_CALL);
+ mInCallPresenter.onCallListChange(mCallList);
+
+ verifyInCallActivityNotStarted();
+ verifyIncomingCallNotificationNotSent();
+ }
+
+
+ //TODO
+ public void testCircularReveal_startsCircularRevealForOutgoingCalls() {
+
+ }
+
+ public void testCircularReveal_waitTillCircularRevealSentBeforeShowingCallCard() {
+ }
+
+ public void testHangupOngoingCall_disconnectsCallCorrectly() {
+ }
+
+ public void testAnswerIncomingCall() {
+ }
+
+ public void testDeclineIncomingCall() {
+ }
+
+ private void verifyInCallActivityNotStarted() {
+ verify(mContext, never()).startActivity(Mockito.any(Intent.class));
+ }
+
+ private void verifyIncomingCallNotificationNotSent() {
+ verify(mStatusBarNotifier, never()).updateNotification(Mockito.any(InCallState.class),
+ Mockito.any(CallList.class));
+ }
+}