Merge "Add CALL_PRIVILEGED" into master-nova
diff --git a/src/com/android/telecomm/Call.java b/src/com/android/telecomm/Call.java
index 0eef378..6aae5ca 100644
--- a/src/com/android/telecomm/Call.java
+++ b/src/com/android/telecomm/Call.java
@@ -28,7 +28,6 @@
import com.google.android.collect.Sets;
import com.google.common.base.Preconditions;
-import java.util.Date;
import java.util.Locale;
import java.util.Set;
@@ -50,7 +49,9 @@
* Beyond logging and such, may also be used for bookkeeping and specifically for marking
* certain call attempts as failed attempts.
*/
- private final Date mCreationTime;
+ private final long mCreationTimeMillis = System.currentTimeMillis();
+
+ private long mConnectTimeMillis;
/** The state of the call. */
private CallState mState;
@@ -86,7 +87,7 @@
* Disconnect cause for the call. Only valid if the state of the call is DISCONNECTED.
* See {@link android.telephony.DisconnectCause}.
*/
- private int mDisconnectCause;
+ private int mDisconnectCause = DisconnectCause.NOT_VALID;
/**
* Additional disconnect information provided by the call service.
@@ -94,7 +95,7 @@
private String mDisconnectMessage;
/** Info used by the call services. */
- private Bundle mExtras;
+ private Bundle mExtras = Bundle.EMPTY;
/** The Uri to dial to perform the handoff. If this is null then handoff is not supported. */
private Uri mHandoffHandle;
@@ -106,6 +107,12 @@
private Call mOriginalCall;
/**
+ * The descriptor for the call service that this call is being switched to, null if handoff is
+ * not in progress.
+ */
+ private CallServiceDescriptor mHandoffCallServiceDescriptor;
+
+ /**
* Creates an empty call object.
*
* @param isIncoming True if this is an incoming call.
@@ -128,9 +135,6 @@
mContactInfo = contactInfo;
mGatewayInfo = gatewayInfo;
mIsIncoming = isIncoming;
- mCreationTime = new Date();
- mDisconnectCause = DisconnectCause.NOT_VALID;
- mExtras = Bundle.EMPTY;
}
/** {@inheritDoc} */
@@ -218,18 +222,27 @@
/**
* @return The "age" of this call object in milliseconds, which typically also represents the
- * period since this call was added to the set pending outgoing calls, see mCreationTime.
+ * period since this call was added to the set pending outgoing calls, see
+ * mCreationTimeMillis.
*/
- long getAgeMs() {
- return new Date().getTime() - mCreationTime.getTime();
+ long getAgeMillis() {
+ return System.currentTimeMillis() - mCreationTimeMillis;
}
/**
* @return The time when this call object was created and added to the set of pending outgoing
* calls.
*/
- long getCreationTimeMs() {
- return mCreationTime.getTime();
+ long getCreationTimeMillis() {
+ return mCreationTimeMillis;
+ }
+
+ long getConnectTimeMillis() {
+ return mConnectTimeMillis;
+ }
+
+ void setConnectTimeMillis(long connectTimeMillis) {
+ mConnectTimeMillis = connectTimeMillis;
}
CallServiceWrapper getCallService() {
@@ -237,13 +250,25 @@
}
void setCallService(CallServiceWrapper callService) {
+ setCallService(callService, null);
+ }
+
+ /**
+ * Changes the call service this call is associated with. If callToReplace is non-null then this
+ * call takes its place within the call service.
+ */
+ void setCallService(CallServiceWrapper callService, Call callToReplace) {
Preconditions.checkNotNull(callService);
clearCallService();
callService.incrementAssociatedCallCount();
mCallService = callService;
- mCallService.addCall(this);
+ if (callToReplace == null) {
+ mCallService.addCall(this);
+ } else {
+ mCallService.replaceCall(this, callToReplace);
+ }
}
/**
@@ -460,6 +485,14 @@
mOriginalCall = originalCall;
}
+ CallServiceDescriptor getHandoffCallServiceDescriptor() {
+ return mHandoffCallServiceDescriptor;
+ }
+
+ void setHandoffCallServiceDescriptor(CallServiceDescriptor descriptor) {
+ mHandoffCallServiceDescriptor = descriptor;
+ }
+
/**
* @return True if the call is ringing, else logs the action name.
*/
diff --git a/src/com/android/telecomm/CallIdMapper.java b/src/com/android/telecomm/CallIdMapper.java
index aec3b5e..a5d70bf 100644
--- a/src/com/android/telecomm/CallIdMapper.java
+++ b/src/com/android/telecomm/CallIdMapper.java
@@ -30,6 +30,14 @@
mCallIdPrefix = callIdPrefix + "@";
}
+ void replaceCall(Call newCall, Call callToReplace) {
+ ThreadUtil.checkOnMainThread();
+
+ // Use the old call's ID for the new call.
+ String callId = getCallId(callToReplace);
+ mCalls.put(callId, newCall);
+ }
+
void addCall(Call call) {
ThreadUtil.checkOnMainThread();
Preconditions.checkNotNull(call);
diff --git a/src/com/android/telecomm/CallLogManager.java b/src/com/android/telecomm/CallLogManager.java
index 8bdc150..fcaf5f2 100644
--- a/src/com/android/telecomm/CallLogManager.java
+++ b/src/com/android/telecomm/CallLogManager.java
@@ -101,8 +101,8 @@
* {@link android.provider.CallLog.Calls#MISSED_TYPE}
*/
private void logCall(Call call, int callLogType) {
- final long creationTime = call.getCreationTimeMs();
- final long age = call.getAgeMs();
+ final long creationTime = call.getCreationTimeMillis();
+ final long age = call.getAgeMillis();
final ContactInfo contactInfo = call.getContactInfo(); // May be null.
final String logNumber = getLogNumber(call);
diff --git a/src/com/android/telecomm/CallServiceRepository.java b/src/com/android/telecomm/CallServiceRepository.java
index 7247259..50ef977 100644
--- a/src/com/android/telecomm/CallServiceRepository.java
+++ b/src/com/android/telecomm/CallServiceRepository.java
@@ -139,7 +139,7 @@
mOutstandingProviders.size());
// Schedule a timeout.
- mHandler.postDelayed(mTimeoutLookupTerminator, Timeouts.getProviderLookupMs());
+ mHandler.postDelayed(mTimeoutLookupTerminator, Timeouts.getProviderLookupMillis());
}
/**
@@ -168,8 +168,8 @@
// TODO(gilad): Either add ICallService.getActiveCallCount() or have this tracked by the
// Switchboard if we rather not rely on 3rd-party code to do the bookkeeping for us. If
- // we prefer the latter, we can also have purgeInactiveCallService(descriptor). Otherwise
- // this might look something like:
+ // we prefer the latter, we can also have purgeInactiveCallService(descriptor).
+ // Otherwise this might look something like:
//
// if (callService.getActiveCallCount() < 1) {
// mCallServices.remove(callServiceName);
diff --git a/src/com/android/telecomm/CallServiceWrapper.java b/src/com/android/telecomm/CallServiceWrapper.java
index 007d35a..70f0ec2 100644
--- a/src/com/android/telecomm/CallServiceWrapper.java
+++ b/src/com/android/telecomm/CallServiceWrapper.java
@@ -28,6 +28,7 @@
import com.android.internal.telecomm.ICallService;
import com.android.internal.telecomm.ICallServiceAdapter;
import com.android.internal.telecomm.ICallServiceProvider;
+import com.google.common.base.Preconditions;
/**
* Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
@@ -253,6 +254,14 @@
mCallIdMapper.addCall(call);
}
+ /**
+ * Associates newCall with this call service by replacing callToReplace.
+ */
+ void replaceCall(Call newCall, Call callToReplace) {
+ Preconditions.checkState(callToReplace.getCallService() == this);
+ mCallIdMapper.replaceCall(newCall, callToReplace);
+ }
+
void removeCall(Call call) {
mAdapter.removePendingCall(call);
mCallIdMapper.removeCall(call);
diff --git a/src/com/android/telecomm/CallsManager.java b/src/com/android/telecomm/CallsManager.java
index b8724e3..d3b22be 100644
--- a/src/com/android/telecomm/CallsManager.java
+++ b/src/com/android/telecomm/CallsManager.java
@@ -23,6 +23,7 @@
import android.telecomm.CallServiceDescriptor;
import android.telecomm.CallState;
import android.telecomm.GatewayInfo;
+import android.telecomm.InCallCall;
import android.telephony.DisconnectCause;
import com.google.common.base.Preconditions;
@@ -51,9 +52,17 @@
void onCallAdded(Call call);
void onCallRemoved(Call call);
void onCallStateChanged(Call call, CallState oldState, CallState newState);
+ void onCallHandoffHandleChanged(Call call, Uri oldHandle, Uri newHandle);
+ void onCallServiceChanged(
+ Call call,
+ CallServiceWrapper oldCallService,
+ CallServiceWrapper newCallService);
+ void onCallHandoffCallServiceDescriptorChanged(
+ Call call,
+ CallServiceDescriptor oldDescriptor,
+ CallServiceDescriptor newDescriptor);
void onIncomingCallAnswered(Call call);
void onIncomingCallRejected(Call call);
- void onCallHandoffHandleChanged(Call call, Uri oldHandle, Uri newHandle);
void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall);
void onAudioStateChanged(CallAudioState oldAudioState, CallAudioState newAudioState);
}
@@ -231,6 +240,15 @@
*/
void handleSuccessfulOutgoingCall(Call call) {
Log.v(this, "handleSuccessfulOutgoingCall, %s", call);
+ if (mCalls.contains(call)) {
+ // The call's CallService has been updated.
+ for (CallsManagerListener listener : mListeners) {
+ listener.onCallServiceChanged(call, null, call.getCallService());
+ }
+ } else if (mPendingHandoffCalls.contains(call)) {
+ updateHandoffCallServiceDescriptor(call.getOriginalCall(),
+ call.getCallService().getDescriptor());
+ }
}
/**
@@ -421,10 +439,13 @@
}
void markCallAsActive(Call call) {
+ if (call.getConnectTimeMillis() == 0) {
+ call.setConnectTimeMillis(System.currentTimeMillis());
+ }
setCallState(call, CallState.ACTIVE);
if (mPendingHandoffCalls.contains(call)) {
- completeHandoff(call);
+ completeHandoff(call, true);
}
}
@@ -442,7 +463,11 @@
void markCallAsDisconnected(Call call, int disconnectCause, String disconnectMessage) {
call.setDisconnectCause(disconnectCause, disconnectMessage);
setCallState(call, CallState.DISCONNECTED);
- removeCall(call);
+
+ // Only remove the call if handoff is not pending.
+ if (call.getHandoffCallServiceDescriptor() == null) {
+ removeCall(call);
+ }
}
void setHandoffInfo(Call call, Uri handle, Bundle extras) {
@@ -496,6 +521,9 @@
}
private void removeCall(Call call) {
+ // If a handoff is pending then the original call shouldn't be removed.
+ Preconditions.checkState(call.getHandoffCallServiceDescriptor() == null);
+
call.clearCallService();
call.clearCallServiceSelector();
@@ -503,10 +531,9 @@
if (mCalls.contains(call)) {
mCalls.remove(call);
shouldNotify = true;
- cleanUpHandoffCallsForOriginalCall(call);
} else if (mPendingHandoffCalls.contains(call)) {
- Log.v(this, "silently removing handoff call %s", call);
- mPendingHandoffCalls.remove(call);
+ Log.v(this, "removeCall, marking handoff call as failed");
+ completeHandoff(call, false);
}
// Only broadcast changes for calls that are being tracked.
@@ -527,6 +554,7 @@
private void setCallState(Call call, CallState newState) {
Preconditions.checkNotNull(newState);
CallState oldState = call.getState();
+ Log.i(this, "setCallState %s -> %s, call: %s", oldState, newState, call);
if (newState != oldState) {
// Unfortunately, in the telephony world the radio is king. So if the call notifies
// us that the call is in a particular state, we allow it even if it doesn't make
@@ -574,45 +602,63 @@
}
}
- private void completeHandoff(Call handoffCall) {
+ private void completeHandoff(Call handoffCall, boolean wasSuccessful) {
Call originalCall = handoffCall.getOriginalCall();
- Log.v(this, "complete handoff, %s -> %s", handoffCall, originalCall);
+ Log.v(this, "complete handoff, %s -> %s, wasSuccessful: %b", handoffCall, originalCall,
+ wasSuccessful);
- // Disconnect.
- originalCall.disconnect();
+ // Remove the transient handoff call object (don't disconnect because the call could still
+ // be live).
+ mPendingHandoffCalls.remove(handoffCall);
- // Synchronize.
- originalCall.setCallService(handoffCall.getCallService());
- setCallState(originalCall, handoffCall.getState());
+ if (wasSuccessful) {
+ // Disconnect.
+ originalCall.disconnect();
- // Remove the transient handoff call object (don't disconnect because the call is still
- // live).
- removeCall(handoffCall);
+ // Synchronize.
+ originalCall.setCallService(handoffCall.getCallService(), handoffCall);
+ setCallState(originalCall, handoffCall.getState());
- // Force the foreground call changed notification to be sent.
- for (CallsManagerListener listener : mListeners) {
- listener.onForegroundCallChanged(mForegroundCall, mForegroundCall);
+ // Force the foreground call changed notification to be sent.
+ for (CallsManagerListener listener : mListeners) {
+ listener.onForegroundCallChanged(mForegroundCall, mForegroundCall);
+ }
+
+ updateHandoffCallServiceDescriptor(originalCall, null);
+ } else {
+ updateHandoffCallServiceDescriptor(originalCall, null);
+ if (originalCall.getState() == CallState.DISCONNECTED ||
+ originalCall.getState() == CallState.ABORTED) {
+ removeCall(originalCall);
+ }
}
}
- /** Makes sure there are no dangling handoff calls. */
- private void cleanUpHandoffCallsForOriginalCall(Call originalCall) {
- for (Call handoffCall : ImmutableList.copyOf((mPendingHandoffCalls))) {
- if (handoffCall.getOriginalCall() == originalCall) {
- Log.d(this, "cancelling handoff call %s for originalCall: %s", handoffCall,
- originalCall);
- if (handoffCall.getState() == CallState.NEW) {
- handoffCall.abort();
- handoffCall.setState(CallState.ABORTED);
- } else {
- handoffCall.disconnect();
- handoffCall.setState(CallState.DISCONNECTED);
- }
- removeCall(handoffCall);
+ private void updateHandoffCallServiceDescriptor(
+ Call originalCall,
+ CallServiceDescriptor newDescriptor) {
+ CallServiceDescriptor oldDescriptor = originalCall.getHandoffCallServiceDescriptor();
+ Log.v(this, "updateHandoffCallServiceDescriptor, call: %s, pending descriptor: %s -> %s",
+ originalCall, oldDescriptor, newDescriptor);
+
+ if (!areDescriptorsEqual(oldDescriptor, newDescriptor)) {
+ originalCall.setHandoffCallServiceDescriptor(newDescriptor);
+ for (CallsManagerListener listener : mListeners) {
+ listener.onCallHandoffCallServiceDescriptorChanged(originalCall, oldDescriptor,
+ newDescriptor);
}
}
}
+ private static boolean areDescriptorsEqual(
+ CallServiceDescriptor descriptor1,
+ CallServiceDescriptor descriptor2) {
+ if (descriptor1 == null) {
+ return descriptor2 == null;
+ }
+ return descriptor1.equals(descriptor2);
+ }
+
private static boolean areUriEqual(Uri handle1, Uri handle2) {
if (handle1 == null) {
return handle2 == null;
diff --git a/src/com/android/telecomm/CallsManagerListenerBase.java b/src/com/android/telecomm/CallsManagerListenerBase.java
index 6144651..8286857 100644
--- a/src/com/android/telecomm/CallsManagerListenerBase.java
+++ b/src/com/android/telecomm/CallsManagerListenerBase.java
@@ -18,6 +18,7 @@
import android.net.Uri;
import android.telecomm.CallAudioState;
+import android.telecomm.CallServiceDescriptor;
import android.telecomm.CallState;
/**
@@ -37,6 +38,24 @@
}
@Override
+ public void onCallHandoffHandleChanged(Call call, Uri oldHandle, Uri newHandle) {
+ }
+
+ @Override
+ public void onCallServiceChanged(
+ Call call,
+ CallServiceWrapper oldCallServiceWrapper,
+ CallServiceWrapper newCallService) {
+ }
+
+ @Override
+ public void onCallHandoffCallServiceDescriptorChanged(
+ Call call,
+ CallServiceDescriptor oldDescriptor,
+ CallServiceDescriptor newDescriptor) {
+ }
+
+ @Override
public void onIncomingCallAnswered(Call call) {
}
@@ -45,10 +64,6 @@
}
@Override
- public void onCallHandoffHandleChanged(Call call, Uri oldHandle, Uri newHandle) {
- }
-
- @Override
public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) {
}
diff --git a/src/com/android/telecomm/InCallController.java b/src/com/android/telecomm/InCallController.java
index beac0d5..395e92e 100644
--- a/src/com/android/telecomm/InCallController.java
+++ b/src/com/android/telecomm/InCallController.java
@@ -24,7 +24,10 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telecomm.CallAudioState;
-import android.telecomm.CallInfo;
+import android.telecomm.CallCapabilities;
+import android.telecomm.CallServiceDescriptor;
+import android.telecomm.CallState;
+import android.telecomm.InCallCall;
import android.telecomm.CallState;
import com.android.internal.telecomm.IInCallService;
@@ -85,9 +88,8 @@
} else {
Log.i(this, "Adding call: %s", call);
mCallIdMapper.addCall(call);
- CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
try {
- mInCallService.addCall(callInfo);
+ mInCallService.addCall(toInCallCall(call));
} catch (RemoteException e) {
}
}
@@ -104,47 +106,28 @@
@Override
public void onCallStateChanged(Call call, CallState oldState, CallState newState) {
- if (mInCallService == null) {
- return;
- }
-
- String callId = mCallIdMapper.getCallId(call);
- switch (newState) {
- case ACTIVE:
- Log.i(this, "Mark call as ACTIVE: %s", callId);
- try {
- mInCallService.setActive(callId);
- } catch (RemoteException e) {
- }
- break;
- case ON_HOLD:
- Log.i(this, "Mark call as HOLD: %s", callId);
- try {
- mInCallService.setOnHold(callId);
- } catch (RemoteException e) {
- }
- break;
- case DISCONNECTED:
- Log.i(this, "Mark call as DISCONNECTED: %s", callId);
- try {
- mInCallService.setDisconnected(callId, call.getDisconnectCause());
- } catch (RemoteException e) {
- }
- break;
- default:
- break;
- }
+ updateCall(call);
}
@Override
public void onCallHandoffHandleChanged(Call call, Uri oldHandle, Uri newHandle) {
- if (mInCallService != null) {
- try {
- mInCallService.setHandoffEnabled(mCallIdMapper.getCallId(call), newHandle != null);
- } catch (RemoteException e) {
- Log.e(this, e, "Exception attempting to call setHandoffEnabled.");
- }
- }
+ updateCall(call);
+ }
+
+ @Override
+ public void onCallServiceChanged(
+ Call call,
+ CallServiceWrapper oldCallServiceWrapper,
+ CallServiceWrapper newCallService) {
+ updateCall(call);
+ }
+
+ @Override
+ public void onCallHandoffCallServiceDescriptorChanged(
+ Call call,
+ CallServiceDescriptor oldDescriptor,
+ CallServiceDescriptor newDescriptor) {
+ updateCall(call);
}
@Override
@@ -219,7 +202,6 @@
if (!calls.isEmpty()) {
for (Call call : calls) {
onCallAdded(call);
- onCallHandoffHandleChanged(call, null, call.getHandoffHandle());
}
onAudioStateChanged(null, CallsManager.getInstance().getAudioState());
} else {
@@ -234,4 +216,36 @@
ThreadUtil.checkOnMainThread();
mInCallService = null;
}
+
+ private void updateCall(Call call) {
+ if (mInCallService != null) {
+ try {
+ mInCallService.updateCall(toInCallCall(call));
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private InCallCall toInCallCall(Call call) {
+ String callId = mCallIdMapper.getCallId(call);
+ CallServiceDescriptor descriptor =
+ call.getCallService() != null ? call.getCallService().getDescriptor() : null;
+
+ boolean isHandoffCapable = call.getHandoffHandle() != null;
+ int capabilities = CallCapabilities.HOLD | CallCapabilities.MUTE;
+ if (call.getHandoffHandle() != null) {
+ capabilities |= CallCapabilities.CONNECTION_HANDOFF;
+ }
+ CallState state = call.getState();
+ if (state == CallState.ABORTED) {
+ state = CallState.DISCONNECTED;
+ }
+ // TODO(sail): Remove this and replace with final reconnecting code.
+ if (state == CallState.DISCONNECTED && call.getHandoffCallServiceDescriptor() != null) {
+ state = CallState.ACTIVE;
+ }
+ return new InCallCall(callId, state, call.getDisconnectCause(), capabilities,
+ call.getConnectTimeMillis(), call.getHandle(), call.getGatewayInfo(), descriptor,
+ call.getHandoffCallServiceDescriptor());
+ }
}
diff --git a/src/com/android/telecomm/InCallTonePlayer.java b/src/com/android/telecomm/InCallTonePlayer.java
index 58e0423..258f8b0 100644
--- a/src/com/android/telecomm/InCallTonePlayer.java
+++ b/src/com/android/telecomm/InCallTonePlayer.java
@@ -65,7 +65,7 @@
// Buffer time (in msec) to add on to the tone timeout value. Needed mainly when the timeout
// value for a tone is exact duration of the tone itself.
- private static final int TIMEOUT_BUFFER_MS = 20;
+ private static final int TIMEOUT_BUFFER_MILLIS = 20;
// The tone state.
private static final int STATE_OFF = 0;
@@ -109,19 +109,19 @@
final int toneType; // Passed to ToneGenerator.startTone.
final int toneVolume; // Passed to the ToneGenerator constructor.
- final int toneLengthMs;
+ final int toneLengthMillis;
switch (mToneId) {
case TONE_BUSY:
// TODO: CDMA-specific tones
toneType = ToneGenerator.TONE_SUP_BUSY;
toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMs = 4000;
+ toneLengthMillis = 4000;
break;
case TONE_CALL_ENDED:
toneType = ToneGenerator.TONE_PROP_PROMPT;
toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMs = 4000;
+ toneLengthMillis = 4000;
break;
case TONE_OTA_CALL_ENDED:
// TODO: fill in
@@ -132,42 +132,42 @@
case TONE_CDMA_DROP:
toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
toneVolume = RELATIVE_VOLUME_LOPRI;
- toneLengthMs = 375;
+ toneLengthMillis = 375;
break;
case TONE_CONGESTION:
toneType = ToneGenerator.TONE_SUP_CONGESTION;
toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMs = 4000;
+ toneLengthMillis = 4000;
break;
case TONE_INTERCEPT:
toneType = ToneGenerator.TONE_CDMA_ABBR_INTERCEPT;
toneVolume = RELATIVE_VOLUME_LOPRI;
- toneLengthMs = 500;
+ toneLengthMillis = 500;
break;
case TONE_OUT_OF_SERVICE:
toneType = ToneGenerator.TONE_CDMA_CALLDROP_LITE;
toneVolume = RELATIVE_VOLUME_LOPRI;
- toneLengthMs = 375;
+ toneLengthMillis = 375;
break;
case TONE_REDIAL:
toneType = ToneGenerator.TONE_CDMA_ALERT_AUTOREDIAL_LITE;
toneVolume = RELATIVE_VOLUME_LOPRI;
- toneLengthMs = 5000;
+ toneLengthMillis = 5000;
break;
case TONE_REORDER:
toneType = ToneGenerator.TONE_CDMA_REORDER;
toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMs = 5000;
+ toneLengthMillis = 5000;
break;
case TONE_RING_BACK:
toneType = ToneGenerator.TONE_SUP_RINGTONE;
toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMs = Integer.MAX_VALUE - TIMEOUT_BUFFER_MS;
+ toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
break;
case TONE_UNOBTAINABLE_NUMBER:
toneType = ToneGenerator.TONE_SUP_ERROR;
toneVolume = RELATIVE_VOLUME_HIPRI;
- toneLengthMs = 4000;
+ toneLengthMillis = 4000;
break;
case TONE_VOICE_PRIVACY:
// TODO: fill in.
@@ -202,8 +202,8 @@
toneGenerator.startTone(toneType);
try {
Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
- toneLengthMs + TIMEOUT_BUFFER_MS);
- wait(toneLengthMs + TIMEOUT_BUFFER_MS);
+ toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
+ wait(toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
} catch (InterruptedException e) {
Log.w(this, "wait interrupted", e);
}
diff --git a/src/com/android/telecomm/MissedCallNotifier.java b/src/com/android/telecomm/MissedCallNotifier.java
index 8100472..9414030 100644
--- a/src/com/android/telecomm/MissedCallNotifier.java
+++ b/src/com/android/telecomm/MissedCallNotifier.java
@@ -106,7 +106,7 @@
// Create the notification.
Notification.Builder builder = new Notification.Builder(mContext);
builder.setSmallIcon(android.R.drawable.stat_notify_missed_call)
- .setWhen(call.getCreationTimeMs())
+ .setWhen(call.getCreationTimeMillis())
.setContentTitle(mContext.getText(titleResId))
.setContentText(expandedText)
.setContentIntent(createCallLogPendingIntent())
diff --git a/src/com/android/telecomm/Switchboard.java b/src/com/android/telecomm/Switchboard.java
index 66e1269..bd6b449 100644
--- a/src/com/android/telecomm/Switchboard.java
+++ b/src/com/android/telecomm/Switchboard.java
@@ -264,7 +264,7 @@
* Schedules the next tick invocation.
*/
private void scheduleNextTick() {
- mHandler.postDelayed(mTicker, Timeouts.getTickMs());
+ mHandler.postDelayed(mTicker, Timeouts.getTickMillis());
}
/**
@@ -359,11 +359,11 @@
return;
}
- final long newCallTimeoutMs = Timeouts.getNewOutgoingCallMs();
+ final long newCallTimeoutMillis = Timeouts.getNewOutgoingCallMillis();
Iterator<Call> iterator = calls.iterator();
while (iterator.hasNext()) {
Call call = iterator.next();
- if (call.getAgeMs() >= newCallTimeoutMs) {
+ if (call.getAgeMillis() >= newCallTimeoutMillis) {
Log.d(this, "Call %s timed out.", call);
mOutgoingCallsManager.abort(call);
calls.remove(call);
diff --git a/src/com/android/telecomm/TelephonyUtil.java b/src/com/android/telecomm/TelephonyUtil.java
index be501f0..bffe7eb 100644
--- a/src/com/android/telecomm/TelephonyUtil.java
+++ b/src/com/android/telecomm/TelephonyUtil.java
@@ -26,7 +26,7 @@
* differently from 3rd party services in some situations (emergency calls, audio focus, etc...).
*/
public final class TelephonyUtil {
- private static final String TAG = ThreadUtil.class.getSimpleName();
+ private static final String TAG = TelephonyUtil.class.getSimpleName();
private static final String TELEPHONY_PACKAGE_NAME =
"com.android.phone";
diff --git a/src/com/android/telecomm/Timeouts.java b/src/com/android/telecomm/Timeouts.java
index 4096c02..4f8dc1c 100644
--- a/src/com/android/telecomm/Timeouts.java
+++ b/src/com/android/telecomm/Timeouts.java
@@ -49,14 +49,14 @@
* @return The longest period in milliseconds each {@link CallServiceProvider} lookup cycle is
* allowed to span over.
*/
- public static long getProviderLookupMs() {
+ public static long getProviderLookupMillis() {
return get("provider_lookup_ms", 1000);
}
/**
* @return How frequently, in milliseconds, to run {@link Switchboard}'s clean-up "tick" cycle.
*/
- public static long getTickMs() {
+ public static long getTickMillis() {
return get("tick_ms", 250);
}
@@ -67,7 +67,7 @@
* @return The longest period, in milliseconds, each new call is allowed to wait before being
* established.
*/
- public static long getNewOutgoingCallMs() {
+ public static long getNewOutgoingCallMillis() {
return get("new_outgoing_call_ms", 5000);
}
}
diff --git a/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java b/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java
index a186e58..e88c293 100644
--- a/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java
+++ b/tests/src/com/android/telecomm/testcallservice/CallServiceNotifier.java
@@ -26,12 +26,10 @@
import android.util.Log;
/**
- * Class used to create, update and cancel the notification used to display and update call state for
- * {@link TestCallService}.
+ * Class used to create, update and cancel the notification used to display and update call state
+ * for {@link TestCallService}.
*/
public class CallServiceNotifier {
- private static final String TAG = CallServiceNotifier.class.getSimpleName();
-
private static final CallServiceNotifier INSTANCE = new CallServiceNotifier();
/**
@@ -56,7 +54,7 @@
* Updates the notification in the notification pane.
*/
public void updateNotification(Context context) {
- Log.i("CallServiceNotifier", "adding the notification ------------");
+ log("adding the notification ------------");
getNotificationManager(context).notify(CALL_NOTIFICATION_ID, getNotification(context));
}
@@ -64,7 +62,7 @@
* Cancels the notification.
*/
public void cancelNotification(Context context) {
- Log.i(TAG, "canceling notification");
+ log("canceling notification");
getNotificationManager(context).cancel(CALL_NOTIFICATION_ID);
}
@@ -110,7 +108,7 @@
* Creates the intent to add an incoming call through Telecomm.
*/
private PendingIntent createIncomingCallIntent(Context context) {
- Log.i(TAG, "Creating incoming call pending intent.");
+ log("Creating incoming call pending intent.");
// Build descriptor for TestCallService.
CallServiceDescriptor.Builder descriptorBuilder = CallServiceDescriptor.newBuilder(context);
descriptorBuilder.setCallService(TestCallService.class);
@@ -141,4 +139,8 @@
private void addExitAction(Notification.Builder builder, Context context) {
builder.addAction(0, "Exit", createExitIntent(context));
}
+
+ private static void log(String msg) {
+ Log.w("testcallservice", "[CallServiceNotifier] " + msg);
+ }
}
diff --git a/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java b/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
index c267867..86319a4 100644
--- a/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
+++ b/tests/src/com/android/telecomm/testcallservice/DummyCallServiceSelector.java
@@ -16,33 +16,100 @@
package com.android.telecomm.testcallservice;
+import android.net.Uri;
+import android.os.Bundle;
import android.telecomm.CallInfo;
import android.telecomm.CallServiceDescriptor;
import android.telecomm.CallServiceSelector;
import android.telecomm.CallServiceSelectorAdapter;
+import android.util.Log;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
-/**
- * Dummy call-service selector which returns the list of call services in the same order in which it
- * was given. Also returns false for every request on switchability.
- */
+/** Simple selector to exercise Telecomm code. */
public class DummyCallServiceSelector extends CallServiceSelector {
+ private static DummyCallServiceSelector sInstance;
+ private static final String SCHEME_TEL = "tel";
+ private static final String TELEPHONY_PACKAGE_NAME =
+ "com.android.phone";
+ private static final String CUSTOM_HANDOFF_KEY = "custom_handoff_key";
+ private static final String CUSTOM_HANDOFF_VALUE = "custom_handoff_value";
+
+ public DummyCallServiceSelector() {
+ log("constructor");
+ Preconditions.checkState(sInstance == null);
+ sInstance = this;
+ }
+
+ static DummyCallServiceSelector getInstance() {
+ Preconditions.checkNotNull(sInstance);
+ return sInstance;
+ }
@Override
protected void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
+ log("select");
List<CallServiceDescriptor> orderedList = Lists.newLinkedList();
- // Make sure that the test call services are the only ones
+ boolean shouldHandoffToPstn = false;
+ if (callInfo.getCurrentCallServiceDescriptor() != null) {
+ // If the current call service is TestCallService then handoff to PSTN, otherwise
+ // handoff to TestCallService.
+ shouldHandoffToPstn = isTestCallService(callInfo.getCurrentCallServiceDescriptor());
+ String extraValue = callInfo.getExtras().getString(CUSTOM_HANDOFF_KEY);
+ log("handing off, toPstn: " + shouldHandoffToPstn + ", extraValue: " + extraValue);
+ Preconditions.checkState(CUSTOM_HANDOFF_VALUE.equals(extraValue));
+ }
+
for (CallServiceDescriptor descriptor : descriptors) {
- String packageName = descriptor.getServiceComponent().getPackageName();
- if (getPackageName().equals(packageName)) {
+ if (isTestCallService(descriptor) && !shouldHandoffToPstn) {
+ orderedList.add(0, descriptor);
+ } else if (isPstnCallService(descriptor)) {
orderedList.add(descriptor);
+ } else {
+ log("skipping call service: " + descriptor.getServiceComponent());
}
}
getAdapter().setSelectedCallServices(callInfo.getId(), orderedList);
}
+
+ void sendHandoffInfo(Uri remoteHandle, Uri handoffHandle) {
+ log("sendHandoffInfo");
+ String callId = findMatchingCall(remoteHandle);
+ Preconditions.checkNotNull(callId);
+ Bundle extras = new Bundle();
+ extras.putString(CUSTOM_HANDOFF_KEY, CUSTOM_HANDOFF_VALUE);
+ getAdapter().setHandoffInfo(callId, handoffHandle, extras);
+ }
+
+ private String findMatchingCall(Uri remoteHandle) {
+ for (CallInfo callInfo : getCalls()) {
+ if (remoteHandle.equals(callInfo.getOriginalHandle())) {
+ return callInfo.getId();
+ }
+ }
+ return null;
+ }
+
+ private boolean isTestCallService(CallServiceDescriptor descriptor) {
+ if (descriptor == null) {
+ return false;
+ }
+ return getPackageName().equals(descriptor.getServiceComponent().getPackageName());
+ }
+
+ private boolean isPstnCallService(CallServiceDescriptor descriptor) {
+ if (descriptor == null) {
+ return false;
+ }
+ return TELEPHONY_PACKAGE_NAME.equals(descriptor.getServiceComponent().getPackageName());
+ }
+
+ private static void log(String msg) {
+ Log.w("testcallservice", "[DummyCallServiceSelector] " + msg);
+ }
}
diff --git a/tests/src/com/android/telecomm/testcallservice/TestCallService.java b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
index f6e2da7..275c208 100644
--- a/tests/src/com/android/telecomm/testcallservice/TestCallService.java
+++ b/tests/src/com/android/telecomm/testcallservice/TestCallService.java
@@ -20,6 +20,7 @@
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.telecomm.CallAudioState;
import android.telecomm.CallInfo;
import android.telecomm.CallService;
@@ -31,35 +32,27 @@
import com.android.telecomm.tests.R;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Maps;
-import java.util.Set;
+import java.util.Map;
/**
* Service which provides fake calls to test the ICallService interface.
* TODO(santoscordon): Rename all classes in the directory to Dummy* (e.g., DummyCallService).
*/
public class TestCallService extends CallService {
- private static final String TAG = TestCallService.class.getSimpleName();
+ private static final String SCHEME_TEL = "tel";
- /**
- * Set of call IDs for live (active, ringing, dialing) calls.
- * TODO(santoscordon): Reference CallState javadoc when available for the different call states.
- */
- private Set<String> mLiveCallIds;
+ private final Map<String, CallInfo> mCalls = Maps.newHashMap();
+ private final Handler mHandler = new Handler();
- /**
- * Used to play an audio tone during a call.
- */
+ /** Used to play an audio tone during a call. */
private MediaPlayer mMediaPlayer;
/** {@inheritDoc} */
@Override
public void onAdapterAttached(CallServiceAdapter callServiceAdapter) {
- Log.i(TAG, "setCallServiceAdapter()");
-
- mLiveCallIds = Sets.newHashSet();
-
+ log("onAdapterAttached");
mMediaPlayer = createMediaPlayer();
}
@@ -71,75 +64,79 @@
*/
@Override
public void isCompatibleWith(CallInfo callInfo) {
- Log.i(TAG, "isCompatibleWith(" + callInfo + ")");
+ log("isCompatibleWith, callInfo: " + callInfo);
Preconditions.checkNotNull(callInfo.getHandle());
// Is compatible if the handle doesn't start with 7.
boolean isCompatible = !callInfo.getHandle().getSchemeSpecificPart().startsWith("7");
- // Tell CallsManager whether this call service can place the call (is compatible).
- // Returning positively on setCompatibleWith() doesn't guarantee that we will be chosen
- // to place the call. If we *are* chosen then CallsManager will execute the call()
- // method below.
+ // Tell CallsManager whether this call service can place the call.
getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
}
/**
- * Starts a call by calling into the adapter. For testing purposes this methods acts as if a
- * call was successfully connected every time.
+ * Starts a call by calling into the adapter.
*
* {@inheritDoc}
*/
@Override
- public void call(CallInfo callInfo) {
+ public void call(final CallInfo callInfo) {
String number = callInfo.getHandle().getSchemeSpecificPart();
- Log.i(TAG, "call(" + number + ")");
+ log("call, number: " + number);
// Crash on 555-DEAD to test call service crashing.
if ("5550340".equals(number)) {
throw new RuntimeException("Goodbye, cruel world.");
}
- createCall(callInfo.getId());
+ mCalls.put(callInfo.getId(), callInfo);
getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ activateCall(callInfo.getId());
+ }
+ }, 4000);
}
/** {@inheritDoc} */
@Override
public void abort(String callId) {
- Log.i(TAG, "abort(" + callId + ")");
+ log("abort, callId: " + callId);
destroyCall(callId);
}
/** {@inheritDoc} */
@Override
public void setIncomingCallId(String callId, Bundle extras) {
- Log.i(TAG, "setIncomingCallId(" + callId + ", " + extras + ")");
+ log("setIncomingCallId, callId: " + callId + " extras: " + extras);
// Use dummy number for testing incoming calls.
- Uri handle = Uri.fromParts("tel", "5551234", null);
+ Uri handle = Uri.fromParts(SCHEME_TEL, "5551234", null);
CallInfo callInfo = new CallInfo(callId, CallState.RINGING, handle);
+ mCalls.put(callInfo.getId(), callInfo);
getAdapter().notifyIncomingCall(callInfo);
}
/** {@inheritDoc} */
@Override
public void answer(String callId) {
- getAdapter().setActive(callId);
- createCall(callId);
+ log("answer, callId: " + callId);
+ activateCall(callId);
}
/** {@inheritDoc} */
@Override
public void reject(String callId) {
+ log("reject, callId: " + callId);
getAdapter().setDisconnected(callId, DisconnectCause.INCOMING_REJECTED, null);
}
/** {@inheritDoc} */
@Override
public void disconnect(String callId) {
- Log.i(TAG, "disconnect(" + callId + ")");
+ log("disconnect, callId: " + callId);
destroyCall(callId);
getAdapter().setDisconnected(callId, DisconnectCause.LOCAL, null);
@@ -148,55 +145,45 @@
/** {@inheritDoc} */
@Override
public void hold(String callId) {
- Log.i(TAG, "hold(" + callId + ")");
+ log("hold, callId: " + callId);
getAdapter().setOnHold(callId);
}
/** {@inheritDoc} */
@Override
public void unhold(String callId) {
- Log.i(TAG, "unhold(" + callId + ")");
+ log("unhold, callId: " + callId);
getAdapter().setActive(callId);
}
/** {@inheritDoc} */
@Override
public void playDtmfTone(String callId, char digit) {
- Log.i(TAG, "playDtmfTone(" + callId + "," + digit + ")");
- // TODO(ihab): Implement
+ log("playDtmfTone, callId: " + callId + " digit: " + digit);
}
/** {@inheritDoc} */
@Override
public void stopDtmfTone(String callId) {
- Log.i(TAG, "stopDtmfTone(" + callId + ")");
- // TODO(ihab): Implement
+ log("stopDtmfTone, callId: " + callId);
}
/** {@inheritDoc} */
@Override
public void onAudioStateChanged(String callId, CallAudioState audioState) {
+ log("onAudioStateChanged, callId: " + callId + " audioState: " + audioState);
}
/** {@inheritDoc} */
@Override
public boolean onUnbind(Intent intent) {
+ log("onUnbind");
mMediaPlayer = null;
-
return super.onUnbind(intent);
}
- /**
- * Adds the specified call ID to the set of live call IDs and starts playing audio on the
- * voice-call stream.
- *
- * @param callId The identifier of the call to create.
- */
- private void createCall(String callId) {
- Preconditions.checkState(!Strings.isNullOrEmpty(callId));
- mLiveCallIds.add(callId);
-
- // Starts audio if not already started.
+ private void activateCall(String callId) {
+ getAdapter().setActive(callId);
if (!mMediaPlayer.isPlaying()) {
mMediaPlayer.start();
}
@@ -210,10 +197,10 @@
*/
private void destroyCall(String callId) {
Preconditions.checkState(!Strings.isNullOrEmpty(callId));
- mLiveCallIds.remove(callId);
+ mCalls.remove(callId);
// Stops audio if there are no more calls.
- if (mLiveCallIds.isEmpty() && mMediaPlayer.isPlaying()) {
+ if (mCalls.isEmpty() && mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = createMediaPlayer();
@@ -227,4 +214,7 @@
return mediaPlayer;
}
+ private static void log(String msg) {
+ Log.w("testcallservice", "[TestCallService] " + msg);
+ }
}
diff --git a/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java b/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java
index 781f629..3a6646c 100644
--- a/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java
+++ b/tests/src/com/android/telecomm/testcallservice/TestCallServiceProvider.java
@@ -28,12 +28,10 @@
* TODO(santoscordon): Build more dummy providers for more CallServiceDescriptor.FLAG_* types.
*/
public class TestCallServiceProvider extends CallServiceProvider {
- private static final String TAG = TestCallServiceProvider.class.getSimpleName();
-
/** {@inheritDoc} */
@Override
public void lookupCallServices(CallServiceLookupResponse response) {
- Log.i(TAG, "lookupCallServices()");
+ log("lookupCallServices");
CallServiceDescriptor.Builder builder = CallServiceDescriptor.newBuilder(this);
builder.setCallService(TestCallService.class);
@@ -41,4 +39,8 @@
response.setCallServiceDescriptors(Lists.newArrayList(builder.build()));
}
+
+ private static void log(String msg) {
+ Log.w("testcallservice", "[TestCallServiceProvider] " + msg);
+ }
}