Loading src/com/android/server/telecom/Call.java +32 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import android.telecom.Connection; import android.telecom.ConnectionService; import android.telecom.DisconnectCause; import android.telecom.GatewayInfo; import android.telecom.InCallService; import android.telecom.Log; import android.telecom.Logging.EventManager; import android.telecom.ParcelableConference; Loading @@ -58,6 +59,7 @@ import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import android.text.TextUtils; import android.util.ArrayMap; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -509,6 +511,15 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, */ private boolean mIsSelfManaged = false; /** * Indicates whether the {@link PhoneAccount} associated with an self-managed call want to * expose the call to an {@link android.telecom.InCallService} which declares the metadata * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS}, * For calls that {@link #mIsSelfManaged} is {@code false}, this value should be {@code false} * as well. */ private boolean mVisibleToInCallService = false; /** * Indicates whether the {@link PhoneAccount} associated with this call supports video calling. * {@code True} if the phone account supports video calling, {@code false} otherwise. Loading Loading @@ -1628,6 +1639,14 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, setConnectionProperties(getConnectionProperties()); } public boolean visibleToInCallService() { return mVisibleToInCallService; } public void setVisibleToInCallService(boolean visibleToInCallService) { mVisibleToInCallService = visibleToInCallService; } public void markFinishedHandoverStateAndCleanup(int handoverState) { if (mHandoverSourceCall != null) { mHandoverSourceCall.setHandoverState(handoverState); Loading Loading @@ -3949,4 +3968,17 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, public void setCallScreeningComponentName(String callScreeningComponentName) { mCallScreeningComponentName = callScreeningComponentName; } public void maybeOnInCallServiceTrackingChanged(boolean isTracking, boolean hasUi) { if (mConnectionService == null) { Log.w(this, "maybeOnInCallServiceTrackingChanged() request on a call" + " without a connection service."); } else { if (hasUi) { mConnectionService.onUsingAlternativeUi(this, isTracking); } else if (isTracking) { mConnectionService.onTrackedByNonUiService(this, isTracking); } } } } src/com/android/server/telecom/CallsManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -1245,10 +1245,14 @@ public class CallsManager extends Call.ListenerBase PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( phoneAccountHandle); if (phoneAccount != null) { Bundle phoneAccountExtras = phoneAccount.getExtras(); call.setIsSelfManaged(phoneAccount.isSelfManaged()); if (call.isSelfManaged()) { // Self managed calls will always be voip audio mode. call.setIsVoipAudioMode(true); call.setVisibleToInCallService(phoneAccountExtras != null && phoneAccountExtras.getBoolean( PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false)); } else { // Incoming call is managed, the active call is self-managed and can't be held. // We need to set extras on it to indicate whether answering will cause a Loading @@ -1267,7 +1271,6 @@ public class CallsManager extends Call.ListenerBase } } Bundle phoneAccountExtras = phoneAccount.getExtras(); if (phoneAccountExtras != null && phoneAccountExtras.getBoolean( PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { Loading Loading @@ -1482,6 +1485,7 @@ public class CallsManager extends Call.ListenerBase PhoneAccount account = mPhoneAccountRegistrar.getPhoneAccount(requestedAccountHandle, initiatingUser); Bundle phoneAccountExtra = account != null ? account.getExtras() : null; boolean isSelfManaged = account != null && account.isSelfManaged(); // Create a call with original handle. The handle may be changed when the call is attached Loading Loading @@ -1512,6 +1516,9 @@ public class CallsManager extends Call.ListenerBase if (isSelfManaged) { // Self-managed calls will ALWAYS use voip audio mode. call.setIsVoipAudioMode(true); call.setVisibleToInCallService(phoneAccountExtra != null && phoneAccountExtra.getBoolean( PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false)); } call.setInitiatingUser(initiatingUser); isReusedCall = false; Loading Loading @@ -4748,6 +4755,9 @@ public class CallsManager extends Call.ListenerBase extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS, SystemClock.elapsedRealtime()); if (call.visibleToInCallService()) { extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true); } call.setIntentExtras(extras); } Loading src/com/android/server/telecom/ConnectionServiceWrapper.java +28 −0 Original line number Diff line number Diff line Loading @@ -1574,6 +1574,34 @@ public class ConnectionServiceWrapper extends ServiceBinder implements } } /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */ @VisibleForTesting public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) { final String callId = mCallIdMapper.getCallId(activeCall); if (callId != null && isServiceValid("onUsingAlternativeUi")) { try { logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi); mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi, Log.getExternalSession(TELECOM_ABBREVIATION)); } catch (RemoteException e) { } } } /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */ @VisibleForTesting public void onTrackedByNonUiService(Call activeCall, boolean isTracked) { final String callId = mCallIdMapper.getCallId(activeCall); if (callId != null && isServiceValid("onTrackedByNonUiService")) { try { logOutgoing("onTrackedByNonUiService %s", isTracked); mServiceInterface.onTrackedByNonUiService(callId, isTracked, Log.getExternalSession(TELECOM_ABBREVIATION)); } catch (RemoteException e) { } } } /** @see IConnectionService#disconnect(String, Session.Info) */ void disconnect(Call call) { final String callId = mCallIdMapper.getCallId(call); Loading src/com/android/server/telecom/InCallController.java +71 −34 Original line number Diff line number Diff line Loading @@ -113,7 +113,7 @@ public class InCallController extends CallsManagerListenerBase { public Call mCall; } private class InCallServiceInfo { public static class InCallServiceInfo { private final ComponentName mComponentName; private boolean mIsExternalCallsSupported; private boolean mIsSelfManagedCallsSupported; Loading Loading @@ -279,7 +279,8 @@ public class InCallController extends CallsManagerListenerBase { } if (call != null && call.isSelfManaged() && !mInCallServiceInfo.isSelfManagedCallsSupported()) { (!mInCallServiceInfo.isSelfManagedCallsSupported() || !call.visibleToInCallService())) { Log.i(this, "Skipping binding to %s - doesn't support self-mgd calls", mInCallServiceInfo); mIsConnected = false; Loading Loading @@ -342,6 +343,7 @@ public class InCallController extends CallsManagerListenerBase { mInCallServiceInfo.getType(), mInCallServiceInfo.getDisconnectTime() - mInCallServiceInfo.getBindingStartTime(), mIsNullBinding); updateCallTracking(mCall, mInCallServiceInfo, false /* isAdd */); } InCallController.this.onDisconnected(mInCallServiceInfo); Loading Loading @@ -748,6 +750,10 @@ public class InCallController extends CallsManagerListenerBase { newConnection.connect(callToConnectWith); } } public List<InCallServiceBindingConnection> getSubConnections() { return mSubConnections; } } private final Call.Listener mCallListener = new Call.ListenerBase() { Loading Loading @@ -925,12 +931,12 @@ public class InCallController extends CallsManagerListenerBase { @Override public void onPackageUninstalled(String packageName) { mCarModeTracker.forceRemove(packageName); updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } }; private static final int IN_CALL_SERVICE_TYPE_INVALID = 0; private static final int IN_CALL_SERVICE_TYPE_DIALER_UI = 1; private static final int IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI = 1; private static final int IN_CALL_SERVICE_TYPE_SYSTEM_UI = 2; private static final int IN_CALL_SERVICE_TYPE_CAR_MODE_UI = 3; private static final int IN_CALL_SERVICE_TYPE_NON_UI = 4; Loading Loading @@ -977,10 +983,9 @@ public class InCallController extends CallsManagerListenerBase { private boolean mIsCallUsingMicrophone = false; public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager, SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker, ClockProxy clockProxy) { SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker, ClockProxy clockProxy) { mContext = context; mAppOpsManager = context.getSystemService(AppOpsManager.class); mLock = lock; Loading Loading @@ -1023,12 +1028,16 @@ public class InCallController extends CallsManagerListenerBase { continue; } if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) { if (call.isSelfManaged() && (!call.visibleToInCallService() || !info.isSelfManagedCallsSupported())) { continue; } // Only send the RTT call if it's a UI in-call service boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo()); boolean includeRttCall = false; if (mInCallServiceConnection != null) { includeRttCall = info.equals(mInCallServiceConnection.getInfo()); } componentsUpdated.add(info.getComponentName()); IInCallService inCallService = entry.getValue(); Loading @@ -1040,6 +1049,7 @@ public class InCallController extends CallsManagerListenerBase { info.getType() == IN_CALL_SERVICE_TYPE_NON_UI); try { inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall)); updateCallTracking(call, info, true /* isAdd */); } catch (RemoteException ignored) { } } Loading Loading @@ -1089,7 +1099,8 @@ public class InCallController extends CallsManagerListenerBase { continue; } if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) { if (call.isSelfManaged() && !call.visibleToInCallService() && !info.isSelfManagedCallsSupported()) { continue; } Loading @@ -1106,6 +1117,7 @@ public class InCallController extends CallsManagerListenerBase { info.getType() == IN_CALL_SERVICE_TYPE_NON_UI); try { inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall)); updateCallTracking(call, info, true /* isAdd */); } catch (RemoteException ignored) { } } Loading Loading @@ -1366,7 +1378,8 @@ public class InCallController extends CallsManagerListenerBase { /** * Binds to all the UI-providing InCallService as well as system-implemented non-UI * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()} before invoking. * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()} * before invoking. * * @param call The newly added call that triggered the binding to the in-call services. */ Loading Loading @@ -1419,7 +1432,7 @@ public class InCallController extends CallsManagerListenerBase { } } private void connectToNonUiInCallServices(Call call) { private void updateNonUiInCallServices() { List<InCallServiceInfo> nonUIInCallComponents = getInCallServiceComponents(IN_CALL_SERVICE_TYPE_NON_UI); List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>(); Loading @@ -1437,7 +1450,14 @@ public class InCallController extends CallsManagerListenerBase { } } } mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls); mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection( nonUIInCalls); } private void connectToNonUiInCallServices(Call call) { if (mNonUIInCallServiceConnections == null) { updateNonUiInCallServices(); } mNonUIInCallServiceConnections.connect(call); IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED); Loading @@ -1454,7 +1474,7 @@ public class InCallController extends CallsManagerListenerBase { InCallServiceInfo defaultDialerComponent = (systemPackageName != null && systemPackageName.equals(packageName)) ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI) : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI); : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI); /* TODO: in Android 12 re-enable this an InCallService is required by the dialer role. if (packageName != null && defaultDialerComponent == null) { // The in call service of default phone app is disabled, send notification. Loading Loading @@ -1504,7 +1524,6 @@ public class InCallController extends CallsManagerListenerBase { private List<InCallServiceInfo> getInCallServiceComponents(String packageName, ComponentName componentName, int requestedType) { List<InCallServiceInfo> retval = new LinkedList<>(); Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE); Loading Loading @@ -1539,13 +1558,18 @@ public class InCallController extends CallsManagerListenerBase { boolean isEnabled = isServiceEnabled(foundComponentName, serviceInfo, packageManager); if (isEnabled && (requestedType == 0 || requestedType == currentType)) { retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported, isSelfManageCallsSupported, requestedType)); boolean isRequestedType; if (requestedType == IN_CALL_SERVICE_TYPE_INVALID) { isRequestedType = true; } else { isRequestedType = requestedType == currentType; } if (isEnabled && isRequestedType) { retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported, isSelfManageCallsSupported, requestedType)); } } } return retval; } Loading Loading @@ -1626,7 +1650,7 @@ public class InCallController extends CallsManagerListenerBase { mDefaultDialerCache.getDefaultDialerApplication( mCallsManager.getCurrentUserHandle().getIdentifier())); if (isDefaultDialerPackage && isUIService) { return IN_CALL_SERVICE_TYPE_DIALER_UI; return IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI; } // Also allow any in-call service that has the control-experience permission (to ensure Loading Loading @@ -1665,7 +1689,7 @@ public class InCallController extends CallsManagerListenerBase { if (info.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI || info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI || info.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) { || info.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) { trackCallingUserInterfaceStarted(info); } IInCallService inCallService = IInCallService.Stub.asInterface(service); Loading @@ -1691,13 +1715,17 @@ public class InCallController extends CallsManagerListenerBase { int numCallsSent = 0; for (Call call : calls) { try { if ((call.isSelfManaged() && !info.isSelfManagedCallsSupported()) || if ((call.isSelfManaged() && (!info.isSelfManagedCallsSupported() || !call.visibleToInCallService())) || (call.isExternalCall() && !info.isExternalCallsSupported())) { continue; } // Only send the RTT call if it's a UI in-call service boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo()); boolean includeRttCall = false; if (mInCallServiceConnection != null) { includeRttCall = info.equals(mInCallServiceConnection.getInfo()); } // Track the call if we don't already know about it. addCall(call); Loading @@ -1711,6 +1739,7 @@ public class InCallController extends CallsManagerListenerBase { info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI || info.getType() == IN_CALL_SERVICE_TYPE_NON_UI); inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall)); updateCallTracking(call, info, true /* isAdd */); } catch (RemoteException ignored) { } } Loading @@ -1737,7 +1766,7 @@ public class InCallController extends CallsManagerListenerBase { Log.i(this, "onDisconnected from %s", disconnectedInfo.getComponentName()); if (disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) { || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) { trackCallingUserInterfaceStopped(disconnectedInfo); } mInCallServices.remove(disconnectedInfo); Loading Loading @@ -1771,7 +1800,8 @@ public class InCallController extends CallsManagerListenerBase { continue; } if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) { if (call.isSelfManaged() && (!call.visibleToInCallService() || !info.isSelfManagedCallsSupported())) { continue; } Loading Loading @@ -1852,7 +1882,7 @@ public class InCallController extends CallsManagerListenerBase { */ private ComponentName getConnectedUi() { InCallServiceInfo connectedUi = mInCallServices.keySet().stream().filter( i -> i.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI i -> i.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI || i.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI) .findAny() .orElse(null); Loading Loading @@ -1970,7 +2000,7 @@ public class InCallController extends CallsManagerListenerBase { mCarModeTracker.handleExitCarMode(priority, packageName); } updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } public void handleSetAutomotiveProjection(@NonNull String packageName) { Loading @@ -1982,20 +2012,20 @@ public class InCallController extends CallsManagerListenerBase { } mCarModeTracker.handleSetAutomotiveProjection(packageName); updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } public void handleReleaseAutomotiveProjection() { Log.i(this, "handleReleaseAutomotiveProjection"); mCarModeTracker.handleReleaseAutomotiveProjection(); updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } public void updateCarModeForSwitchingConnection() { if (mInCallServiceConnection != null) { Log.i(this, "updateCarModeForSwitchingConnection: car mode apps: %s", public void updateCarModeForConnections() { Log.i(this, "updateCarModeForConnections: car mode apps: %s", mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", "))); if (mInCallServiceConnection != null) { if (shouldUseCarModeUI()) { mInCallServiceConnection.changeCarModeApp( mCarModeTracker.getCurrentCarModePackage()); Loading Loading @@ -2105,4 +2135,11 @@ public class InCallController extends CallsManagerListenerBase { notificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID, builder.build()); } private void updateCallTracking(Call call, InCallServiceInfo info, boolean isAdd) { int type = info.getType(); boolean hasUi = type == IN_CALL_SERVICE_TYPE_CAR_MODE_UI || type == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI; call.maybeOnInCallServiceTrackingChanged(isAdd, hasUi); } } testapps/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,8 @@ android:exported="true"> <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true"/> <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS" android:value="true" /> <intent-filter> <action android:name="android.telecom.InCallService"/> </intent-filter> Loading Loading
src/com/android/server/telecom/Call.java +32 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import android.telecom.Connection; import android.telecom.ConnectionService; import android.telecom.DisconnectCause; import android.telecom.GatewayInfo; import android.telecom.InCallService; import android.telecom.Log; import android.telecom.Logging.EventManager; import android.telecom.ParcelableConference; Loading @@ -58,6 +59,7 @@ import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import android.text.TextUtils; import android.util.ArrayMap; import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -509,6 +511,15 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, */ private boolean mIsSelfManaged = false; /** * Indicates whether the {@link PhoneAccount} associated with an self-managed call want to * expose the call to an {@link android.telecom.InCallService} which declares the metadata * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS}, * For calls that {@link #mIsSelfManaged} is {@code false}, this value should be {@code false} * as well. */ private boolean mVisibleToInCallService = false; /** * Indicates whether the {@link PhoneAccount} associated with this call supports video calling. * {@code True} if the phone account supports video calling, {@code false} otherwise. Loading Loading @@ -1628,6 +1639,14 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, setConnectionProperties(getConnectionProperties()); } public boolean visibleToInCallService() { return mVisibleToInCallService; } public void setVisibleToInCallService(boolean visibleToInCallService) { mVisibleToInCallService = visibleToInCallService; } public void markFinishedHandoverStateAndCleanup(int handoverState) { if (mHandoverSourceCall != null) { mHandoverSourceCall.setHandoverState(handoverState); Loading Loading @@ -3949,4 +3968,17 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, public void setCallScreeningComponentName(String callScreeningComponentName) { mCallScreeningComponentName = callScreeningComponentName; } public void maybeOnInCallServiceTrackingChanged(boolean isTracking, boolean hasUi) { if (mConnectionService == null) { Log.w(this, "maybeOnInCallServiceTrackingChanged() request on a call" + " without a connection service."); } else { if (hasUi) { mConnectionService.onUsingAlternativeUi(this, isTracking); } else if (isTracking) { mConnectionService.onTrackedByNonUiService(this, isTracking); } } } }
src/com/android/server/telecom/CallsManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -1245,10 +1245,14 @@ public class CallsManager extends Call.ListenerBase PhoneAccount phoneAccount = mPhoneAccountRegistrar.getPhoneAccountUnchecked( phoneAccountHandle); if (phoneAccount != null) { Bundle phoneAccountExtras = phoneAccount.getExtras(); call.setIsSelfManaged(phoneAccount.isSelfManaged()); if (call.isSelfManaged()) { // Self managed calls will always be voip audio mode. call.setIsVoipAudioMode(true); call.setVisibleToInCallService(phoneAccountExtras != null && phoneAccountExtras.getBoolean( PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false)); } else { // Incoming call is managed, the active call is self-managed and can't be held. // We need to set extras on it to indicate whether answering will cause a Loading @@ -1267,7 +1271,6 @@ public class CallsManager extends Call.ListenerBase } } Bundle phoneAccountExtras = phoneAccount.getExtras(); if (phoneAccountExtras != null && phoneAccountExtras.getBoolean( PhoneAccount.EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE)) { Loading Loading @@ -1482,6 +1485,7 @@ public class CallsManager extends Call.ListenerBase PhoneAccount account = mPhoneAccountRegistrar.getPhoneAccount(requestedAccountHandle, initiatingUser); Bundle phoneAccountExtra = account != null ? account.getExtras() : null; boolean isSelfManaged = account != null && account.isSelfManaged(); // Create a call with original handle. The handle may be changed when the call is attached Loading Loading @@ -1512,6 +1516,9 @@ public class CallsManager extends Call.ListenerBase if (isSelfManaged) { // Self-managed calls will ALWAYS use voip audio mode. call.setIsVoipAudioMode(true); call.setVisibleToInCallService(phoneAccountExtra != null && phoneAccountExtra.getBoolean( PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false)); } call.setInitiatingUser(initiatingUser); isReusedCall = false; Loading Loading @@ -4748,6 +4755,9 @@ public class CallsManager extends Call.ListenerBase extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_START_TIME_MILLIS, SystemClock.elapsedRealtime()); if (call.visibleToInCallService()) { extras.putBoolean(PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true); } call.setIntentExtras(extras); } Loading
src/com/android/server/telecom/ConnectionServiceWrapper.java +28 −0 Original line number Diff line number Diff line Loading @@ -1574,6 +1574,34 @@ public class ConnectionServiceWrapper extends ServiceBinder implements } } /** @see IConnectionService#onUsingAlternativeUi(String, boolean, Session.Info) */ @VisibleForTesting public void onUsingAlternativeUi(Call activeCall, boolean isUsingAlternativeUi) { final String callId = mCallIdMapper.getCallId(activeCall); if (callId != null && isServiceValid("onUsingAlternativeUi")) { try { logOutgoing("onUsingAlternativeUi %s", isUsingAlternativeUi); mServiceInterface.onUsingAlternativeUi(callId, isUsingAlternativeUi, Log.getExternalSession(TELECOM_ABBREVIATION)); } catch (RemoteException e) { } } } /** @see IConnectionService#onTrackedByNonUiService(String, boolean, Session.Info) */ @VisibleForTesting public void onTrackedByNonUiService(Call activeCall, boolean isTracked) { final String callId = mCallIdMapper.getCallId(activeCall); if (callId != null && isServiceValid("onTrackedByNonUiService")) { try { logOutgoing("onTrackedByNonUiService %s", isTracked); mServiceInterface.onTrackedByNonUiService(callId, isTracked, Log.getExternalSession(TELECOM_ABBREVIATION)); } catch (RemoteException e) { } } } /** @see IConnectionService#disconnect(String, Session.Info) */ void disconnect(Call call) { final String callId = mCallIdMapper.getCallId(call); Loading
src/com/android/server/telecom/InCallController.java +71 −34 Original line number Diff line number Diff line Loading @@ -113,7 +113,7 @@ public class InCallController extends CallsManagerListenerBase { public Call mCall; } private class InCallServiceInfo { public static class InCallServiceInfo { private final ComponentName mComponentName; private boolean mIsExternalCallsSupported; private boolean mIsSelfManagedCallsSupported; Loading Loading @@ -279,7 +279,8 @@ public class InCallController extends CallsManagerListenerBase { } if (call != null && call.isSelfManaged() && !mInCallServiceInfo.isSelfManagedCallsSupported()) { (!mInCallServiceInfo.isSelfManagedCallsSupported() || !call.visibleToInCallService())) { Log.i(this, "Skipping binding to %s - doesn't support self-mgd calls", mInCallServiceInfo); mIsConnected = false; Loading Loading @@ -342,6 +343,7 @@ public class InCallController extends CallsManagerListenerBase { mInCallServiceInfo.getType(), mInCallServiceInfo.getDisconnectTime() - mInCallServiceInfo.getBindingStartTime(), mIsNullBinding); updateCallTracking(mCall, mInCallServiceInfo, false /* isAdd */); } InCallController.this.onDisconnected(mInCallServiceInfo); Loading Loading @@ -748,6 +750,10 @@ public class InCallController extends CallsManagerListenerBase { newConnection.connect(callToConnectWith); } } public List<InCallServiceBindingConnection> getSubConnections() { return mSubConnections; } } private final Call.Listener mCallListener = new Call.ListenerBase() { Loading Loading @@ -925,12 +931,12 @@ public class InCallController extends CallsManagerListenerBase { @Override public void onPackageUninstalled(String packageName) { mCarModeTracker.forceRemove(packageName); updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } }; private static final int IN_CALL_SERVICE_TYPE_INVALID = 0; private static final int IN_CALL_SERVICE_TYPE_DIALER_UI = 1; private static final int IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI = 1; private static final int IN_CALL_SERVICE_TYPE_SYSTEM_UI = 2; private static final int IN_CALL_SERVICE_TYPE_CAR_MODE_UI = 3; private static final int IN_CALL_SERVICE_TYPE_NON_UI = 4; Loading Loading @@ -977,10 +983,9 @@ public class InCallController extends CallsManagerListenerBase { private boolean mIsCallUsingMicrophone = false; public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager, SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker, ClockProxy clockProxy) { SystemStateHelper systemStateHelper, DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter, EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker, ClockProxy clockProxy) { mContext = context; mAppOpsManager = context.getSystemService(AppOpsManager.class); mLock = lock; Loading Loading @@ -1023,12 +1028,16 @@ public class InCallController extends CallsManagerListenerBase { continue; } if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) { if (call.isSelfManaged() && (!call.visibleToInCallService() || !info.isSelfManagedCallsSupported())) { continue; } // Only send the RTT call if it's a UI in-call service boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo()); boolean includeRttCall = false; if (mInCallServiceConnection != null) { includeRttCall = info.equals(mInCallServiceConnection.getInfo()); } componentsUpdated.add(info.getComponentName()); IInCallService inCallService = entry.getValue(); Loading @@ -1040,6 +1049,7 @@ public class InCallController extends CallsManagerListenerBase { info.getType() == IN_CALL_SERVICE_TYPE_NON_UI); try { inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall)); updateCallTracking(call, info, true /* isAdd */); } catch (RemoteException ignored) { } } Loading Loading @@ -1089,7 +1099,8 @@ public class InCallController extends CallsManagerListenerBase { continue; } if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) { if (call.isSelfManaged() && !call.visibleToInCallService() && !info.isSelfManagedCallsSupported()) { continue; } Loading @@ -1106,6 +1117,7 @@ public class InCallController extends CallsManagerListenerBase { info.getType() == IN_CALL_SERVICE_TYPE_NON_UI); try { inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall)); updateCallTracking(call, info, true /* isAdd */); } catch (RemoteException ignored) { } } Loading Loading @@ -1366,7 +1378,8 @@ public class InCallController extends CallsManagerListenerBase { /** * Binds to all the UI-providing InCallService as well as system-implemented non-UI * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()} before invoking. * InCallServices. Method-invoker must check {@link #isBoundAndConnectedToServices()} * before invoking. * * @param call The newly added call that triggered the binding to the in-call services. */ Loading Loading @@ -1419,7 +1432,7 @@ public class InCallController extends CallsManagerListenerBase { } } private void connectToNonUiInCallServices(Call call) { private void updateNonUiInCallServices() { List<InCallServiceInfo> nonUIInCallComponents = getInCallServiceComponents(IN_CALL_SERVICE_TYPE_NON_UI); List<InCallServiceBindingConnection> nonUIInCalls = new LinkedList<>(); Loading @@ -1437,7 +1450,14 @@ public class InCallController extends CallsManagerListenerBase { } } } mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls); mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection( nonUIInCalls); } private void connectToNonUiInCallServices(Call call) { if (mNonUIInCallServiceConnections == null) { updateNonUiInCallServices(); } mNonUIInCallServiceConnections.connect(call); IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED); Loading @@ -1454,7 +1474,7 @@ public class InCallController extends CallsManagerListenerBase { InCallServiceInfo defaultDialerComponent = (systemPackageName != null && systemPackageName.equals(packageName)) ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI) : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DIALER_UI); : getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI); /* TODO: in Android 12 re-enable this an InCallService is required by the dialer role. if (packageName != null && defaultDialerComponent == null) { // The in call service of default phone app is disabled, send notification. Loading Loading @@ -1504,7 +1524,6 @@ public class InCallController extends CallsManagerListenerBase { private List<InCallServiceInfo> getInCallServiceComponents(String packageName, ComponentName componentName, int requestedType) { List<InCallServiceInfo> retval = new LinkedList<>(); Intent serviceIntent = new Intent(InCallService.SERVICE_INTERFACE); Loading Loading @@ -1539,13 +1558,18 @@ public class InCallController extends CallsManagerListenerBase { boolean isEnabled = isServiceEnabled(foundComponentName, serviceInfo, packageManager); if (isEnabled && (requestedType == 0 || requestedType == currentType)) { retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported, isSelfManageCallsSupported, requestedType)); boolean isRequestedType; if (requestedType == IN_CALL_SERVICE_TYPE_INVALID) { isRequestedType = true; } else { isRequestedType = requestedType == currentType; } if (isEnabled && isRequestedType) { retval.add(new InCallServiceInfo(foundComponentName, isExternalCallsSupported, isSelfManageCallsSupported, requestedType)); } } } return retval; } Loading Loading @@ -1626,7 +1650,7 @@ public class InCallController extends CallsManagerListenerBase { mDefaultDialerCache.getDefaultDialerApplication( mCallsManager.getCurrentUserHandle().getIdentifier())); if (isDefaultDialerPackage && isUIService) { return IN_CALL_SERVICE_TYPE_DIALER_UI; return IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI; } // Also allow any in-call service that has the control-experience permission (to ensure Loading Loading @@ -1665,7 +1689,7 @@ public class InCallController extends CallsManagerListenerBase { if (info.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI || info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI || info.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) { || info.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) { trackCallingUserInterfaceStarted(info); } IInCallService inCallService = IInCallService.Stub.asInterface(service); Loading @@ -1691,13 +1715,17 @@ public class InCallController extends CallsManagerListenerBase { int numCallsSent = 0; for (Call call : calls) { try { if ((call.isSelfManaged() && !info.isSelfManagedCallsSupported()) || if ((call.isSelfManaged() && (!info.isSelfManagedCallsSupported() || !call.visibleToInCallService())) || (call.isExternalCall() && !info.isExternalCallsSupported())) { continue; } // Only send the RTT call if it's a UI in-call service boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo()); boolean includeRttCall = false; if (mInCallServiceConnection != null) { includeRttCall = info.equals(mInCallServiceConnection.getInfo()); } // Track the call if we don't already know about it. addCall(call); Loading @@ -1711,6 +1739,7 @@ public class InCallController extends CallsManagerListenerBase { info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI || info.getType() == IN_CALL_SERVICE_TYPE_NON_UI); inCallService.addCall(sanitizeParcelableCallForService(info, parcelableCall)); updateCallTracking(call, info, true /* isAdd */); } catch (RemoteException ignored) { } } Loading @@ -1737,7 +1766,7 @@ public class InCallController extends CallsManagerListenerBase { Log.i(this, "onDisconnected from %s", disconnectedInfo.getComponentName()); if (disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_CAR_MODE_UI || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI) { || disconnectedInfo.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI) { trackCallingUserInterfaceStopped(disconnectedInfo); } mInCallServices.remove(disconnectedInfo); Loading Loading @@ -1771,7 +1800,8 @@ public class InCallController extends CallsManagerListenerBase { continue; } if (call.isSelfManaged() && !info.isSelfManagedCallsSupported()) { if (call.isSelfManaged() && (!call.visibleToInCallService() || !info.isSelfManagedCallsSupported())) { continue; } Loading Loading @@ -1852,7 +1882,7 @@ public class InCallController extends CallsManagerListenerBase { */ private ComponentName getConnectedUi() { InCallServiceInfo connectedUi = mInCallServices.keySet().stream().filter( i -> i.getType() == IN_CALL_SERVICE_TYPE_DIALER_UI i -> i.getType() == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI || i.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI) .findAny() .orElse(null); Loading Loading @@ -1970,7 +2000,7 @@ public class InCallController extends CallsManagerListenerBase { mCarModeTracker.handleExitCarMode(priority, packageName); } updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } public void handleSetAutomotiveProjection(@NonNull String packageName) { Loading @@ -1982,20 +2012,20 @@ public class InCallController extends CallsManagerListenerBase { } mCarModeTracker.handleSetAutomotiveProjection(packageName); updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } public void handleReleaseAutomotiveProjection() { Log.i(this, "handleReleaseAutomotiveProjection"); mCarModeTracker.handleReleaseAutomotiveProjection(); updateCarModeForSwitchingConnection(); updateCarModeForConnections(); } public void updateCarModeForSwitchingConnection() { if (mInCallServiceConnection != null) { Log.i(this, "updateCarModeForSwitchingConnection: car mode apps: %s", public void updateCarModeForConnections() { Log.i(this, "updateCarModeForConnections: car mode apps: %s", mCarModeTracker.getCarModeApps().stream().collect(Collectors.joining(", "))); if (mInCallServiceConnection != null) { if (shouldUseCarModeUI()) { mInCallServiceConnection.changeCarModeApp( mCarModeTracker.getCurrentCarModePackage()); Loading Loading @@ -2105,4 +2135,11 @@ public class InCallController extends CallsManagerListenerBase { notificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID, builder.build()); } private void updateCallTracking(Call call, InCallServiceInfo info, boolean isAdd) { int type = info.getType(); boolean hasUi = type == IN_CALL_SERVICE_TYPE_CAR_MODE_UI || type == IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI; call.maybeOnInCallServiceTrackingChanged(isAdd, hasUi); } }
testapps/AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,8 @@ android:exported="true"> <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true"/> <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS" android:value="true" /> <intent-filter> <action android:name="android.telecom.InCallService"/> </intent-filter> Loading