Loading src/com/android/server/telecom/Call.java +100 −6 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.telecom.DisconnectCause; import android.telecom.GatewayInfo; import android.telecom.Log; import android.telecom.Logging.EventManager; import android.telecom.ParcelableConference; import android.telecom.ParcelableConnection; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; Loading Loading @@ -326,6 +327,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, /** The handle with which to establish this call. */ private Uri mHandle; /** The participants with which to establish adhoc conference call */ private List<Uri> mParticipants; /** * The presentation requirements for the handle. See {@link TelecomManager} for valid values. */ Loading Loading @@ -624,15 +627,43 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, boolean isConference, ClockProxy clockProxy, ToastFactory toastFactory) { this(callId, context, callsManager, lock, repository, phoneNumberUtilsAdapter, handle, null, gatewayInfo, connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection, shouldAttachToExistingConnection, isConference, clockProxy, toastFactory); } public Call( String callId, Context context, CallsManager callsManager, TelecomSystem.SyncRoot lock, ConnectionServiceRepository repository, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, Uri handle, List<Uri> participants, GatewayInfo gatewayInfo, PhoneAccountHandle connectionManagerPhoneAccountHandle, PhoneAccountHandle targetPhoneAccountHandle, int callDirection, boolean shouldAttachToExistingConnection, boolean isConference, ClockProxy clockProxy, ToastFactory toastFactory) { mId = callId; mConnectionId = callId; mState = isConference ? CallState.ACTIVE : CallState.NEW; mState = (isConference && callDirection != CALL_DIRECTION_INCOMING && callDirection != CALL_DIRECTION_OUTGOING) ? CallState.ACTIVE : CallState.NEW; mContext = context; mCallsManager = callsManager; mLock = lock; mRepository = repository; mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; setHandle(handle); mParticipants = participants; mPostDialDigits = handle != null ? PhoneNumberUtils.extractPostDialPortion(handle.getSchemeSpecificPart()) : ""; mGatewayInfo = gatewayInfo; Loading Loading @@ -1080,6 +1111,16 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, return mHandle; } public List<Uri> getParticipants() { return mParticipants; } public boolean isAdhocConferenceCall() { return mIsConference && (mCallDirection == CALL_DIRECTION_OUTGOING || mCallDirection == CALL_DIRECTION_INCOMING); } public String getPostDialDigits() { return mPostDialDigits; } Loading Loading @@ -1827,6 +1868,39 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, mCreateConnectionProcessor.process(); } @Override public void handleCreateConferenceSuccess( CallIdMapper idMapper, ParcelableConference conference) { Log.v(this, "handleCreateConferenceSuccessful %s", conference); setTargetPhoneAccount(conference.getPhoneAccount()); setHandle(conference.getHandle(), conference.getHandlePresentation()); setConnectionCapabilities(conference.getConnectionCapabilities()); setConnectionProperties(conference.getConnectionProperties()); setVideoProvider(conference.getVideoProvider()); setVideoState(conference.getVideoState()); setRingbackRequested(conference.isRingbackRequested()); setStatusHints(conference.getStatusHints()); putExtras(SOURCE_CONNECTION_SERVICE, conference.getExtras()); switch (mCallDirection) { case CALL_DIRECTION_INCOMING: // Listeners (just CallsManager for now) will be responsible for checking whether // the call should be blocked. for (Listener l : mListeners) { l.onSuccessfulIncomingCall(this); } break; case CALL_DIRECTION_OUTGOING: for (Listener l : mListeners) { l.onSuccessfulOutgoingCall(this, getStateFromConnectionState(conference.getState())); } break; } } @Override public void handleCreateConnectionSuccess( CallIdMapper idMapper, Loading Loading @@ -1877,6 +1951,26 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, } } @Override public void handleCreateConferenceFailure(DisconnectCause disconnectCause) { clearConnectionService(); setDisconnectCause(disconnectCause); mCallsManager.markCallAsDisconnected(this, disconnectCause); switch (mCallDirection) { case CALL_DIRECTION_INCOMING: for (Listener listener : mListeners) { listener.onFailedIncomingCall(this); } break; case CALL_DIRECTION_OUTGOING: for (Listener listener : mListeners) { listener.onFailedOutgoingCall(this, disconnectCause); } break; } } @Override public void handleCreateConnectionFailure(DisconnectCause disconnectCause) { clearConnectionService(); Loading src/com/android/server/telecom/CallsManager.java +124 −11 Original line number Diff line number Diff line Loading @@ -109,6 +109,7 @@ import com.android.server.telecom.ui.IncomingCallNotifier; import com.android.server.telecom.ui.ToastFactory; import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; Loading Loading @@ -1153,6 +1154,11 @@ public class CallsManager extends Call.ListenerBase mListeners.remove(listener); } void processIncomingConference(PhoneAccountHandle phoneAccountHandle, Bundle extras) { Log.d(this, "processIncomingCallConference"); processIncomingCallIntent(phoneAccountHandle, extras, true); } /** * Starts the process to attach the call to a connection service. * Loading @@ -1161,6 +1167,11 @@ public class CallsManager extends Call.ListenerBase * @param extras The optional extras Bundle passed with the intent used for the incoming call. */ void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { processIncomingCallIntent(phoneAccountHandle, extras, false); } void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras, boolean isConference) { Log.d(this, "processIncomingCallIntent"); boolean isHandover = extras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER); Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS); Loading @@ -1181,7 +1192,7 @@ public class CallsManager extends Call.ListenerBase phoneAccountHandle, Call.CALL_DIRECTION_INCOMING /* callDirection */, false /* forceAttachToExistingConnection */, false, /* isConference */ isConference, /* isConference */ mClockProxy, mToastFactory); Loading Loading @@ -1295,14 +1306,22 @@ public class CallsManager extends Call.ListenerBase if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call, call.getTargetPhoneAccount()))) { if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else if (isInEmergencyCall()) { // The incoming call is implicitly being rejected so the user does not get any incoming // call UI during an emergency call. In this case, log the call as missed instead of // rejected since the user did not explicitly reject. mCallLogManager.logCall(call, Calls.MISSED_TYPE, true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/); if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else { call.startCreateConnection(mPhoneAccountRegistrar); } Loading Loading @@ -1390,7 +1409,18 @@ public class CallsManager extends Call.ListenerBase PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage) { final List<Uri> callee = new ArrayList<>(); callee.add(handle); return startOutgoingCall(callee, requestedAccountHandle, extras, initiatingUser, originalIntent, callingPackage, false); } private CompletableFuture<Call> startOutgoingCall(List<Uri> participants, PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage, boolean isConference) { boolean isReusedCall; Uri handle = isConference ? Uri.parse("tel:conf-factory") : participants.get(0); Call call = reuseOutgoingCall(handle); PhoneAccount account = Loading @@ -1406,12 +1436,13 @@ public class CallsManager extends Call.ListenerBase mConnectionServiceRepository, mPhoneNumberUtilsAdapter, handle, isConference ? participants : null, null /* gatewayInfo */, null /* connectionManagerPhoneAccount */, null /* requestedAccountHandle */, Call.CALL_DIRECTION_OUTGOING /* callDirection */, false /* forceAttachToExistingConnection */, false, /* isConference */ isConference, /* isConference */ mClockProxy, mToastFactory); call.initAnalytics(callingPackage); Loading Loading @@ -1475,7 +1506,8 @@ public class CallsManager extends Call.ListenerBase CompletableFuture.completedFuture((Void) null).thenComposeAsync((x) -> findOutgoingCallPhoneAccount(requestedAccountHandle, handle, VideoProfile.isVideo(finalVideoState), finalCall.isEmergencyCall(), initiatingUser), finalCall.isEmergencyCall(), initiatingUser, isConference), new LoggedHandlerExecutor(outgoingCallHandler, "CM.fOCP", mLock)); // This is a block of code that executes after the list of potential phone accts has been Loading Loading @@ -1543,9 +1575,14 @@ public class CallsManager extends Call.ListenerBase } else { // If the ongoing call is a managed call, we will prevent the outgoing // call from dialing. if (isConference) { notifyCreateConferenceFailed(finalCall.getTargetPhoneAccount(), finalCall); } else { notifyCreateConnectionFailed( finalCall.getTargetPhoneAccount(), finalCall); } } Log.i(CallsManager.this, "Aborting call since there's no room"); return CompletableFuture.completedFuture(null); } Loading Loading @@ -1706,6 +1743,38 @@ public class CallsManager extends Call.ListenerBase return mLatestPostSelectionProcessingFuture; } public void startConference(List<Uri> participants, Bundle clientExtras, String callingPackage, UserHandle initiatingUser) { if (clientExtras == null) { clientExtras = new Bundle(); } PhoneAccountHandle phoneAccountHandle = clientExtras.getParcelable( TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); CompletableFuture<Call> callFuture = startOutgoingCall(participants, phoneAccountHandle, clientExtras, initiatingUser, null/* originalIntent */, callingPackage, true/* isconference*/); final boolean speakerphoneOn = clientExtras.getBoolean( TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE); final int videoState = clientExtras.getInt( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE); final Session logSubsession = Log.createSubsession(); callFuture.thenAccept((call) -> { if (call != null) { Log.continueSession(logSubsession, "CM.pOGC"); try { placeOutgoingCall(call, call.getHandle(), null/* gatewayInfo */, speakerphoneOn, videoState); } finally { Log.endSession(); } } }); } /** * Performs call identification for an outgoing phone call. * @param theCall The outgoing call to perform identification. Loading Loading @@ -1768,6 +1837,14 @@ public class CallsManager extends Call.ListenerBase public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, boolean isEmergency, UserHandle initiatingUser) { return findOutgoingCallPhoneAccount(targetPhoneAccountHandle, handle, isVideo, isEmergency, initiatingUser, false/* isConference */); } public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, boolean isEmergency, UserHandle initiatingUser, boolean isConference) { if (isSelfManaged(targetPhoneAccountHandle, initiatingUser)) { return CompletableFuture.completedFuture(Arrays.asList(targetPhoneAccountHandle)); } Loading @@ -1775,12 +1852,13 @@ public class CallsManager extends Call.ListenerBase List<PhoneAccountHandle> accounts; // Try to find a potential phone account, taking into account whether this is a video // call. accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo, isEmergency); accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo, isEmergency, isConference); if (isVideo && accounts.size() == 0) { // Placing a video call but no video capable accounts were found, so consider any // call capable accounts (we can fallback to audio). accounts = constructPossiblePhoneAccounts(handle, initiatingUser, false /* isVideo */, isEmergency /* isEmergency */); false /* isVideo */, isEmergency /* isEmergency */, isConference); } Log.v(this, "findOutgoingCallPhoneAccount: accounts = " + accounts); Loading Loading @@ -2057,7 +2135,11 @@ public class CallsManager extends Call.ListenerBase // If the account has been set, proceed to place the outgoing call. // Otherwise the connection will be initiated when the account is set by the user. if (call.isSelfManaged() && !isOutgoingCallPermitted) { if (call.isAdhocConferenceCall()) { notifyCreateConferenceFailed(call.getTargetPhoneAccount(), call); } else { notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); } } else { if (call.isEmergencyCall()) { // Drop any ongoing self-managed calls to make way for an emergency call. Loading Loading @@ -2458,15 +2540,23 @@ public class CallsManager extends Call.ListenerBase @VisibleForTesting public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency) { return constructPossiblePhoneAccounts(handle, user, isVideo, isEmergency, false); } public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency, boolean isConference) { if (handle == null) { return Collections.emptyList(); } // If we're specifically looking for video capable accounts, then include that capability, // otherwise specify no additional capability constraints. When handling the emergency call, // it also needs to find the phone accounts excluded by CAPABILITY_EMERGENCY_CALLS_ONLY. int capabilities = isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0; capabilities |= isConference ? PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING : 0; List<PhoneAccountHandle> allAccounts = mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user, isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0 /* any */, capabilities, isEmergency ? 0 : PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY); if (mMaxNumberOfSimultaneouslyActiveSims < 0) { mMaxNumberOfSimultaneouslyActiveSims = Loading Loading @@ -4362,6 +4452,29 @@ public class CallsManager extends Call.ListenerBase } } /** * Notifies the {@link android.telecom.ConnectionService} associated with a * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. * * @param phoneAccountHandle The {@link PhoneAccountHandle}. * @param call The {@link Call} which could not be added. */ private void notifyCreateConferenceFailed(PhoneAccountHandle phoneAccountHandle, Call call) { if (phoneAccountHandle == null) { return; } ConnectionServiceWrapper service = mConnectionServiceRepository.getService( phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); if (service == null) { Log.i(this, "Found no connection service."); return; } else { call.setConnectionService(service); service.createConferenceFailed(call); } } /** * Notifies the {@link android.telecom.ConnectionService} associated with a * {@link PhoneAccountHandle} that the attempt to handover a call has failed. Loading src/com/android/server/telecom/ConnectionServiceWrapper.java +157 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes src/com/android/server/telecom/CreateConnectionProcessor.java +62 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.telecom; import android.content.Context; import android.telecom.DisconnectCause; import android.telecom.Log; import android.telecom.ParcelableConference; import android.telecom.ParcelableConnection; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; Loading Loading @@ -245,7 +246,11 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { mCall.setConnectionService(mService); setTimeoutIfNeeded(mService, attempt); if (mCall.isIncoming()) { if (mCall.isAdhocConferenceCall()) { mService.createConference(mCall, CreateConnectionProcessor.this); } else { mService.createConnection(mCall, CreateConnectionProcessor.this); } } else { // Start to create the connection for outgoing call after the ConnectionService // of the call has gained the focus. Loading @@ -254,11 +259,17 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { new CallsManager.RequestCallback(new CallsManager.PendingAction() { @Override public void performAction() { if (mCall.isAdhocConferenceCall()) { Log.d(this, "perform create conference"); mService.createConference(mCall, CreateConnectionProcessor.this); } else { Log.d(this, "perform create connection"); mService.createConnection( mCall, CreateConnectionProcessor.this); } } })); } Loading @@ -267,9 +278,13 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { Log.v(this, "attemptNextPhoneAccount, no more accounts, failing"); DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ? mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR); if (mCall.isAdhocConferenceCall()) { notifyConferenceCallFailure(disconnectCause); } else { notifyCallConnectionFailure(disconnectCause); } } } private void setTimeoutIfNeeded(ConnectionServiceWrapper service, CallAttemptRecord attempt) { clearTimeout(); Loading Loading @@ -457,6 +472,16 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { } } private void notifyConferenceCallFailure(DisconnectCause errorDisconnectCause) { if (mCallResponse != null) { clearTimeout(); mCallResponse.handleCreateConferenceFailure(errorDisconnectCause); mCallResponse = null; mCall.clearConnectionService(); } } @Override public void handleCreateConnectionSuccess( CallIdMapper idMapper, Loading @@ -475,6 +500,25 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { } } @Override public void handleCreateConferenceSuccess( CallIdMapper idMapper, ParcelableConference conference) { if (mCallResponse == null) { // Nobody is listening for this conference attempt any longer; ask the responsible // ConnectionService to tear down any resources associated with the call mService.abort(mCall); } else { // Success -- share the good news and remember that we are no longer interested // in hearing about any more attempts mCallResponse.handleCreateConferenceSuccess(idMapper, conference); mCallResponse = null; // If there's a timeout running then don't clear it. The timeout can be triggered // after the call has successfully been created but before it has become active. } } private boolean shouldFailCallIfConnectionManagerFails(DisconnectCause cause) { // Connection Manager does not exist or does not match registered Connection Manager // Since Connection manager is a proxy for SIM, fall back to SIM Loading Loading @@ -522,6 +566,18 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { attemptNextPhoneAccount(); } @Override public void handleCreateConferenceFailure(DisconnectCause errorDisconnectCause) { // Failure of some sort; record the reasons for failure and try again if possible Log.d(CreateConnectionProcessor.this, "Conference failed: (%s)", errorDisconnectCause); if (shouldFailCallIfConnectionManagerFails(errorDisconnectCause)) { notifyConferenceCallFailure(errorDisconnectCause); return; } mLastErrorDisconnectCause = errorDisconnectCause; attemptNextPhoneAccount(); } public void sortSimPhoneAccountsForEmergency(List<PhoneAccount> accounts, PhoneAccount userPreferredAccount) { // Sort the accounts according to how we want to display them (ascending order). Loading src/com/android/server/telecom/CreateConnectionResponse.java +4 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.telecom; import android.telecom.DisconnectCause; import android.telecom.ParcelableConference; import android.telecom.ParcelableConnection; import com.android.internal.annotations.VisibleForTesting; Loading @@ -28,4 +29,7 @@ import com.android.internal.annotations.VisibleForTesting; public interface CreateConnectionResponse { void handleCreateConnectionSuccess(CallIdMapper idMapper, ParcelableConnection connection); void handleCreateConnectionFailure(DisconnectCause disconnectCaused); void handleCreateConferenceSuccess(CallIdMapper idMapper, ParcelableConference conference); void handleCreateConferenceFailure(DisconnectCause disconnectCaused); } Loading
src/com/android/server/telecom/Call.java +100 −6 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.telecom.DisconnectCause; import android.telecom.GatewayInfo; import android.telecom.Log; import android.telecom.Logging.EventManager; import android.telecom.ParcelableConference; import android.telecom.ParcelableConnection; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; Loading Loading @@ -326,6 +327,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, /** The handle with which to establish this call. */ private Uri mHandle; /** The participants with which to establish adhoc conference call */ private List<Uri> mParticipants; /** * The presentation requirements for the handle. See {@link TelecomManager} for valid values. */ Loading Loading @@ -624,15 +627,43 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, boolean isConference, ClockProxy clockProxy, ToastFactory toastFactory) { this(callId, context, callsManager, lock, repository, phoneNumberUtilsAdapter, handle, null, gatewayInfo, connectionManagerPhoneAccountHandle, targetPhoneAccountHandle, callDirection, shouldAttachToExistingConnection, isConference, clockProxy, toastFactory); } public Call( String callId, Context context, CallsManager callsManager, TelecomSystem.SyncRoot lock, ConnectionServiceRepository repository, PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, Uri handle, List<Uri> participants, GatewayInfo gatewayInfo, PhoneAccountHandle connectionManagerPhoneAccountHandle, PhoneAccountHandle targetPhoneAccountHandle, int callDirection, boolean shouldAttachToExistingConnection, boolean isConference, ClockProxy clockProxy, ToastFactory toastFactory) { mId = callId; mConnectionId = callId; mState = isConference ? CallState.ACTIVE : CallState.NEW; mState = (isConference && callDirection != CALL_DIRECTION_INCOMING && callDirection != CALL_DIRECTION_OUTGOING) ? CallState.ACTIVE : CallState.NEW; mContext = context; mCallsManager = callsManager; mLock = lock; mRepository = repository; mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; setHandle(handle); mParticipants = participants; mPostDialDigits = handle != null ? PhoneNumberUtils.extractPostDialPortion(handle.getSchemeSpecificPart()) : ""; mGatewayInfo = gatewayInfo; Loading Loading @@ -1080,6 +1111,16 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, return mHandle; } public List<Uri> getParticipants() { return mParticipants; } public boolean isAdhocConferenceCall() { return mIsConference && (mCallDirection == CALL_DIRECTION_OUTGOING || mCallDirection == CALL_DIRECTION_INCOMING); } public String getPostDialDigits() { return mPostDialDigits; } Loading Loading @@ -1827,6 +1868,39 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, mCreateConnectionProcessor.process(); } @Override public void handleCreateConferenceSuccess( CallIdMapper idMapper, ParcelableConference conference) { Log.v(this, "handleCreateConferenceSuccessful %s", conference); setTargetPhoneAccount(conference.getPhoneAccount()); setHandle(conference.getHandle(), conference.getHandlePresentation()); setConnectionCapabilities(conference.getConnectionCapabilities()); setConnectionProperties(conference.getConnectionProperties()); setVideoProvider(conference.getVideoProvider()); setVideoState(conference.getVideoState()); setRingbackRequested(conference.isRingbackRequested()); setStatusHints(conference.getStatusHints()); putExtras(SOURCE_CONNECTION_SERVICE, conference.getExtras()); switch (mCallDirection) { case CALL_DIRECTION_INCOMING: // Listeners (just CallsManager for now) will be responsible for checking whether // the call should be blocked. for (Listener l : mListeners) { l.onSuccessfulIncomingCall(this); } break; case CALL_DIRECTION_OUTGOING: for (Listener l : mListeners) { l.onSuccessfulOutgoingCall(this, getStateFromConnectionState(conference.getState())); } break; } } @Override public void handleCreateConnectionSuccess( CallIdMapper idMapper, Loading Loading @@ -1877,6 +1951,26 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, } } @Override public void handleCreateConferenceFailure(DisconnectCause disconnectCause) { clearConnectionService(); setDisconnectCause(disconnectCause); mCallsManager.markCallAsDisconnected(this, disconnectCause); switch (mCallDirection) { case CALL_DIRECTION_INCOMING: for (Listener listener : mListeners) { listener.onFailedIncomingCall(this); } break; case CALL_DIRECTION_OUTGOING: for (Listener listener : mListeners) { listener.onFailedOutgoingCall(this, disconnectCause); } break; } } @Override public void handleCreateConnectionFailure(DisconnectCause disconnectCause) { clearConnectionService(); Loading
src/com/android/server/telecom/CallsManager.java +124 −11 Original line number Diff line number Diff line Loading @@ -109,6 +109,7 @@ import com.android.server.telecom.ui.IncomingCallNotifier; import com.android.server.telecom.ui.ToastFactory; import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; Loading Loading @@ -1153,6 +1154,11 @@ public class CallsManager extends Call.ListenerBase mListeners.remove(listener); } void processIncomingConference(PhoneAccountHandle phoneAccountHandle, Bundle extras) { Log.d(this, "processIncomingCallConference"); processIncomingCallIntent(phoneAccountHandle, extras, true); } /** * Starts the process to attach the call to a connection service. * Loading @@ -1161,6 +1167,11 @@ public class CallsManager extends Call.ListenerBase * @param extras The optional extras Bundle passed with the intent used for the incoming call. */ void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) { processIncomingCallIntent(phoneAccountHandle, extras, false); } void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras, boolean isConference) { Log.d(this, "processIncomingCallIntent"); boolean isHandover = extras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER); Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS); Loading @@ -1181,7 +1192,7 @@ public class CallsManager extends Call.ListenerBase phoneAccountHandle, Call.CALL_DIRECTION_INCOMING /* callDirection */, false /* forceAttachToExistingConnection */, false, /* isConference */ isConference, /* isConference */ mClockProxy, mToastFactory); Loading Loading @@ -1295,14 +1306,22 @@ public class CallsManager extends Call.ListenerBase if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call, call.getTargetPhoneAccount()))) { if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else if (isInEmergencyCall()) { // The incoming call is implicitly being rejected so the user does not get any incoming // call UI during an emergency call. In this case, log the call as missed instead of // rejected since the user did not explicitly reject. mCallLogManager.logCall(call, Calls.MISSED_TYPE, true /*showNotificationForMissedCall*/, null /*CallFilteringResult*/); if (isConference) { notifyCreateConferenceFailed(phoneAccountHandle, call); } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else { call.startCreateConnection(mPhoneAccountRegistrar); } Loading Loading @@ -1390,7 +1409,18 @@ public class CallsManager extends Call.ListenerBase PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage) { final List<Uri> callee = new ArrayList<>(); callee.add(handle); return startOutgoingCall(callee, requestedAccountHandle, extras, initiatingUser, originalIntent, callingPackage, false); } private CompletableFuture<Call> startOutgoingCall(List<Uri> participants, PhoneAccountHandle requestedAccountHandle, Bundle extras, UserHandle initiatingUser, Intent originalIntent, String callingPackage, boolean isConference) { boolean isReusedCall; Uri handle = isConference ? Uri.parse("tel:conf-factory") : participants.get(0); Call call = reuseOutgoingCall(handle); PhoneAccount account = Loading @@ -1406,12 +1436,13 @@ public class CallsManager extends Call.ListenerBase mConnectionServiceRepository, mPhoneNumberUtilsAdapter, handle, isConference ? participants : null, null /* gatewayInfo */, null /* connectionManagerPhoneAccount */, null /* requestedAccountHandle */, Call.CALL_DIRECTION_OUTGOING /* callDirection */, false /* forceAttachToExistingConnection */, false, /* isConference */ isConference, /* isConference */ mClockProxy, mToastFactory); call.initAnalytics(callingPackage); Loading Loading @@ -1475,7 +1506,8 @@ public class CallsManager extends Call.ListenerBase CompletableFuture.completedFuture((Void) null).thenComposeAsync((x) -> findOutgoingCallPhoneAccount(requestedAccountHandle, handle, VideoProfile.isVideo(finalVideoState), finalCall.isEmergencyCall(), initiatingUser), finalCall.isEmergencyCall(), initiatingUser, isConference), new LoggedHandlerExecutor(outgoingCallHandler, "CM.fOCP", mLock)); // This is a block of code that executes after the list of potential phone accts has been Loading Loading @@ -1543,9 +1575,14 @@ public class CallsManager extends Call.ListenerBase } else { // If the ongoing call is a managed call, we will prevent the outgoing // call from dialing. if (isConference) { notifyCreateConferenceFailed(finalCall.getTargetPhoneAccount(), finalCall); } else { notifyCreateConnectionFailed( finalCall.getTargetPhoneAccount(), finalCall); } } Log.i(CallsManager.this, "Aborting call since there's no room"); return CompletableFuture.completedFuture(null); } Loading Loading @@ -1706,6 +1743,38 @@ public class CallsManager extends Call.ListenerBase return mLatestPostSelectionProcessingFuture; } public void startConference(List<Uri> participants, Bundle clientExtras, String callingPackage, UserHandle initiatingUser) { if (clientExtras == null) { clientExtras = new Bundle(); } PhoneAccountHandle phoneAccountHandle = clientExtras.getParcelable( TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE); CompletableFuture<Call> callFuture = startOutgoingCall(participants, phoneAccountHandle, clientExtras, initiatingUser, null/* originalIntent */, callingPackage, true/* isconference*/); final boolean speakerphoneOn = clientExtras.getBoolean( TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE); final int videoState = clientExtras.getInt( TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE); final Session logSubsession = Log.createSubsession(); callFuture.thenAccept((call) -> { if (call != null) { Log.continueSession(logSubsession, "CM.pOGC"); try { placeOutgoingCall(call, call.getHandle(), null/* gatewayInfo */, speakerphoneOn, videoState); } finally { Log.endSession(); } } }); } /** * Performs call identification for an outgoing phone call. * @param theCall The outgoing call to perform identification. Loading Loading @@ -1768,6 +1837,14 @@ public class CallsManager extends Call.ListenerBase public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, boolean isEmergency, UserHandle initiatingUser) { return findOutgoingCallPhoneAccount(targetPhoneAccountHandle, handle, isVideo, isEmergency, initiatingUser, false/* isConference */); } public CompletableFuture<List<PhoneAccountHandle>> findOutgoingCallPhoneAccount( PhoneAccountHandle targetPhoneAccountHandle, Uri handle, boolean isVideo, boolean isEmergency, UserHandle initiatingUser, boolean isConference) { if (isSelfManaged(targetPhoneAccountHandle, initiatingUser)) { return CompletableFuture.completedFuture(Arrays.asList(targetPhoneAccountHandle)); } Loading @@ -1775,12 +1852,13 @@ public class CallsManager extends Call.ListenerBase List<PhoneAccountHandle> accounts; // Try to find a potential phone account, taking into account whether this is a video // call. accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo, isEmergency); accounts = constructPossiblePhoneAccounts(handle, initiatingUser, isVideo, isEmergency, isConference); if (isVideo && accounts.size() == 0) { // Placing a video call but no video capable accounts were found, so consider any // call capable accounts (we can fallback to audio). accounts = constructPossiblePhoneAccounts(handle, initiatingUser, false /* isVideo */, isEmergency /* isEmergency */); false /* isVideo */, isEmergency /* isEmergency */, isConference); } Log.v(this, "findOutgoingCallPhoneAccount: accounts = " + accounts); Loading Loading @@ -2057,7 +2135,11 @@ public class CallsManager extends Call.ListenerBase // If the account has been set, proceed to place the outgoing call. // Otherwise the connection will be initiated when the account is set by the user. if (call.isSelfManaged() && !isOutgoingCallPermitted) { if (call.isAdhocConferenceCall()) { notifyCreateConferenceFailed(call.getTargetPhoneAccount(), call); } else { notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call); } } else { if (call.isEmergencyCall()) { // Drop any ongoing self-managed calls to make way for an emergency call. Loading Loading @@ -2458,15 +2540,23 @@ public class CallsManager extends Call.ListenerBase @VisibleForTesting public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency) { return constructPossiblePhoneAccounts(handle, user, isVideo, isEmergency, false); } public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency, boolean isConference) { if (handle == null) { return Collections.emptyList(); } // If we're specifically looking for video capable accounts, then include that capability, // otherwise specify no additional capability constraints. When handling the emergency call, // it also needs to find the phone accounts excluded by CAPABILITY_EMERGENCY_CALLS_ONLY. int capabilities = isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0; capabilities |= isConference ? PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING : 0; List<PhoneAccountHandle> allAccounts = mPhoneAccountRegistrar.getCallCapablePhoneAccounts(handle.getScheme(), false, user, isVideo ? PhoneAccount.CAPABILITY_VIDEO_CALLING : 0 /* any */, capabilities, isEmergency ? 0 : PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY); if (mMaxNumberOfSimultaneouslyActiveSims < 0) { mMaxNumberOfSimultaneouslyActiveSims = Loading Loading @@ -4362,6 +4452,29 @@ public class CallsManager extends Call.ListenerBase } } /** * Notifies the {@link android.telecom.ConnectionService} associated with a * {@link PhoneAccountHandle} that the attempt to create a new connection has failed. * * @param phoneAccountHandle The {@link PhoneAccountHandle}. * @param call The {@link Call} which could not be added. */ private void notifyCreateConferenceFailed(PhoneAccountHandle phoneAccountHandle, Call call) { if (phoneAccountHandle == null) { return; } ConnectionServiceWrapper service = mConnectionServiceRepository.getService( phoneAccountHandle.getComponentName(), phoneAccountHandle.getUserHandle()); if (service == null) { Log.i(this, "Found no connection service."); return; } else { call.setConnectionService(service); service.createConferenceFailed(call); } } /** * Notifies the {@link android.telecom.ConnectionService} associated with a * {@link PhoneAccountHandle} that the attempt to handover a call has failed. Loading
src/com/android/server/telecom/ConnectionServiceWrapper.java +157 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/com/android/server/telecom/CreateConnectionProcessor.java +62 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.telecom; import android.content.Context; import android.telecom.DisconnectCause; import android.telecom.Log; import android.telecom.ParcelableConference; import android.telecom.ParcelableConnection; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; Loading Loading @@ -245,7 +246,11 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { mCall.setConnectionService(mService); setTimeoutIfNeeded(mService, attempt); if (mCall.isIncoming()) { if (mCall.isAdhocConferenceCall()) { mService.createConference(mCall, CreateConnectionProcessor.this); } else { mService.createConnection(mCall, CreateConnectionProcessor.this); } } else { // Start to create the connection for outgoing call after the ConnectionService // of the call has gained the focus. Loading @@ -254,11 +259,17 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { new CallsManager.RequestCallback(new CallsManager.PendingAction() { @Override public void performAction() { if (mCall.isAdhocConferenceCall()) { Log.d(this, "perform create conference"); mService.createConference(mCall, CreateConnectionProcessor.this); } else { Log.d(this, "perform create connection"); mService.createConnection( mCall, CreateConnectionProcessor.this); } } })); } Loading @@ -267,9 +278,13 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { Log.v(this, "attemptNextPhoneAccount, no more accounts, failing"); DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ? mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR); if (mCall.isAdhocConferenceCall()) { notifyConferenceCallFailure(disconnectCause); } else { notifyCallConnectionFailure(disconnectCause); } } } private void setTimeoutIfNeeded(ConnectionServiceWrapper service, CallAttemptRecord attempt) { clearTimeout(); Loading Loading @@ -457,6 +472,16 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { } } private void notifyConferenceCallFailure(DisconnectCause errorDisconnectCause) { if (mCallResponse != null) { clearTimeout(); mCallResponse.handleCreateConferenceFailure(errorDisconnectCause); mCallResponse = null; mCall.clearConnectionService(); } } @Override public void handleCreateConnectionSuccess( CallIdMapper idMapper, Loading @@ -475,6 +500,25 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { } } @Override public void handleCreateConferenceSuccess( CallIdMapper idMapper, ParcelableConference conference) { if (mCallResponse == null) { // Nobody is listening for this conference attempt any longer; ask the responsible // ConnectionService to tear down any resources associated with the call mService.abort(mCall); } else { // Success -- share the good news and remember that we are no longer interested // in hearing about any more attempts mCallResponse.handleCreateConferenceSuccess(idMapper, conference); mCallResponse = null; // If there's a timeout running then don't clear it. The timeout can be triggered // after the call has successfully been created but before it has become active. } } private boolean shouldFailCallIfConnectionManagerFails(DisconnectCause cause) { // Connection Manager does not exist or does not match registered Connection Manager // Since Connection manager is a proxy for SIM, fall back to SIM Loading Loading @@ -522,6 +566,18 @@ public class CreateConnectionProcessor implements CreateConnectionResponse { attemptNextPhoneAccount(); } @Override public void handleCreateConferenceFailure(DisconnectCause errorDisconnectCause) { // Failure of some sort; record the reasons for failure and try again if possible Log.d(CreateConnectionProcessor.this, "Conference failed: (%s)", errorDisconnectCause); if (shouldFailCallIfConnectionManagerFails(errorDisconnectCause)) { notifyConferenceCallFailure(errorDisconnectCause); return; } mLastErrorDisconnectCause = errorDisconnectCause; attemptNextPhoneAccount(); } public void sortSimPhoneAccountsForEmergency(List<PhoneAccount> accounts, PhoneAccount userPreferredAccount) { // Sort the accounts according to how we want to display them (ascending order). Loading
src/com/android/server/telecom/CreateConnectionResponse.java +4 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.telecom; import android.telecom.DisconnectCause; import android.telecom.ParcelableConference; import android.telecom.ParcelableConnection; import com.android.internal.annotations.VisibleForTesting; Loading @@ -28,4 +29,7 @@ import com.android.internal.annotations.VisibleForTesting; public interface CreateConnectionResponse { void handleCreateConnectionSuccess(CallIdMapper idMapper, ParcelableConnection connection); void handleCreateConnectionFailure(DisconnectCause disconnectCaused); void handleCreateConferenceSuccess(CallIdMapper idMapper, ParcelableConference conference); void handleCreateConferenceFailure(DisconnectCause disconnectCaused); }