Loading src/com/android/server/telecom/CallsManager.java +88 −5 Original line number Diff line number Diff line Loading @@ -82,7 +82,6 @@ import android.provider.BlockedNumberContract; import android.provider.BlockedNumberContract.BlockedNumbers; import android.provider.CallLog.Calls; import android.provider.Settings; import android.sysprop.TelephonyProperties; import android.telecom.CallAttributes; import android.telecom.CallAudioState; import android.telecom.CallEndpoint; Loading Loading @@ -165,7 +164,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; Loading Loading @@ -491,6 +489,7 @@ public class CallsManager extends Call.ListenerBase private final UserManager mUserManager; private final CallStreamingNotification mCallStreamingNotification; private final FeatureFlags mFeatureFlags; private final com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags; private final IncomingCallFilterGraphProvider mIncomingCallFilterGraphProvider; Loading Loading @@ -610,6 +609,7 @@ public class CallsManager extends Call.ListenerBase CallStreamingNotification callStreamingNotification, BluetoothDeviceManager bluetoothDeviceManager, FeatureFlags featureFlags, com.android.internal.telephony.flags.FeatureFlags telephonyFlags, IncomingCallFilterGraphProvider incomingCallFilterGraphProvider) { mContext = context; Loading Loading @@ -717,6 +717,7 @@ public class CallsManager extends Call.ListenerBase mCallStreamingController = new CallStreamingController(mContext, mLock); mCallStreamingNotification = callStreamingNotification; mFeatureFlags = featureFlags; mTelephonyFeatureFlags = telephonyFlags; if (mFeatureFlags.useImprovedListenerOrder()) { mListeners.add(mInCallController); Loading Loading @@ -3428,8 +3429,14 @@ public class CallsManager extends Call.ListenerBase // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP. @VisibleForTesting public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency) { return constructPossiblePhoneAccounts(handle, user, isVideo, isEmergency, false); boolean isVideo, boolean isEmergency, boolean isConference) { if (mTelephonyFeatureFlags.simultaneousCallingIndications()) { return constructPossiblePhoneAccountsNew(handle, user, isVideo, isEmergency, isConference); } else { return constructPossiblePhoneAccountsOld(handle, user, isVideo, isEmergency, isConference); } } // Returns whether the device is capable of 2 simultaneous active voice calls on different subs. Loading @@ -3444,7 +3451,7 @@ public class CallsManager extends Call.ListenerBase } } public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, private List<PhoneAccountHandle> constructPossiblePhoneAccountsOld(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency, boolean isConference) { if (handle == null) { Loading Loading @@ -3485,6 +3492,82 @@ public class CallsManager extends Call.ListenerBase return allAccounts; } /** * Filters the list of all PhoneAccounts that match the outgoing call Handle's schema against * the outgoing call request criteria and the state of the already ongoing calls on the * device and their potential simultaneous calling restrictions. * @return The filtered List */ private List<PhoneAccountHandle> constructPossiblePhoneAccountsNew(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, capabilities, isEmergency ? 0 : PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY, isEmergency); Log.v(this, "constructPossiblePhoneAccountsNew: allAccounts=" + allAccounts); Set<PhoneAccountHandle> activeCallAccounts = mCalls.stream() .filter(c -> !c.isDisconnected() && !c.isNew()).map(Call::getTargetPhoneAccount) .filter(Objects::nonNull) .collect(Collectors.toSet()); Log.v(this, "constructPossiblePhoneAccountsNew: activeCallAccounts=" + activeCallAccounts); // No Active calls - all accounts are valid if (activeCallAccounts.isEmpty()) return allAccounts; // The emergency call should be attempted only over the same SIM PhoneAccounts where there // are already ongoing calls - filter out inactive SIM PhoneAccounts in this case. if (isEmergency) { Set<PhoneAccountHandle> simAccounts = new HashSet<>(mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser()); if (activeCallAccounts.stream().anyMatch(simAccounts::contains)) { allAccounts.removeIf(h -> { boolean isRemoved = simAccounts.contains(h) && !activeCallAccounts.contains(h); if (isRemoved) { Log.i(this, "constructPossiblePhoneAccountsNew: removing candidate PAH [" + h + "] because another SIM account is active with an emergency " + "call"); } return isRemoved; }); } } // Apply restrictions to which PhoneAccounts can be used to place a call by looking at // active calls and removing candidate PhoneAccounts if they are from the same source // as the active call and the candidate PhoneAccount is not part of the restriction. for (PhoneAccountHandle callHandle : activeCallAccounts) { allAccounts.removeIf(candidateHandle -> { PhoneAccount callAcct = mPhoneAccountRegistrar.getPhoneAccount(callHandle, user); if (callAcct == null) { Log.w(this, "constructPossiblePhoneAccountsNew: unexpected" + "null PA for PAH, removing : " + candidateHandle); return true; } boolean isRemoved = !Objects.equals(candidateHandle, callHandle) && Objects.equals(candidateHandle.getComponentName(), callHandle.getComponentName()) && callAcct.hasSimultaneousCallingRestriction() && !callAcct.getSimultaneousCallingRestriction().contains(candidateHandle); if (isRemoved) { Log.i(this, "constructPossiblePhoneAccountsNew: removing candidate" + " PAH [" + candidateHandle + "] because it is not part of the" + " restriction set by [" + callHandle + "], restriction=" + callAcct.getSimultaneousCallingRestriction()); } return isRemoved; }); } return allAccounts; } private TelephonyManager getTelephonyManager() { return mContext.getSystemService(TelephonyManager.class); } Loading src/com/android/server/telecom/TelecomSystem.java +3 −1 Original line number Diff line number Diff line Loading @@ -230,7 +230,8 @@ public class TelecomSystem { Executor asyncTaskExecutor, Executor asyncCallAudioTaskExecutor, BlockedNumbersAdapter blockedNumbersAdapter, FeatureFlags featureFlags) { FeatureFlags featureFlags, com.android.internal.telephony.flags.FeatureFlags telephonyFlags) { mContext = context.getApplicationContext(); mFeatureFlags = featureFlags; LogUtils.initLogging(mContext); Loading Loading @@ -427,6 +428,7 @@ public class TelecomSystem { callStreamingNotification, bluetoothDeviceManager, featureFlags, telephonyFlags, IncomingCallFilterGraph::new); mIncomingCallNotifier = incomingCallNotifier; Loading src/com/android/server/telecom/components/TelecomService.java +2 −1 Original line number Diff line number Diff line Loading @@ -234,7 +234,8 @@ public class TelecomService extends Service implements TelecomSystem.Component { showNotification); } }, new FeatureFlagsImpl())); new FeatureFlagsImpl(), new com.android.internal.telephony.flags.FeatureFlagsImpl())); } } Loading tests/src/com/android/server/telecom/tests/CallsManagerTest.java +297 −9 File changed.Preview size limit exceeded, changes collapsed. Show changes tests/src/com/android/server/telecom/tests/TelecomSystemTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -221,6 +221,8 @@ public class TelecomSystemTest extends TelecomTestCase{ CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker; @Mock FeatureFlags mFeatureFlags; @Mock com.android.internal.telephony.flags.FeatureFlags mTelephonyFlags; final ComponentName mInCallServiceComponentNameX = new ComponentName( Loading Loading @@ -581,7 +583,8 @@ public class TelecomSystemTest extends TelecomTestCase{ Runnable::run, Runnable::run, mBlockedNumbersAdapter, mFeatureFlags); mFeatureFlags, mTelephonyFlags); mComponentContextFixture.setTelecomManager(new TelecomManager( mComponentContextFixture.getTestDouble(), Loading Loading
src/com/android/server/telecom/CallsManager.java +88 −5 Original line number Diff line number Diff line Loading @@ -82,7 +82,6 @@ import android.provider.BlockedNumberContract; import android.provider.BlockedNumberContract.BlockedNumbers; import android.provider.CallLog.Calls; import android.provider.Settings; import android.sysprop.TelephonyProperties; import android.telecom.CallAttributes; import android.telecom.CallAudioState; import android.telecom.CallEndpoint; Loading Loading @@ -165,7 +164,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; Loading Loading @@ -491,6 +489,7 @@ public class CallsManager extends Call.ListenerBase private final UserManager mUserManager; private final CallStreamingNotification mCallStreamingNotification; private final FeatureFlags mFeatureFlags; private final com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags; private final IncomingCallFilterGraphProvider mIncomingCallFilterGraphProvider; Loading Loading @@ -610,6 +609,7 @@ public class CallsManager extends Call.ListenerBase CallStreamingNotification callStreamingNotification, BluetoothDeviceManager bluetoothDeviceManager, FeatureFlags featureFlags, com.android.internal.telephony.flags.FeatureFlags telephonyFlags, IncomingCallFilterGraphProvider incomingCallFilterGraphProvider) { mContext = context; Loading Loading @@ -717,6 +717,7 @@ public class CallsManager extends Call.ListenerBase mCallStreamingController = new CallStreamingController(mContext, mLock); mCallStreamingNotification = callStreamingNotification; mFeatureFlags = featureFlags; mTelephonyFeatureFlags = telephonyFlags; if (mFeatureFlags.useImprovedListenerOrder()) { mListeners.add(mInCallController); Loading Loading @@ -3428,8 +3429,14 @@ public class CallsManager extends Call.ListenerBase // then include only that SIM based PhoneAccount and any non-SIM PhoneAccounts, such as SIP. @VisibleForTesting public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency) { return constructPossiblePhoneAccounts(handle, user, isVideo, isEmergency, false); boolean isVideo, boolean isEmergency, boolean isConference) { if (mTelephonyFeatureFlags.simultaneousCallingIndications()) { return constructPossiblePhoneAccountsNew(handle, user, isVideo, isEmergency, isConference); } else { return constructPossiblePhoneAccountsOld(handle, user, isVideo, isEmergency, isConference); } } // Returns whether the device is capable of 2 simultaneous active voice calls on different subs. Loading @@ -3444,7 +3451,7 @@ public class CallsManager extends Call.ListenerBase } } public List<PhoneAccountHandle> constructPossiblePhoneAccounts(Uri handle, UserHandle user, private List<PhoneAccountHandle> constructPossiblePhoneAccountsOld(Uri handle, UserHandle user, boolean isVideo, boolean isEmergency, boolean isConference) { if (handle == null) { Loading Loading @@ -3485,6 +3492,82 @@ public class CallsManager extends Call.ListenerBase return allAccounts; } /** * Filters the list of all PhoneAccounts that match the outgoing call Handle's schema against * the outgoing call request criteria and the state of the already ongoing calls on the * device and their potential simultaneous calling restrictions. * @return The filtered List */ private List<PhoneAccountHandle> constructPossiblePhoneAccountsNew(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, capabilities, isEmergency ? 0 : PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY, isEmergency); Log.v(this, "constructPossiblePhoneAccountsNew: allAccounts=" + allAccounts); Set<PhoneAccountHandle> activeCallAccounts = mCalls.stream() .filter(c -> !c.isDisconnected() && !c.isNew()).map(Call::getTargetPhoneAccount) .filter(Objects::nonNull) .collect(Collectors.toSet()); Log.v(this, "constructPossiblePhoneAccountsNew: activeCallAccounts=" + activeCallAccounts); // No Active calls - all accounts are valid if (activeCallAccounts.isEmpty()) return allAccounts; // The emergency call should be attempted only over the same SIM PhoneAccounts where there // are already ongoing calls - filter out inactive SIM PhoneAccounts in this case. if (isEmergency) { Set<PhoneAccountHandle> simAccounts = new HashSet<>(mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser()); if (activeCallAccounts.stream().anyMatch(simAccounts::contains)) { allAccounts.removeIf(h -> { boolean isRemoved = simAccounts.contains(h) && !activeCallAccounts.contains(h); if (isRemoved) { Log.i(this, "constructPossiblePhoneAccountsNew: removing candidate PAH [" + h + "] because another SIM account is active with an emergency " + "call"); } return isRemoved; }); } } // Apply restrictions to which PhoneAccounts can be used to place a call by looking at // active calls and removing candidate PhoneAccounts if they are from the same source // as the active call and the candidate PhoneAccount is not part of the restriction. for (PhoneAccountHandle callHandle : activeCallAccounts) { allAccounts.removeIf(candidateHandle -> { PhoneAccount callAcct = mPhoneAccountRegistrar.getPhoneAccount(callHandle, user); if (callAcct == null) { Log.w(this, "constructPossiblePhoneAccountsNew: unexpected" + "null PA for PAH, removing : " + candidateHandle); return true; } boolean isRemoved = !Objects.equals(candidateHandle, callHandle) && Objects.equals(candidateHandle.getComponentName(), callHandle.getComponentName()) && callAcct.hasSimultaneousCallingRestriction() && !callAcct.getSimultaneousCallingRestriction().contains(candidateHandle); if (isRemoved) { Log.i(this, "constructPossiblePhoneAccountsNew: removing candidate" + " PAH [" + candidateHandle + "] because it is not part of the" + " restriction set by [" + callHandle + "], restriction=" + callAcct.getSimultaneousCallingRestriction()); } return isRemoved; }); } return allAccounts; } private TelephonyManager getTelephonyManager() { return mContext.getSystemService(TelephonyManager.class); } Loading
src/com/android/server/telecom/TelecomSystem.java +3 −1 Original line number Diff line number Diff line Loading @@ -230,7 +230,8 @@ public class TelecomSystem { Executor asyncTaskExecutor, Executor asyncCallAudioTaskExecutor, BlockedNumbersAdapter blockedNumbersAdapter, FeatureFlags featureFlags) { FeatureFlags featureFlags, com.android.internal.telephony.flags.FeatureFlags telephonyFlags) { mContext = context.getApplicationContext(); mFeatureFlags = featureFlags; LogUtils.initLogging(mContext); Loading Loading @@ -427,6 +428,7 @@ public class TelecomSystem { callStreamingNotification, bluetoothDeviceManager, featureFlags, telephonyFlags, IncomingCallFilterGraph::new); mIncomingCallNotifier = incomingCallNotifier; Loading
src/com/android/server/telecom/components/TelecomService.java +2 −1 Original line number Diff line number Diff line Loading @@ -234,7 +234,8 @@ public class TelecomService extends Service implements TelecomSystem.Component { showNotification); } }, new FeatureFlagsImpl())); new FeatureFlagsImpl(), new com.android.internal.telephony.flags.FeatureFlagsImpl())); } } Loading
tests/src/com/android/server/telecom/tests/CallsManagerTest.java +297 −9 File changed.Preview size limit exceeded, changes collapsed. Show changes
tests/src/com/android/server/telecom/tests/TelecomSystemTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -221,6 +221,8 @@ public class TelecomSystemTest extends TelecomTestCase{ CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker; @Mock FeatureFlags mFeatureFlags; @Mock com.android.internal.telephony.flags.FeatureFlags mTelephonyFlags; final ComponentName mInCallServiceComponentNameX = new ComponentName( Loading Loading @@ -581,7 +583,8 @@ public class TelecomSystemTest extends TelecomTestCase{ Runnable::run, Runnable::run, mBlockedNumbersAdapter, mFeatureFlags); mFeatureFlags, mTelephonyFlags); mComponentContextFixture.setTelecomManager(new TelecomManager( mComponentContextFixture.getTestDouble(), Loading