Merge "Revert submission"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..75feeb6
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,20 @@
+{
+ "presubmit": [
+ {
+ "name": "TelecomUnitTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "TeleServiceTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/res/values/config.xml b/res/values/config.xml
index 5b9636d..9cbbf46 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -53,11 +53,6 @@
Devices should overlay this value based on the type of vibration hardware they employ. -->
<bool name="use_simple_vibration_pattern">false</bool>
- <!-- When true, if Telecom is playing the ringtone, it will attempt to pause for some time
- between repeats of the ringtone.
- When false, the ringtone will be looping with no pause. -->
- <bool name="should_pause_between_ringtone_repeats">true</bool>
-
<!-- Threshold for the X+Y component of gravity needed for the device orientation to be
classified as being on a user's ear. -->
<item name="device_on_ear_xy_gravity_threshold" format="float" type="dimen">5.5</item>
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index 8f11882..1a7d0f7 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -43,10 +43,6 @@
// Message codes used with the ringtone thread.
private static final int EVENT_PLAY = 1;
private static final int EVENT_STOP = 2;
- private static final int EVENT_REPEAT = 3;
-
- // The interval in which to restart the ringer.
- private static final int RESTART_RINGER_MILLIS = 3000;
/** Handler running on the ringtone thread. */
private Handler mHandler;
@@ -60,26 +56,10 @@
*/
private CompletableFuture<Boolean> mHapticsFuture = null;
- /**
- * Determines if the {@link AsyncRingtonePlayer} should pause between repeats of the ringtone.
- * When {@code true}, the system will check if the ringtone has stopped every
- * {@link #RESTART_RINGER_MILLIS} and restart the ringtone if it has stopped. This does not
- * guarantee that there is {@link #RESTART_RINGER_MILLIS} between each repeat of the ringtone,
- * rather it ensures that for short ringtones, or ringtones which are not a multiple of
- * {@link #RESTART_RINGER_MILLIS} in duration that there will be some pause between repetitions.
- * When {@code false}, the ringtone will be looped continually with no attempt to pause between
- * repeats.
- */
- private boolean mShouldPauseBetweenRepeat = true;
-
public AsyncRingtonePlayer() {
// Empty
}
- public AsyncRingtonePlayer(boolean shouldPauseBetweenRepeat) {
- mShouldPauseBetweenRepeat = shouldPauseBetweenRepeat;
- }
-
/**
* Plays the appropriate ringtone for the specified call.
* If {@link VolumeShaper.Configuration} is specified, it is applied to the ringtone to change
@@ -156,9 +136,6 @@
case EVENT_PLAY:
handlePlay((SomeArgs) msg.obj);
break;
- case EVENT_REPEAT:
- handleRepeat();
- break;
case EVENT_STOP:
handleStop();
break;
@@ -241,43 +218,18 @@
}
}
- if (mShouldPauseBetweenRepeat) {
- // We're trying to pause between repeats, so the ringtone will not intentionally loop.
- // Instead, we'll use a handler message to perform repeats.
- handleRepeat();
- } else {
- mRingtone.setLooping(true);
- if (mRingtone.isPlaying()) {
- Log.d(this, "Ringtone already playing.");
- return;
- }
- mRingtone.play();
- Log.i(this, "Play ringtone, looping.");
+ mRingtone.setLooping(true);
+ if (mRingtone.isPlaying()) {
+ Log.d(this, "Ringtone already playing.");
+ return;
}
+ mRingtone.play();
+ Log.i(this, "Play ringtone, looping.");
} finally {
Log.cancelSubsession(session);
}
}
- private void handleRepeat() {
- if (mRingtone == null) {
- return;
- }
- if (mRingtone.isPlaying()) {
- Log.d(this, "Ringtone already playing.");
- } else {
- mRingtone.play();
- Log.i(this, "Repeat ringtone.");
- }
-
- // Repost event to restart ringer in {@link RESTART_RINGER_MILLIS}.
- synchronized(this) {
- if (!mHandler.hasMessages(EVENT_REPEAT)) {
- mHandler.sendEmptyMessageDelayed(EVENT_REPEAT, RESTART_RINGER_MILLIS);
- }
- }
- }
-
/**
* Stops the playback of the ringtone. Executes on the ringtone-thread.
*/
@@ -292,10 +244,6 @@
}
synchronized(this) {
- // At the time that STOP is handled, there should be no need for repeat messages in the
- // queue.
- mHandler.removeMessages(EVENT_REPEAT);
-
if (mHandler.hasMessages(EVENT_PLAY)) {
Log.v(this, "Keeping alive ringtone thread for subsequent play request.");
} else {
diff --git a/src/com/android/server/telecom/BluetoothAdapterProxy.java b/src/com/android/server/telecom/BluetoothAdapterProxy.java
index 72962b8..41b4faa 100644
--- a/src/com/android/server/telecom/BluetoothAdapterProxy.java
+++ b/src/com/android/server/telecom/BluetoothAdapterProxy.java
@@ -17,6 +17,7 @@
package com.android.server.telecom;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -37,4 +38,11 @@
}
return mBluetoothAdapter.getProfileProxy(context, listener, profile);
}
+
+ public boolean setActiveDevice(BluetoothDevice device, int profiles) {
+ if (mBluetoothAdapter == null) {
+ return false;
+ }
+ return mBluetoothAdapter.setActiveDevice(device, profiles);
+ }
}
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 3d04e50..8773ea2 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -136,9 +136,11 @@
void onPhoneAccountChanged(Call call);
void onConferenceableCallsChanged(Call call);
void onConferenceStateChanged(Call call, boolean isConference);
+ void onCdmaConferenceSwap(Call call);
boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout);
void onHoldToneRequested(Call call);
void onCallHoldFailed(Call call);
+ void onCallSwitchFailed(Call call);
void onConnectionEvent(Call call, String event, Bundle extras);
void onExternalCallChanged(Call call, boolean isExternalCall);
void onRttInitiationFailure(Call call, int reason);
@@ -207,6 +209,8 @@
@Override
public void onConferenceStateChanged(Call call, boolean isConference) {}
@Override
+ public void onCdmaConferenceSwap(Call call) {}
+ @Override
public boolean onCanceledViaNewOutgoingCallBroadcast(Call call, long disconnectionTimeout) {
return false;
}
@@ -215,6 +219,8 @@
@Override
public void onCallHoldFailed(Call call) {}
@Override
+ public void onCallSwitchFailed(Call call) {}
+ @Override
public void onConnectionEvent(Call call, String event, Bundle extras) {}
@Override
public void onExternalCallChanged(Call call, boolean isExternalCall) {}
@@ -325,6 +331,11 @@
*/
private int mHandlePresentation;
+ /**
+ * The verification status for an incoming call's number.
+ */
+ private @Connection.VerificationStatus int mCallerNumberVerificationStatus;
+
/** The caller display name (CNAP) set by the connection service. */
private String mCallerDisplayName;
@@ -575,6 +586,13 @@
private boolean mHasGoneActiveBefore = false;
/**
+ * Indicates the package name of the {@link android.telecom.CallScreeningService} which should
+ * be sent the {@link android.telecom.TelecomManager#ACTION_POST_CALL} intent upon disconnection
+ * of a call.
+ */
+ private String mPostCallPackageName;
+
+ /**
* Persists the specified parameters and initializes the new instance.
* @param context The context.
* @param repository The connection service repository.
@@ -1085,6 +1103,14 @@
return mHandlePresentation;
}
+ public void setCallerNumberVerificationStatus(
+ @Connection.VerificationStatus int callerNumberVerificationStatus) {
+ mCallerNumberVerificationStatus = callerNumberVerificationStatus;
+ }
+
+ public @Connection.VerificationStatus int getCallerNumberVerificationStatus() {
+ return mCallerNumberVerificationStatus;
+ }
void setHandle(Uri handle) {
setHandle(handle, TelecomManager.PRESENTATION_ALLOWED);
@@ -1590,14 +1616,6 @@
Log.v(this, "setConnectionCapabilities: %s", Connection.capabilitiesToString(
connectionCapabilities));
if (forceUpdate || mConnectionCapabilities != connectionCapabilities) {
- // If the phone account does not support video calling, and the connection capabilities
- // passed in indicate that the call supports video, remove those video capabilities.
- if (!isVideoCallingSupportedByPhoneAccount()
- && doesCallSupportVideo(connectionCapabilities)) {
- Log.w(this, "setConnectionCapabilities: attempt to set connection as video " +
- "capable when not supported by the phone account.");
- connectionCapabilities = removeVideoCapabilities(connectionCapabilities);
- }
int previousCapabilities = mConnectionCapabilities;
mConnectionCapabilities = connectionCapabilities;
for (Listener l : mListeners) {
@@ -1836,6 +1854,8 @@
switch (mCallDirection) {
case CALL_DIRECTION_INCOMING:
+ setCallerNumberVerificationStatus(connection.getCallerNumberVerificationStatus());
+
// Listeners (just CallsManager for now) will be responsible for checking whether
// the call should be blocked.
for (Listener l : mListeners) {
@@ -2396,6 +2416,9 @@
mConferenceLevelActiveCall = null;
break;
}
+ for (Listener l : mListeners) {
+ l.onCdmaConferenceSwap(this);
+ }
}
}
@@ -3207,6 +3230,10 @@
for (Listener l : mListeners) {
l.onCallHoldFailed(this);
}
+ } else if (Connection.EVENT_CALL_SWITCH_FAILED.equals(event)) {
+ for (Listener l : mListeners) {
+ l.onCallSwitchFailed(this);
+ }
} else {
for (Listener l : mListeners) {
l.onConnectionEvent(this, event, extras);
@@ -3398,4 +3425,23 @@
}
return CALL_DIRECTION_UNDEFINED;
}
+
+ /**
+ * Set the package name of the {@link android.telecom.CallScreeningService} which should be sent
+ * the {@link android.telecom.TelecomManager#ACTION_POST_CALL} upon disconnection of a call.
+ * @param packageName post call screen service package name.
+ */
+ public void setPostCallPackageName(String packageName) {
+ mPostCallPackageName = packageName;
+ }
+
+ /**
+ * Return the package name of the {@link android.telecom.CallScreeningService} which should be
+ * sent the {@link android.telecom.TelecomManager#ACTION_POST_CALL} upon disconnection of a
+ * call.
+ * @return post call screen service package name.
+ */
+ public String getPostCallPackageName() {
+ return mPostCallPackageName;
+ }
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index e825a0e..9bd1fe5 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -16,6 +16,18 @@
package com.android.server.telecom;
+import static android.telecom.TelecomManager.ACTION_POST_CALL;
+import static android.telecom.TelecomManager.DURATION_LONG;
+import static android.telecom.TelecomManager.DURATION_MEDIUM;
+import static android.telecom.TelecomManager.DURATION_SHORT;
+import static android.telecom.TelecomManager.DURATION_VERY_SHORT;
+import static android.telecom.TelecomManager.EXTRA_CALL_DURATION;
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+import static android.telecom.TelecomManager.MEDIUM_CALL_TIME_MS;
+import static android.telecom.TelecomManager.SHORT_CALL_TIME_MS;
+import static android.telecom.TelecomManager.VERY_SHORT_CALL_TIME_MS;
+
import android.Manifest;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -154,6 +166,7 @@
void onDisconnectedTonePlaying(boolean isTonePlaying);
void onConnectionTimeChanged(Call call);
void onConferenceStateChanged(Call call, boolean isConference);
+ void onCdmaConferenceSwap(Call call);
}
/** Interface used to define the action which is executed delay under some condition. */
@@ -600,6 +613,7 @@
@Override
public void onSuccessfulOutgoingCall(Call call, int callState) {
Log.v(this, "onSuccessfulOutgoingCall, %s", call);
+ call.setPostCallPackageName(getRoleManagerAdapter().getDefaultCallScreeningApp());
setCallState(call, callState, "successful outgoing call");
if (!mCalls.contains(call)) {
@@ -739,6 +753,9 @@
}
if (result.shouldAllowCall) {
+ incomingCall.setPostCallPackageName(
+ getRoleManagerAdapter().getDefaultCallScreeningApp());
+
if (hasMaximumManagedRingingCalls(incomingCall)) {
if (shouldSilenceInsteadOfReject(incomingCall)) {
incomingCall.silence();
@@ -913,6 +930,14 @@
}
@Override
+ public void onCdmaConferenceSwap(Call call) {
+ // SWAP was executed on a CDMA conference
+ for (CallsManagerListener listener : mListeners) {
+ listener.onCdmaConferenceSwap(call);
+ }
+ }
+
+ @Override
public void onIsVoipAudioModeChanged(Call call) {
for (CallsManagerListener listener : mListeners) {
listener.onIsVoipAudioModeChanged(call);
@@ -1030,12 +1055,22 @@
@Override
public void onCallHoldFailed(Call call) {
- // Normally, we don't care whether a call hold has failed. However, if a call was held in
- // order to answer an incoming call, that incoming call needs to be brought out of the
- // ANSWERED state so that the user can try the operation again.
+ markAllAnsweredCallAsRinging(call, "hold");
+ }
+
+ @Override
+ public void onCallSwitchFailed(Call call) {
+ markAllAnsweredCallAsRinging(call, "switch");
+ }
+
+ private void markAllAnsweredCallAsRinging(Call call, String actionName) {
+ // Normally, we don't care whether a call hold or switch has failed.
+ // However, if a call was held or switched in order to answer an incoming call, that
+ // incoming call needs to be brought out of the ANSWERED state so that the user can
+ // try the operation again.
for (Call call1 : mCalls) {
if (call1 != call && call1.getState() == CallState.ANSWERED) {
- setCallState(call1, CallState.RINGING, "hold failed on other call");
+ setCallState(call1, CallState.RINGING, actionName + " failed on other call");
}
}
}
@@ -3247,6 +3282,10 @@
// TODO: Define expected state transitions here, and log when an
// unexpected transition occurs.
if (call.setState(newState, tag)) {
+ if ((oldState != CallState.AUDIO_PROCESSING) &&
+ (newState == CallState.DISCONNECTED)) {
+ maybeSendPostCallScreenIntent(call);
+ }
maybeShowErrorDialogOnDisconnect(call);
Trace.beginSection("onCallStateChanged");
@@ -4826,4 +4865,28 @@
public LinkedList<HandlerThread> getGraphHandlerThreads() {
return mGraphHandlerThreads;
}
+
+ private void maybeSendPostCallScreenIntent(Call call) {
+ if (call.isEmergencyCall() || (call.isNetworkIdentifiedEmergencyCall()) ||
+ (call.getPostCallPackageName() == null)) {
+ return;
+ }
+
+ Intent intent = new Intent(ACTION_POST_CALL);
+ intent.setPackage(call.getPostCallPackageName());
+ intent.putExtra(EXTRA_HANDLE, call.getHandle());
+ intent.putExtra(EXTRA_DISCONNECT_CAUSE, call.getDisconnectCause().getCode());
+ long duration = call.getAgeMillis();
+ int durationCode = DURATION_VERY_SHORT;
+ if ((duration >= VERY_SHORT_CALL_TIME_MS) && (duration < SHORT_CALL_TIME_MS)) {
+ durationCode = DURATION_SHORT;
+ } else if ((duration >= SHORT_CALL_TIME_MS) && (duration < MEDIUM_CALL_TIME_MS)) {
+ durationCode = DURATION_MEDIUM;
+ } else if (duration >= MEDIUM_CALL_TIME_MS) {
+ durationCode = DURATION_LONG;
+ }
+ intent.putExtra(EXTRA_CALL_DURATION, durationCode);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(intent, mCurrentUserHandle);
+ }
}
diff --git a/src/com/android/server/telecom/CallsManagerListenerBase.java b/src/com/android/server/telecom/CallsManagerListenerBase.java
index 4fa2ee5..e0d2831 100644
--- a/src/com/android/server/telecom/CallsManagerListenerBase.java
+++ b/src/com/android/server/telecom/CallsManagerListenerBase.java
@@ -100,4 +100,8 @@
@Override
public void onConferenceStateChanged(Call call, boolean isConference) {
}
+
+ @Override
+ public void onCdmaConferenceSwap(Call call) {
+ }
}
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index d608852..dd50318 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -813,8 +813,11 @@
// ParcelableConnection is in fact registered to Telecom and is being called
// from the correct user.
List<PhoneAccountHandle> accountHandles =
+ // Include CAPABILITY_EMERGENCY_CALLS_ONLY in this list in case we are adding
+ // an emergency call.
mPhoneAccountRegistrar.getCallCapablePhoneAccounts(null /*uriScheme*/,
- false /*includeDisabledAccounts*/, userHandle);
+ false /*includeDisabledAccounts*/, userHandle, 0 /*capabilities*/,
+ 0 /*excludedCapabilities*/);
PhoneAccountHandle phoneAccountHandle = null;
for (PhoneAccountHandle accountHandle : accountHandles) {
if(accountHandle.equals(callingPhoneAccountHandle)) {
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 9fc06e4..b18c6ff 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -865,7 +865,7 @@
info.isExternalCallsSupported(), includeRttCall,
info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
try {
- inCallService.addCall(parcelableCall);
+ inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
}
}
@@ -929,7 +929,7 @@
info.isExternalCallsSupported(), includeRttCall,
info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
try {
- inCallService.addCall(parcelableCall);
+ inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
}
}
@@ -961,7 +961,8 @@
);
try {
- inCallService.updateCall(parcelableCall);
+ inCallService.updateCall(
+ sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
}
}
@@ -1046,6 +1047,12 @@
updateCall(call);
}
+ @Override
+ public void onCdmaConferenceSwap(Call call) {
+ Log.d(this, "onCdmaConferenceSwap %s", call);
+ updateCall(call);
+ }
+
void bringToForeground(boolean showDialpad) {
if (!mInCallServices.isEmpty()) {
for (IInCallService inCallService : mInCallServices.values()) {
@@ -1446,13 +1453,14 @@
// Track the call if we don't already know about it.
addCall(call);
numCallsSent += 1;
- inCallService.addCall(ParcelableCallUtils.toParcelableCall(
+ ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
call,
true /* includeVideoProvider */,
mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported(),
includeRttCall,
- info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI));
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
+ inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
}
}
@@ -1522,7 +1530,8 @@
componentsUpdated.add(componentName);
try {
- inCallService.updateCall(parcelableCall);
+ inCallService.updateCall(
+ sanitizeParcelableCallForService(info, parcelableCall));
} catch (RemoteException ignored) {
}
}
@@ -1654,6 +1663,21 @@
return childCalls;
}
+ private ParcelableCall sanitizeParcelableCallForService(
+ InCallServiceInfo info, ParcelableCall parcelableCall) {
+ ParcelableCall.ParcelableCallBuilder builder =
+ ParcelableCall.ParcelableCallBuilder.fromParcelableCall(parcelableCall);
+ // Check for contacts permission. If it's not there, remove the contactsDisplayName.
+ PackageManager pm = mContext.getPackageManager();
+ if (pm.checkPermission(Manifest.permission.READ_CONTACTS,
+ info.getComponentName().getPackageName()) != PackageManager.PERMISSION_GRANTED) {
+ builder.setContactDisplayName(null);
+ }
+
+ // TODO: move all the other service-specific sanitizations in here
+ return builder.createParcelableCall();
+ }
+
@VisibleForTesting
public Handler getHandler() {
return mHandler;
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index 1abd6fb..7f71ad2 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -519,7 +519,13 @@
private boolean isPotentialEmergencyNumber(String number) {
Log.v(this, "Checking restrictions for number : %s", Log.pii(number));
if (number == null) return false;
- return mContext.getSystemService(TelephonyManager.class).isPotentialEmergencyNumber(number);
+ try {
+ return mContext.getSystemService(TelephonyManager.class).isPotentialEmergencyNumber(
+ number);
+ } catch (Exception e) {
+ Log.e(this, e, "isPotentialEmergencyNumber: Telephony threw an exception.");
+ return false;
+ }
}
/**
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index be44131..69d9c5e 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -220,6 +220,11 @@
callDirection = DIRECTION_OUTGOING;
}
+ String activeChildCallId = null;
+ if (call.getConferenceLevelActiveCall() != null) {
+ activeChildCallId = call.getConferenceLevelActiveCall().getId();
+ }
+
Bundle extras;
if (isForSystemDialer) {
extras = call.getExtras();
@@ -227,34 +232,38 @@
extras = sanitizeExtras(call.getExtras());
}
- return new ParcelableCall(
- call.getId(),
- state,
- call.getDisconnectCause(),
- call.getCannedSmsResponses(),
- capabilities,
- properties,
- supportedAudioRoutes,
- connectTimeMillis,
- handle,
- call.getHandlePresentation(),
- callerDisplayName,
- call.getCallerDisplayNamePresentation(),
- call.getGatewayInfo(),
- call.getTargetPhoneAccount(),
- includeVideoProvider,
- includeVideoProvider ? call.getVideoProvider() : null,
- includeRttCall,
- rttCall,
- parentCallId,
- childCallIds,
- call.getStatusHints(),
- call.getVideoState(),
- conferenceableCallIds,
- call.getIntentExtras(),
- extras,
- call.getCreationTimeMillis(),
- callDirection);
+ return new ParcelableCall.ParcelableCallBuilder()
+ .setId(call.getId())
+ .setState(state)
+ .setDisconnectCause(call.getDisconnectCause())
+ .setCannedSmsResponses(call.getCannedSmsResponses())
+ .setCapabilities(capabilities)
+ .setProperties(properties)
+ .setSupportedAudioRoutes(supportedAudioRoutes)
+ .setConnectTimeMillis(connectTimeMillis)
+ .setHandle(handle)
+ .setHandlePresentation(call.getHandlePresentation())
+ .setCallerDisplayName(callerDisplayName)
+ .setCallerDisplayNamePresentation(call.getCallerDisplayNamePresentation())
+ .setGatewayInfo(call.getGatewayInfo())
+ .setAccountHandle(call.getTargetPhoneAccount())
+ .setIsVideoCallProviderChanged(includeVideoProvider)
+ .setVideoCallProvider(includeVideoProvider ? call.getVideoProvider() : null)
+ .setIsRttCallChanged(includeRttCall)
+ .setRttCall(rttCall)
+ .setParentCallId(parentCallId)
+ .setChildCallIds(childCallIds)
+ .setStatusHints(call.getStatusHints())
+ .setVideoState(call.getVideoState())
+ .setConferenceableCallIds(conferenceableCallIds)
+ .setIntentExtras(call.getIntentExtras())
+ .setExtras(extras)
+ .setCreationTimeMillis(call.getCreationTimeMillis())
+ .setCallDirection(callDirection)
+ .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
+ .setContactDisplayName(call.getName())
+ .setActiveChildCallId(activeChildCallId)
+ .createParcelableCall();
}
/**
@@ -267,6 +276,7 @@
* <li>Connection time</li>
* <li>Handle (phone number)</li>
* <li>Handle (phone number) presentation</li>
+ * <li>Caller number verification status (verstat)</li>
* </ul>
* All other fields are nulled or set to 0 values.
* Where the call screening service is part of the system dialer, the
@@ -297,34 +307,38 @@
callExtras = new Bundle();
}
- return new ParcelableCall(
- call.getId(),
- getParcelableState(call, false /* supportsExternalCalls */),
- new DisconnectCause(DisconnectCause.UNKNOWN),
- null, /* cannedSmsResponses */
- 0, /* capabilities */
- 0, /* properties */
- 0, /* supportedAudioRoutes */
- call.getConnectTimeMillis(),
- handle,
- call.getHandlePresentation(),
- null, /* callerDisplayName */
- 0 /* callerDisplayNamePresentation */,
- null, /* gatewayInfo */
- null, /* targetPhoneAccount */
- false, /* includeVideoProvider */
- null, /* videoProvider */
- false, /* includeRttCall */
- null, /* rttCall */
- null, /* parentCallId */
- null, /* childCallIds */
- null, /* statusHints */
- 0, /* videoState */
- Collections.emptyList(), /* conferenceableCallIds */
- null, /* intentExtras */
- callExtras, /* callExtras */
- call.getCreationTimeMillis(),
- callDirection);
+ return new ParcelableCall.ParcelableCallBuilder()
+ .setId(call.getId())
+ .setState(getParcelableState(call, false /* supportsExternalCalls */))
+ .setDisconnectCause(new DisconnectCause(DisconnectCause.UNKNOWN))
+ .setCannedSmsResponses(null)
+ .setCapabilities(0)
+ .setProperties(0)
+ .setSupportedAudioRoutes(0)
+ .setConnectTimeMillis(call.getConnectTimeMillis())
+ .setHandle(handle)
+ .setHandlePresentation(call.getHandlePresentation())
+ .setCallerDisplayName(null)
+ .setCallerDisplayNamePresentation(0)
+ .setGatewayInfo(null)
+ .setAccountHandle(null)
+ .setIsVideoCallProviderChanged(false)
+ .setVideoCallProvider(null)
+ .setIsRttCallChanged(false)
+ .setRttCall(null)
+ .setParentCallId(null)
+ .setChildCallIds(null)
+ .setStatusHints(null)
+ .setVideoState(0)
+ .setConferenceableCallIds(Collections.emptyList())
+ .setIntentExtras(null)
+ .setExtras(callExtras)
+ .setCreationTimeMillis(call.getCreationTimeMillis())
+ .setCallDirection(callDirection)
+ .setCallerNumberVerificationStatus(call.getCallerNumberVerificationStatus())
+ .setContactDisplayName(null)
+ .setActiveChildCallId(null)
+ .createParcelableCall();
}
/**
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index c1af159..3daa452 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -34,6 +34,7 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -449,8 +450,8 @@
try {
Log.startSession("TSI.rPA");
synchronized (mLock) {
- if (!mContext.getApplicationContext().getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable)) {
+ if (!((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .isVoiceCapable()) {
Log.w(this,
"registerPhoneAccount not allowed on non-voice capable device.");
return;
@@ -1466,6 +1467,24 @@
return BlockedNumbersActivity.getIntentForStartingActivity();
}
+
+ @Override
+ public Intent createLaunchEmergencyDialerIntent(String number) {
+ String packageName = mContext.getApplicationContext().getString(
+ com.android.internal.R.string.config_emergency_dialer_package);
+ Intent intent = new Intent(Intent.ACTION_DIAL_EMERGENCY)
+ .setPackage(packageName);
+ ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0 /* flags*/);
+ if (resolveInfo == null) {
+ // No matching activity from config, fallback to default platform implementation
+ intent.setPackage(null);
+ }
+ if (!TextUtils.isEmpty(number) && TextUtils.isDigitsOnly(number)) {
+ intent.setData(Uri.parse("tel:" + number));
+ }
+ return intent;
+ }
+
/**
* @see android.telecom.TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)
*/
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 92de536..7fd600c 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.bluetooth;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
@@ -119,9 +120,11 @@
private BluetoothHeadsetProxy mBluetoothHeadsetService;
private BluetoothHearingAid mBluetoothHearingAidService;
private BluetoothDevice mBluetoothHearingAidActiveDeviceCache;
+ private BluetoothAdapterProxy mBluetoothAdapterProxy;
public BluetoothDeviceManager(Context context, BluetoothAdapterProxy bluetoothAdapter) {
if (bluetoothAdapter != null) {
+ mBluetoothAdapterProxy = bluetoothAdapter;
bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
BluetoothProfile.HEADSET);
bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
@@ -246,7 +249,8 @@
} else {
for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
if (device != null) {
- mBluetoothHearingAidService.setActiveDevice(null);
+ mBluetoothAdapterProxy.setActiveDevice(null,
+ BluetoothAdapter.ACTIVE_DEVICE_ALL);
}
}
}
@@ -269,15 +273,17 @@
Log.w(this, "Attempting to turn on audio when the hearing aid service is null");
return false;
}
- return mBluetoothHearingAidService.setActiveDevice(
- mHearingAidDevicesByAddress.get(address));
+ return mBluetoothAdapterProxy.setActiveDevice(
+ mHearingAidDevicesByAddress.get(address),
+ BluetoothAdapter.ACTIVE_DEVICE_ALL);
} else if (mHfpDevicesByAddress.containsKey(address)) {
BluetoothDevice device = mHfpDevicesByAddress.get(address);
if (mBluetoothHeadsetService == null) {
Log.w(this, "Attempting to turn on audio when the headset service is null");
return false;
}
- boolean success = mBluetoothHeadsetService.setActiveDevice(device);
+ boolean success = mBluetoothAdapterProxy.setActiveDevice(device,
+ BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
if (!success) {
Log.w(this, "Couldn't set active device to %s", address);
return false;
@@ -304,7 +310,9 @@
public void restoreHearingAidDevice() {
if (mBluetoothHearingAidActiveDeviceCache != null && mBluetoothHearingAidService != null) {
- mBluetoothHearingAidService.setActiveDevice(mBluetoothHearingAidActiveDeviceCache);
+ mBluetoothAdapterProxy.setActiveDevice(
+ mBluetoothHearingAidActiveDeviceCache,
+ BluetoothAdapter.ACTIVE_DEVICE_ALL);
mBluetoothHearingAidActiveDeviceCache = null;
}
}
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index 7671abd..8a14cbd 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -146,6 +146,10 @@
if (device == null) {
mBluetoothRouteManager.sendMessage(BT_AUDIO_LOST, args);
} else {
+ if (!mIsInCall) {
+ Log.i(LOG_TAG, "Ignoring hearing aid audio on since we're not in a call");
+ return;
+ }
args.arg2 = device.getAddress();
mBluetoothRouteManager.sendMessage(BT_AUDIO_IS_ON, args);
}
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 2acc548..e20da80 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -90,8 +90,6 @@
new NotificationChannelManager();
notificationChannelManager.createChannels(context);
- boolean shouldPauseBetweenRingtoneRepeat = context.getResources().getBoolean(
- R.bool.should_pause_between_ringtone_repeats);
TelecomSystem.setInstance(
new TelecomSystem(
context,
@@ -173,7 +171,7 @@
},
ConnectionServiceFocusManager::new,
new Timeouts.Adapter(),
- new AsyncRingtonePlayer(shouldPauseBetweenRingtoneRepeat),
+ new AsyncRingtonePlayer(),
new PhoneNumberUtilsAdapterImpl(),
new IncomingCallNotifier(context),
ToneGenerator::new,
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index 134db80..75c1996 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -27,6 +27,7 @@
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
import com.android.server.telecom.CallIntentProcessor;
import com.android.server.telecom.R;
@@ -163,8 +164,8 @@
* @return {@code True} if the device is voice-capable.
*/
private boolean isVoiceCapable() {
- return mContext.getApplicationContext().getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable);
+ return ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .isVoiceCapable();
}
/**
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index f19c13e..4238191 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -273,5 +273,13 @@
android:excludeFromRecents="true"
android:launchMode="singleInstance">
</activity>
+
+ <activity android:name=".PostCallActivity"
+ android:label="@string/postCallActivityLabel">
+ <intent-filter>
+ <action android:name="android.telecom.action.POST_CALL" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index aa34070..fcd6eff 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -96,6 +96,8 @@
<string name="rttUiLabel">Test RTT UI</string>
+ <string name="postCallActivityLabel">Test Post Call Screen</string>
+
<string-array name="rtt_mode_array">
<item>Full</item>
<item>HCO</item>
diff --git a/testapps/src/com/android/server/telecom/testapps/PostCallActivity.java b/testapps/src/com/android/server/telecom/testapps/PostCallActivity.java
new file mode 100644
index 0000000..101a68e
--- /dev/null
+++ b/testapps/src/com/android/server/telecom/testapps/PostCallActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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.server.telecom.testapps;
+
+import static android.telecom.TelecomManager.EXTRA_CALL_DURATION;
+import static android.telecom.TelecomManager.EXTRA_DISCONNECT_CAUSE;
+import static android.telecom.TelecomManager.EXTRA_HANDLE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.Log;
+
+public class PostCallActivity extends Activity {
+
+ public static final String ACTION_POST_CALL = "android.telecom.action.POST_CALL";
+ public static final int DEFAULT_DISCONNECT_CAUSE = -1;
+ public static final int DEFAULT_DURATION = -1;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Intent intent = getIntent();
+ final String action = intent != null ? intent.getAction() : null;
+ Log.i(this, "action: %s", action);
+ if (ACTION_POST_CALL.equals(action)) {
+ Log.i(this, "extra handle: " +
+ intent.getParcelableExtra(EXTRA_HANDLE));
+ Log.i(this, "extra disconnect cause: " +
+ intent.getIntExtra(EXTRA_DISCONNECT_CAUSE, DEFAULT_DISCONNECT_CAUSE));
+ Log.i(this, "extra duration: " +
+ intent.getIntExtra(EXTRA_CALL_DURATION, DEFAULT_DURATION));
+ }
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 423e069..d536cbd 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -811,7 +811,7 @@
when(getBlockedNumberProvider().call(
anyString(),
anyString(),
- eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
+ eq(BlockedNumberContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
eq(phoneNumber),
nullable(Bundle.class))).thenAnswer(answer);
}
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index 63ff962..bfa7a75 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -16,6 +16,7 @@
package com.android.server.telecom.tests;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
@@ -59,7 +60,7 @@
BluetoothDeviceManager mBluetoothDeviceManager;
BluetoothProfile.ServiceListener serviceListenerUnderTest;
- BroadcastReceiver receiverUnderTest;
+ BluetoothStateReceiver receiverUnderTest;
private BluetoothDevice device1;
private BluetoothDevice device2;
@@ -90,8 +91,7 @@
serviceCaptor.capture(), eq(BluetoothProfile.HEADSET));
serviceListenerUnderTest = serviceCaptor.getValue();
- receiverUnderTest = new BluetoothStateReceiver(mBluetoothDeviceManager,
- null /* route mgr not needed here */);
+ receiverUnderTest = new BluetoothStateReceiver(mBluetoothDeviceManager, mRouteManager);
mBluetoothDeviceManager.setHeadsetServiceForTesting(mHeadsetProxy);
mBluetoothDeviceManager.setHearingAidServiceForTesting(mBluetoothHearingAid);
@@ -198,15 +198,28 @@
@SmallTest
@Test
+ public void testHearingAidChangesIgnoredWhenNotInCall() {
+ receiverUnderTest.setIsInCall(false);
+ receiverUnderTest.onReceive(mContext,
+ buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+ Intent activeDeviceChangedIntent =
+ new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
+ activeDeviceChangedIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device2);
+ receiverUnderTest.onReceive(mContext, activeDeviceChangedIntent);
+
+ verify(mRouteManager).onActiveDeviceChanged(device2, true);
+ verify(mRouteManager, never()).sendMessage(BluetoothRouteManager.BT_AUDIO_IS_ON);
+ }
+
+ @SmallTest
+ @Test
public void testConnectDisconnectAudioHeadset() {
receiverUnderTest.onReceive(mContext,
buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
- when(mHeadsetProxy.setActiveDevice(nullable(BluetoothDevice.class))).thenReturn(true);
+ when(mAdapterProxy.setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
mBluetoothDeviceManager.connectAudio(device1.getAddress());
- verify(mHeadsetProxy).setActiveDevice(device1);
- verify(mHeadsetProxy).connectAudio();
- verify(mBluetoothHearingAid, never()).setActiveDevice(nullable(BluetoothDevice.class));
-
+ verify(mAdapterProxy).setActiveDevice(device1, BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
+ verify(mAdapterProxy, never()).setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_ALL));
mBluetoothDeviceManager.disconnectAudio();
verify(mHeadsetProxy).disconnectAudio();
}
@@ -217,14 +230,14 @@
receiverUnderTest.onReceive(mContext,
buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
mBluetoothDeviceManager.connectAudio(device2.getAddress());
- verify(mBluetoothHearingAid).setActiveDevice(device2);
+ verify(mAdapterProxy).setActiveDevice(device2, BluetoothAdapter.ACTIVE_DEVICE_ALL);
verify(mHeadsetProxy, never()).connectAudio();
- verify(mHeadsetProxy, never()).setActiveDevice(nullable(BluetoothDevice.class));
+ verify(mAdapterProxy, never()).setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(device2, null));
mBluetoothDeviceManager.disconnectAudio();
- verify(mBluetoothHearingAid).setActiveDevice(null);
+ verify(mAdapterProxy).setActiveDevice(null, BluetoothAdapter.ACTIVE_DEVICE_ALL);
verify(mHeadsetProxy).disconnectAudio();
}
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 1b63a42..ef294bd 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -1193,28 +1193,9 @@
assertTrue((newCapabilities & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
== Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
assertTrue(ongoingCall.isVideoCallingSupportedByPhoneAccount());
-
- // Fire a changed event for the phone account making it not capable.
- mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
- SIM_2_ACCOUNT);
- newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
- assertFalse((newCapabilities & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
- == Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
- assertFalse(ongoingCall.isVideoCallingSupportedByPhoneAccount());
-
- // Fire a change for an unrelated phone account.
- PhoneAccount anotherVideoCapableAcct = new PhoneAccount.Builder(SIM_1_ACCOUNT)
- .setCapabilities(SIM_2_ACCOUNT.getCapabilities()
- | PhoneAccount.CAPABILITY_VIDEO_CALLING)
- .build();
- mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
- anotherVideoCapableAcct);
- // Call still should not be video capable
- assertFalse((ongoingCall.getConnectionCapabilities()
- & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)
- == Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
}
+
private Call addSpyCall() {
return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
}
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 3718419..131e591 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -424,6 +424,7 @@
boolean isVoipAudioMode;
Bundle extras;
boolean isConferenceCreated;
+ int callerNumberVerificationStatus;
}
public class ConferenceInfo {
@@ -712,6 +713,7 @@
c.statusHints,
c.disconnectCause,
c.conferenceableConnectionIds,
- c.extras);
+ c.extras,
+ c.callerNumberVerificationStatus);
}
}
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index ed36d29..23d22e9 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -625,6 +625,44 @@
verifyBinding(bindIntentCaptor, 0, DEF_PKG, DEF_CLASS);
}
+ @MediumTest
+ @Test
+ public void testSanitizeContactName() throws Exception {
+ setupMocks(false /* isExternalCall */);
+ setupMockPackageManager(true /* default */, true /* system */, true /* external calls */);
+ when(mMockPackageManager.checkPermission(
+ matches(Manifest.permission.READ_CONTACTS),
+ matches(DEF_PKG))).thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mMockCall.getName()).thenReturn("evil");
+
+ mInCallController.bindToServices(mMockCall);
+
+ // Bind InCallServices
+ ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
+ ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
+ ArgumentCaptor.forClass(ServiceConnection.class);
+ verify(mMockContext, times(1)).bindServiceAsUser(
+ bindIntentCaptor.capture(),
+ serviceConnectionCaptor.capture(),
+ eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+ | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
+ eq(UserHandle.CURRENT));
+ assertEquals(1, bindIntentCaptor.getAllValues().size());
+ verifyBinding(bindIntentCaptor, 0, DEF_PKG, DEF_CLASS);
+
+ IInCallService.Stub mockInCallServiceStub = mock(IInCallService.Stub.class);
+ IInCallService mockInCallService = mock(IInCallService.class);
+ when(mockInCallServiceStub.queryLocalInterface(anyString())).thenReturn(mockInCallService);
+ serviceConnectionCaptor.getValue().onServiceConnected(new ComponentName(DEF_PKG, DEF_CLASS),
+ mockInCallServiceStub);
+
+ mInCallController.onCallAdded(mMockCall);
+ ArgumentCaptor<ParcelableCall> parcelableCallCaptor =
+ ArgumentCaptor.forClass(ParcelableCall.class);
+ verify(mockInCallService).addCall(parcelableCallCaptor.capture());
+ assertTrue(TextUtils.isEmpty(parcelableCallCaptor.getValue().getContactDisplayName()));
+ }
+
/**
* Ensures that the {@link InCallController} will bind to a higher priority car mode service
* when one becomes available.
diff --git a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
index 3438802..a966ffc 100644
--- a/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
+++ b/tests/src/com/android/server/telecom/tests/NewOutgoingCallIntentBroadcasterTest.java
@@ -28,6 +28,7 @@
import static org.mockito.Matchers.isNotNull;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -49,6 +50,7 @@
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.DisconnectCause;
+import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.server.telecom.Call;
@@ -429,6 +431,18 @@
verify(mCall).disconnect(eq(0L));
}
+ /**
+ * Ensure if {@link TelephonyManager#isPotentialEmergencyNumber(String)} throws an exception of
+ * any sort that we don't crash Telecom.
+ */
+ @SmallTest
+ @Test
+ public void testThrowOnIsPotentialEmergencyNumber() {
+ doThrow(new IllegalStateException()).when(mComponentContextFixture.getTelephonyManager())
+ .isPotentialEmergencyNumber(anyString());
+ testUnmodifiedRegularCall();
+ }
+
private ReceiverIntentPair regularCallTestHelper(Intent intent,
Bundle expectedAdditionalExtras) {
Uri handle = intent.getData();
diff --git a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
index 30b870e..6c941fe 100644
--- a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
+++ b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
@@ -2,22 +2,19 @@
import static com.android.server.telecom.TelecomSystem.*;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.telecom.Connection;
-import android.telecom.GatewayInfo;
import android.telecom.ParcelableCall;
import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.SmallTest;
@@ -26,7 +23,6 @@
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.ClockProxy;
-import com.android.server.telecom.ConnectionServiceRepository;
import com.android.server.telecom.ParcelableCallUtils;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneNumberUtilsAdapter;
@@ -149,6 +145,48 @@
assertFalse(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
}
+ @SmallTest
+ @Test
+ public void testVerificationStatusParcelingForScreening() {
+ checkVerStatParcelingForCallScreening(Connection.VERIFICATION_STATUS_NOT_VERIFIED, false);
+ checkVerStatParcelingForCallScreening(Connection.VERIFICATION_STATUS_NOT_VERIFIED, true);
+ checkVerStatParcelingForCallScreening(Connection.VERIFICATION_STATUS_PASSED, false);
+ checkVerStatParcelingForCallScreening(Connection.VERIFICATION_STATUS_PASSED, true);
+ checkVerStatParcelingForCallScreening(Connection.VERIFICATION_STATUS_FAILED, false);
+ checkVerStatParcelingForCallScreening(Connection.VERIFICATION_STATUS_FAILED, true);
+ }
+
+ @SmallTest
+ @Test
+ public void testVerificationStatusParcelingForDialer() {
+ checkVerStatParcelingForDialer(Connection.VERIFICATION_STATUS_NOT_VERIFIED, false);
+ checkVerStatParcelingForDialer(Connection.VERIFICATION_STATUS_NOT_VERIFIED, true);
+ checkVerStatParcelingForDialer(Connection.VERIFICATION_STATUS_PASSED, false);
+ checkVerStatParcelingForDialer(Connection.VERIFICATION_STATUS_PASSED, true);
+ checkVerStatParcelingForDialer(Connection.VERIFICATION_STATUS_FAILED, false);
+ checkVerStatParcelingForDialer(Connection.VERIFICATION_STATUS_FAILED, true);
+ }
+
+ private void checkVerStatParcelingForCallScreening(int connectionVerificationStatus,
+ boolean isForSystemDialer) {
+ mCall.setCallerNumberVerificationStatus(connectionVerificationStatus);
+ ParcelableCall call = ParcelableCallUtils.toParcelableCallForScreening(mCall,
+ isForSystemDialer /* isPartOfSystemDialer */);
+ assertEquals(connectionVerificationStatus, call.getCallerNumberVerificationStatus());
+ }
+
+ private void checkVerStatParcelingForDialer(int connectionVerificationStatus,
+ boolean isForSystemDialer) {
+ mCall.setCallerNumberVerificationStatus(connectionVerificationStatus);
+ ParcelableCall call = ParcelableCallUtils.toParcelableCall(mCall,
+ false /* includevideoProvider */,
+ null /* phoneAccountRegistrar */,
+ false /* supportsExternalCalls */,
+ false /* includeRttCall */,
+ isForSystemDialer /* isForSystemDialer */);
+ assertEquals(connectionVerificationStatus, call.getCallerNumberVerificationStatus());
+ }
+
private Bundle getSomeExtras() {
Bundle extras = new Bundle();
extras.putString(Connection.EXTRA_SIP_INVITE, "scary data");
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 890fa6f..324bca2 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -190,8 +190,10 @@
public void setUp() throws Exception {
super.setUp();
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
- mComponentContextFixture.putBooleanResource(
- com.android.internal.R.bool.config_voice_capable, true);
+
+ TelephonyManager mockTelephonyManager =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ when(mockTelephonyManager.isVoiceCapable()).thenReturn(true);
doReturn(mContext).when(mContext).getApplicationContext();
doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class),
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index a4aba3d..442c310 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -581,8 +581,9 @@
mComponentContextFixture.putResource(
com.android.server.telecom.R.string.incall_default_class,
mInCallServiceComponentNameX.getClassName());
- mComponentContextFixture.putBooleanResource(
- com.android.internal.R.bool.config_voice_capable, true);
+
+ doReturn(true).when(mComponentContextFixture.getTelephonyManager())
+ .isVoiceCapable();
mInCallServiceFixtureX = new InCallServiceFixture();
mInCallServiceFixtureY = new InCallServiceFixture();