Merge "Resolve Telecom UserManager/UserInfo references" into main
diff --git a/Android.bp b/Android.bp
index 68a8e39..94654a6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11,6 +11,14 @@
out: ["com/android/server/telecom/TelecomStatsLog.java"],
}
+filegroup {
+ name: "telecom-shell-commands-src",
+ srcs: [
+ "src/com/android/server/telecom/TelecomShellCommand.java",
+ ],
+ path: "src",
+}
+
android_library {
name: "TelecomLib",
manifest: "AndroidManifestLib.xml",
@@ -33,7 +41,6 @@
platform_apis: true,
}
-
// Build the Telecom service.
android_app {
name: "Telecom",
diff --git a/flags/Android.bp b/flags/Android.bp
index b089796..25a7a8c 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -39,6 +39,7 @@
"telecom_bluetoothroutemanager_flags.aconfig",
"telecom_work_profile_flags.aconfig",
"telecom_connection_service_wrapper_flags.aconfig",
+ "telecom_remote_connection_service.aconfig",
"telecom_profile_user_flags.aconfig",
],
}
diff --git a/flags/telecom_api_flags.aconfig b/flags/telecom_api_flags.aconfig
index c44bea4..c0f4cba 100644
--- a/flags/telecom_api_flags.aconfig
+++ b/flags/telecom_api_flags.aconfig
@@ -48,4 +48,12 @@
namespace: "telecom"
description: "Enables enriched calling features (e.g. Business name will show for a call)"
bug: "311688497"
+ is_exported: true
+}
+
+flag{
+ name: "get_last_known_cell_identity"
+ namespace: "telecom"
+ description: "Formalizes the getLastKnownCellIdentity API that Telecom reliees on as a system api"
+ bug: "327454165"
}
diff --git a/flags/telecom_calls_manager_flags.aconfig b/flags/telecom_calls_manager_flags.aconfig
index de17eee..f329ca6 100644
--- a/flags/telecom_calls_manager_flags.aconfig
+++ b/flags/telecom_calls_manager_flags.aconfig
@@ -19,5 +19,5 @@
name: "enable_call_sequencing"
namespace: "telecom"
description: "Enables simultaneous call sequencing for SIM PhoneAccounts"
- bug: "297446980"
+ bug: "327038818"
}
diff --git a/flags/telecom_remote_connection_service.aconfig b/flags/telecom_remote_connection_service.aconfig
new file mode 100644
index 0000000..55c7536
--- /dev/null
+++ b/flags/telecom_remote_connection_service.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.telecom.flags"
+
+flag {
+ name: "set_remote_connection_call_id"
+ namespace: "telecom"
+ description: "Sets the telecom call id for remote connections/ conferences."
+ bug: "320242200"
+}
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index 091c8fc..d38577d 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -836,6 +836,16 @@
CallAudioState oldState = mCallAudioState;
mCallAudioState = callAudioState;
mCallsManager.onCallAudioStateChanged(oldState, mCallAudioState);
+ updateAudioStateForTrackedCalls(mCallAudioState);
+ }
+
+ private void updateAudioStateForTrackedCalls(CallAudioState newCallAudioState) {
+ Set<Call> calls = mCallsManager.getTrackedCalls();
+ for (Call call : calls) {
+ if (call != null && call.getConnectionService() != null) {
+ call.getConnectionService().onCallAudioStateChanged(call, newCallAudioState);
+ }
+ }
}
private AudioRoute getPreferredAudioRouteFromStrategy() {
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index e736681..6395f2f 100644
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -16,6 +16,7 @@
package com.android.server.telecom;
+import static android.provider.CallLog.AddCallParams.AddCallParametersBuilder.MAX_NUMBER_OF_CHARACTERS;
import static android.provider.CallLog.Calls.BLOCK_REASON_NOT_BLOCKED;
import static android.telephony.CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL;
@@ -31,6 +32,7 @@
import android.location.Location;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
@@ -60,8 +62,6 @@
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
import java.util.stream.Stream;
/**
@@ -419,11 +419,24 @@
paramBuilder.setCallType(callLogType);
paramBuilder.setIsRead(call.isSelfManaged());
paramBuilder.setMissedReason(call.getMissedReason());
- if (Flags.businessCallComposer() && call.getExtras() != null) {
- paramBuilder.setIsBusinessCall(call.getExtras().getBoolean(
- android.telecom.Call.EXTRA_IS_BUSINESS_CALL, false));
- paramBuilder.setBusinessName(call.getExtras().getString(
- android.telecom.Call.EXTRA_ASSERTED_DISPLAY_NAME, ""));
+ if (mFeatureFlags.businessCallComposer() && call.getExtras() != null) {
+ Bundle extras = call.getExtras();
+ boolean isBusinessCall =
+ extras.getBoolean(android.telecom.Call.EXTRA_IS_BUSINESS_CALL, false);
+ paramBuilder.setIsBusinessCall(isBusinessCall);
+ if (isBusinessCall) {
+ Log.i(TAG, "logging business call");
+ String assertedDisplayName =
+ extras.getString(android.telecom.Call.EXTRA_ASSERTED_DISPLAY_NAME, "");
+ if (assertedDisplayName.length() > MAX_NUMBER_OF_CHARACTERS) {
+ // avoid throwing an IllegalArgumentException and only log the first 256
+ // characters of the name.
+ paramBuilder.setAssertedDisplayName(
+ assertedDisplayName.substring(0, MAX_NUMBER_OF_CHARACTERS));
+ } else {
+ paramBuilder.setAssertedDisplayName(assertedDisplayName);
+ }
+ }
}
sendAddCallBroadcast(callLogType, call.getAgeMillis());
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index b43f8b1..5d98bb8 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -82,7 +82,6 @@
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;
@@ -165,7 +164,6 @@
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;
@@ -491,6 +489,7 @@
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;
@@ -610,6 +609,7 @@
CallStreamingNotification callStreamingNotification,
BluetoothDeviceManager bluetoothDeviceManager,
FeatureFlags featureFlags,
+ com.android.internal.telephony.flags.FeatureFlags telephonyFlags,
IncomingCallFilterGraphProvider incomingCallFilterGraphProvider) {
mContext = context;
@@ -717,6 +717,7 @@
mCallStreamingController = new CallStreamingController(mContext, mLock);
mCallStreamingNotification = callStreamingNotification;
mFeatureFlags = featureFlags;
+ mTelephonyFeatureFlags = telephonyFlags;
if (mFeatureFlags.useImprovedListenerOrder()) {
mListeners.add(mInCallController);
@@ -3454,8 +3455,14 @@
// 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.
@@ -3470,7 +3477,7 @@
}
}
- 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) {
@@ -3511,6 +3518,82 @@
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);
}
@@ -4717,19 +4800,7 @@
* @return {@code true} if the app has ongoing calls, or {@code false} otherwise.
*/
public boolean isInSelfManagedCall(String packageName, UserHandle userHandle) {
- return isInSelfManagedCallCrossUsers(packageName, userHandle, false);
- }
-
- /**
- * Determines if there are any ongoing self-managed calls for the given package/user (unless
- * hasCrossUsers has been enabled).
- * @param packageName The package name to check.
- * @param userHandle The {@link UserHandle} to check.
- * @param hasCrossUserAccess indicates if calls across all users should be returned.
- * @return {@code true} if the app has ongoing calls, or {@code false} otherwise.
- */
- public boolean isInSelfManagedCallCrossUsers(
- String packageName, UserHandle userHandle, boolean hasCrossUserAccess) {
+ boolean hasCrossUserAccess = userHandle.equals(UserHandle.ALL);
return mSelfManagedCallsBeingSetup.stream().anyMatch(c -> c.isSelfManaged()
&& c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
&& (!hasCrossUserAccess
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 58a99c0..6b384f4 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -477,6 +477,7 @@
String defaultSimCallManager = null;
CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
Context.CARRIER_CONFIG_SERVICE);
+ if (configManager == null) return null;
PersistableBundle configBundle = configManager.getConfigForSubId(subId);
if (configBundle != null) {
defaultSimCallManager = configBundle.getString(
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index f3d91f1..a24064c 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -53,8 +53,11 @@
import android.os.Build;
import android.os.Bundle;
import android.os.OutcomeReceiver;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.UserHandle;
import android.provider.BlockedNumberContract;
import android.provider.Settings;
@@ -72,12 +75,14 @@
import android.util.EventLog;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telecom.ICallControl;
import com.android.internal.telecom.ICallEventCallback;
import com.android.internal.telecom.ITelecomService;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.modules.utils.BasicShellCommandHandler;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.flags.FeatureFlags;
import com.android.server.telecom.settings.BlockedNumbersActivity;
@@ -2092,6 +2097,14 @@
}
}
+ @Override
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return new TelecomShellCommand(this, mContext).exec(this,
+ in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
+ }
+
/**
* Print all feature flag configurations that Telecom is using for debugging purposes.
*/
@@ -2563,34 +2576,26 @@
* @param packageName the package name of the app to check calls for.
* @param userHandle the user handle on which to check for calls.
* @param callingPackage The caller's package name.
- * @param detectForAllUsers indicates if calls should be detected across all users. If the
- * caller does not have the ability to interact across users, get
- * managed calls for the caller instead.
* @return {@code true} if there are ongoing calls, {@code false} otherwise.
*/
@Override
public boolean isInSelfManagedCall(String packageName, UserHandle userHandle,
- String callingPackage, boolean detectForAllUsers) {
+ String callingPackage) {
try {
mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
"READ_PRIVILEGED_PHONE_STATE required.");
// Ensure that the caller has the INTERACT_ACROSS_USERS permission if it's trying
// to access calls that don't belong to it.
- if (detectForAllUsers || (userHandle != null
- && !Binder.getCallingUserHandle().equals(userHandle))) {
+ if (!Binder.getCallingUserHandle().equals(userHandle)) {
enforceInAppCrossUserPermission();
- } else {
- // If INTERACT_ACROSS_USERS doesn't need to be enforced, ensure that the user
- // being checked is the caller.
- userHandle = Binder.getCallingUserHandle();
}
Log.startSession("TSI.iISMC", Log.getPackageAbbreviation(callingPackage));
synchronized (mLock) {
long token = Binder.clearCallingIdentity();
try {
- return mCallsManager.isInSelfManagedCallCrossUsers(
- packageName, userHandle, detectForAllUsers);
+ return mCallsManager.isInSelfManagedCall(
+ packageName, userHandle);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/src/com/android/server/telecom/TelecomShellCommand.java b/src/com/android/server/telecom/TelecomShellCommand.java
new file mode 100644
index 0000000..557002c
--- /dev/null
+++ b/src/com/android/server/telecom/TelecomShellCommand.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.sysprop.TelephonyProperties;
+import android.telecom.Log;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.android.internal.telecom.ITelecomService;
+import com.android.modules.utils.BasicShellCommandHandler;
+
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+/**
+ * Implements shell commands sent to telecom using the "adb shell cmd telecom..." command from shell
+ * or CTS.
+ */
+public class TelecomShellCommand extends BasicShellCommandHandler {
+ private static final String CALLING_PACKAGE = TelecomShellCommand.class.getPackageName();
+ private static final String COMMAND_SET_PHONE_ACCOUNT_ENABLED = "set-phone-account-enabled";
+ private static final String COMMAND_SET_PHONE_ACCOUNT_DISABLED = "set-phone-account-disabled";
+ private static final String COMMAND_REGISTER_PHONE_ACCOUNT = "register-phone-account";
+ private static final String COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT =
+ "set-user-selected-outgoing-phone-account";
+ private static final String COMMAND_REGISTER_SIM_PHONE_ACCOUNT = "register-sim-phone-account";
+ private static final String COMMAND_SET_TEST_CALL_REDIRECTION_APP =
+ "set-test-call-redirection-app";
+ private static final String COMMAND_SET_TEST_CALL_SCREENING_APP = "set-test-call-screening-app";
+ private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
+ "add-or-remove-call-companion-app";
+ private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
+ "set-phone-acct-suggestion-component";
+ private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
+ private static final String COMMAND_SET_CALL_DIAGNOSTIC_SERVICE = "set-call-diagnostic-service";
+ private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
+ private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+ private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+ private static final String COMMAND_CLEANUP_STUCK_CALLS = "cleanup-stuck-calls";
+ private static final String COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS =
+ "cleanup-orphan-phone-accounts";
+ private static final String COMMAND_RESET_CAR_MODE = "reset-car-mode";
+ private static final String COMMAND_IS_NON_IN_CALL_SERVICE_BOUND =
+ "is-non-ui-in-call-service-bound";
+
+ /**
+ * Change the system dialer package name if a package name was specified,
+ * Example: adb shell telecom set-system-dialer <PACKAGE>
+ *
+ * Restore it to the default if if argument is "default" or no argument is passed.
+ * Example: adb shell telecom set-system-dialer default
+ */
+ private static final String COMMAND_SET_SYSTEM_DIALER = "set-system-dialer";
+ private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
+ private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
+ private static final String COMMAND_SET_SIM_COUNT = "set-sim-count";
+ private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config";
+ private static final String COMMAND_GET_MAX_PHONES = "get-max-phones";
+ private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER =
+ "set-test-emergency-phone-account-package-filter";
+ /**
+ * Command used to emit a distinct "mark" in the logs.
+ */
+ private static final String COMMAND_LOG_MARK = "log-mark";
+
+ private final Context mContext;
+ private final ITelecomService mTelecomService;
+ private TelephonyManager mTelephonyManager;
+ private UserManager mUserManager;
+
+ public TelecomShellCommand(ITelecomService binder, Context context) {
+ mTelecomService = binder;
+ mContext = context;
+ }
+
+ @Override
+ public int onCommand(String command) {
+ if (command == null || command.isEmpty()) {
+ onHelp();
+ return 0;
+ }
+ try {
+ switch (command) {
+ case COMMAND_SET_PHONE_ACCOUNT_ENABLED:
+ runSetPhoneAccountEnabled(true);
+ break;
+ case COMMAND_SET_PHONE_ACCOUNT_DISABLED:
+ runSetPhoneAccountEnabled(false);
+ break;
+ case COMMAND_REGISTER_PHONE_ACCOUNT:
+ runRegisterPhoneAccount();
+ break;
+ case COMMAND_SET_TEST_CALL_REDIRECTION_APP:
+ runSetTestCallRedirectionApp();
+ break;
+ case COMMAND_SET_TEST_CALL_SCREENING_APP:
+ runSetTestCallScreeningApp();
+ break;
+ case COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP:
+ runAddOrRemoveCallCompanionApp();
+ break;
+ case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
+ runSetTestPhoneAcctSuggestionComponent();
+ break;
+ case COMMAND_SET_CALL_DIAGNOSTIC_SERVICE:
+ runSetCallDiagnosticService();
+ break;
+ case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
+ runRegisterSimPhoneAccount();
+ break;
+ case COMMAND_SET_USER_SELECTED_OUTGOING_PHONE_ACCOUNT:
+ runSetUserSelectedOutgoingPhoneAccount();
+ break;
+ case COMMAND_UNREGISTER_PHONE_ACCOUNT:
+ runUnregisterPhoneAccount();
+ break;
+ case COMMAND_STOP_BLOCK_SUPPRESSION:
+ runStopBlockSuppression();
+ break;
+ case COMMAND_CLEANUP_STUCK_CALLS:
+ runCleanupStuckCalls();
+ break;
+ case COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS:
+ runCleanupOrphanPhoneAccounts();
+ break;
+ case COMMAND_RESET_CAR_MODE:
+ runResetCarMode();
+ break;
+ case COMMAND_SET_DEFAULT_DIALER:
+ runSetDefaultDialer();
+ break;
+ case COMMAND_GET_DEFAULT_DIALER:
+ runGetDefaultDialer();
+ break;
+ case COMMAND_SET_SYSTEM_DIALER:
+ runSetSystemDialer();
+ break;
+ case COMMAND_GET_SYSTEM_DIALER:
+ runGetSystemDialer();
+ break;
+ case COMMAND_WAIT_ON_HANDLERS:
+ runWaitOnHandler();
+ break;
+ case COMMAND_SET_SIM_COUNT:
+ runSetSimCount();
+ break;
+ case COMMAND_GET_SIM_CONFIG:
+ runGetSimConfig();
+ break;
+ case COMMAND_GET_MAX_PHONES:
+ runGetMaxPhones();
+ break;
+ case COMMAND_IS_NON_IN_CALL_SERVICE_BOUND:
+ runIsNonUiInCallServiceBound();
+ break;
+ case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER:
+ runSetEmergencyPhoneAccountPackageFilter();
+ break;
+ case COMMAND_LOG_MARK:
+ runLogMark();
+ break;
+ default:
+ return handleDefaultCommands(command);
+ }
+ } catch (Exception e) {
+ getErrPrintWriter().println("Command["+ command + "]: Error: " + e);
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ getOutPrintWriter().println("usage: telecom [subcommand] [options]\n"
+ + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
+ + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
+ + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
+ + "usage: telecom register-sim-phone-account [-e] <COMPONENT> <ID> <USER_SN>"
+ + " <LABEL>: registers a PhoneAccount with CAPABILITY_SIM_SUBSCRIPTION"
+ + " and optionally CAPABILITY_PLACE_EMERGENCY_CALLS if \"-e\" is provided\n"
+ + "usage: telecom set-user-selected-outgoing-phone-account [-e] <COMPONENT> <ID> "
+ + "<USER_SN>\n"
+ + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
+ + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
+ + "usage: telecom set-phone-acct-suggestion-component <COMPONENT>\n"
+ + "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n"
+ + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
+ + " <LABEL> <ADDRESS>\n"
+ + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n"
+ + "usage: telecom set-call-diagnostic-service <PACKAGE>\n"
+ + "usage: telecom set-default-dialer <PACKAGE>\n"
+ + "usage: telecom get-default-dialer\n"
+ + "usage: telecom get-system-dialer\n"
+ + "usage: telecom wait-on-handlers\n"
+ + "usage: telecom set-sim-count <COUNT>\n"
+ + "usage: telecom get-sim-config\n"
+ + "usage: telecom get-max-phones\n"
+ + "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+ + " provider after a call to emergency services.\n"
+ + "usage: telecom cleanup-stuck-calls: Clear any disconnected calls that have"
+ + " gotten wedged in Telecom.\n"
+ + "usage: telecom cleanup-orphan-phone-accounts: remove any phone accounts that"
+ + " no longer have a valid UserHandle or accounts that no longer belongs to an"
+ + " installed package.\n"
+ + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+ + "\n"
+ + "telecom set-phone-account-enabled: Enables the given phone account, if it has"
+ + " already been registered with Telecom.\n"
+ + "\n"
+ + "telecom set-phone-account-disabled: Disables the given phone account, if it"
+ + " has already been registered with telecom.\n"
+ + "\n"
+ + "telecom set-call-diagnostic-service: overrides call diagnostic service.\n"
+ + "telecom set-default-dialer: Sets the override default dialer to the given"
+ + " component; this will override whatever the dialer role is set to.\n"
+ + "\n"
+ + "telecom get-default-dialer: Displays the current default dialer.\n"
+ + "\n"
+ + "telecom get-system-dialer: Displays the current system dialer.\n"
+ + "telecom set-system-dialer: Set the override system dialer to the given"
+ + " component. To remove the override, send \"default\"\n"
+ + "\n"
+ + "telecom wait-on-handlers: Wait until all handlers finish their work.\n"
+ + "\n"
+ + "telecom set-sim-count: Set num SIMs (2 for DSDS, 1 for single SIM."
+ + " This may restart the device.\n"
+ + "\n"
+ + "telecom get-sim-config: Get the mSIM config string. \"DSDS\" for DSDS mode,"
+ + " or \"\" for single SIM\n"
+ + "\n"
+ + "telecom get-max-phones: Get the max supported phones from the modem.\n"
+ + "telecom set-test-emergency-phone-account-package-filter <PACKAGE>: sets a"
+ + " package name that will be used for test emergency calls. To clear,"
+ + " send an empty package name. Real emergency calls will still be placed"
+ + " over Telephony.\n"
+ + "telecom log-mark <MESSAGE>: emits a message into the telecom logs. Useful for "
+ + "testers to indicate where in the logs various test steps take place.\n"
+ + "telecom is-non-ui-in-call-service-bound <PACKAGE>: queries a particular "
+ + "non-ui-InCallService in InCallController to determine if it is bound \n"
+ );
+ }
+ private void runSetPhoneAccountEnabled(boolean enabled) throws RemoteException {
+ final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+ final boolean success = mTelecomService.enablePhoneAccount(handle, enabled);
+ if (success) {
+ getOutPrintWriter().println("Success - " + handle
+ + (enabled ? " enabled." : " disabled."));
+ } else {
+ getOutPrintWriter().println("Error - is " + handle + " a valid PhoneAccount?");
+ }
+ }
+
+ private void runRegisterPhoneAccount() throws RemoteException {
+ final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+ final String label = getNextArgRequired();
+ PhoneAccount account = PhoneAccount.builder(handle, label)
+ .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER).build();
+ mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
+ getOutPrintWriter().println("Success - " + handle + " registered.");
+ }
+
+ private void runRegisterSimPhoneAccount() throws RemoteException {
+ boolean isEmergencyAccount = false;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-e": {
+ isEmergencyAccount = true;
+ break;
+ }
+ }
+ }
+ final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+ final String label = getNextArgRequired();
+ final String address = getNextArgRequired();
+ int capabilities = PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
+ | (isEmergencyAccount ? PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS : 0);
+ PhoneAccount account = PhoneAccount.builder(
+ handle, label)
+ .setAddress(Uri.parse(address))
+ .setSubscriptionAddress(Uri.parse(address))
+ .setCapabilities(capabilities)
+ .setShortDescription(label)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+ .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+ .build();
+ mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
+ getOutPrintWriter().println("Success - " + handle + " registered.");
+ }
+
+ private void runSetTestCallRedirectionApp() throws RemoteException {
+ final String packageName = getNextArg();
+ mTelecomService.setTestDefaultCallRedirectionApp(packageName);
+ }
+
+ private void runSetTestCallScreeningApp() throws RemoteException {
+ final String packageName = getNextArg();
+ mTelecomService.setTestDefaultCallScreeningApp(packageName);
+ }
+
+ private void runAddOrRemoveCallCompanionApp() throws RemoteException {
+ final String packageName = getNextArgRequired();
+ String isAdded = getNextArgRequired();
+ boolean isAddedBool = "1".equals(isAdded);
+ mTelecomService.addOrRemoveTestCallCompanionApp(packageName, isAddedBool);
+ }
+
+ private void runSetCallDiagnosticService() throws RemoteException {
+ String packageName = getNextArg();
+ if ("default".equals(packageName)) packageName = null;
+ mTelecomService.setTestCallDiagnosticService(packageName);
+ getOutPrintWriter().println("Success - " + packageName
+ + " set as call diagnostic service.");
+ }
+
+ private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
+ final String componentName = getNextArg();
+ mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
+ }
+
+ private void runSetUserSelectedOutgoingPhoneAccount() throws RemoteException {
+ Log.i(this, "runSetUserSelectedOutgoingPhoneAccount");
+ final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+ mTelecomService.setUserSelectedOutgoingPhoneAccount(handle);
+ getOutPrintWriter().println("Success - " + handle + " set as default outgoing account.");
+ }
+
+ private void runUnregisterPhoneAccount() throws RemoteException {
+ final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
+ mTelecomService.unregisterPhoneAccount(handle, CALLING_PACKAGE);
+ getOutPrintWriter().println("Success - " + handle + " unregistered.");
+ }
+
+ private void runStopBlockSuppression() throws RemoteException {
+ mTelecomService.stopBlockSuppression();
+ }
+
+ private void runCleanupStuckCalls() throws RemoteException {
+ mTelecomService.cleanupStuckCalls();
+ }
+
+ private void runCleanupOrphanPhoneAccounts() throws RemoteException {
+ getOutPrintWriter().println("Success - cleaned up "
+ + mTelecomService.cleanupOrphanPhoneAccounts()
+ + " phone accounts.");
+ }
+
+ private void runResetCarMode() throws RemoteException {
+ mTelecomService.resetCarMode();
+ }
+
+ private void runSetDefaultDialer() throws RemoteException {
+ String packageName = getNextArg();
+ if ("default".equals(packageName)) packageName = null;
+ mTelecomService.setTestDefaultDialer(packageName);
+ getOutPrintWriter().println("Success - " + packageName
+ + " set as override default dialer.");
+ }
+
+ private void runSetSystemDialer() throws RemoteException {
+ final String flatComponentName = getNextArg();
+ final ComponentName componentName = (flatComponentName.equals("default")
+ ? null : parseComponentName(flatComponentName));
+ mTelecomService.setSystemDialer(componentName);
+ getOutPrintWriter().println("Success - " + componentName + " set as override system dialer.");
+ }
+
+ private void runGetDefaultDialer() throws RemoteException {
+ getOutPrintWriter().println(mTelecomService.getDefaultDialerPackage(CALLING_PACKAGE));
+ }
+
+ private void runGetSystemDialer() throws RemoteException {
+ getOutPrintWriter().println(mTelecomService.getSystemDialerPackage(CALLING_PACKAGE));
+ }
+
+ private void runWaitOnHandler() throws RemoteException {
+
+ }
+
+ private void runSetSimCount() throws RemoteException {
+ if (!callerIsRoot()) {
+ getOutPrintWriter().println("set-sim-count requires adb root");
+ return;
+ }
+ int numSims = Integer.parseInt(getNextArgRequired());
+ getOutPrintWriter().println("Setting sim count to " + numSims + ". Device may reboot");
+ getTelephonyManager().switchMultiSimConfig(numSims);
+ }
+
+ /**
+ * prints out whether a particular non-ui InCallServices is bound in a call
+ */
+ public void runIsNonUiInCallServiceBound() throws RemoteException {
+ if (TextUtils.isEmpty(peekNextArg())) {
+ getOutPrintWriter().println("No Argument passed. Please pass a <PACKAGE_NAME> to "
+ + "lookup.");
+ } else {
+ getOutPrintWriter().println(
+ String.valueOf(mTelecomService.isNonUiInCallServiceBound(getNextArg())));
+ }
+ }
+
+ /**
+ * Prints the mSIM config to the console.
+ * "DSDS" for a phone in DSDS mode
+ * "" (empty string) for a phone in SS mode
+ */
+ private void runGetSimConfig() throws RemoteException {
+ getOutPrintWriter().println(TelephonyProperties.multi_sim_config().orElse(""));
+ }
+
+ private void runGetMaxPhones() throws RemoteException {
+ // how many logical modems can be potentially active simultaneously
+ getOutPrintWriter().println(getTelephonyManager().getSupportedModemCount());
+ }
+
+ private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
+ String packageName = getNextArg();
+ if (TextUtils.isEmpty(packageName)) {
+ mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(null);
+ getOutPrintWriter().println("Success - filter cleared");
+ } else {
+ mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(packageName);
+ getOutPrintWriter().println("Success = filter set to " + packageName);
+ }
+
+ }
+
+ private void runLogMark() throws RemoteException {
+ String message = Arrays.stream(peekRemainingArgs()).collect(Collectors.joining(" "));
+ mTelecomService.requestLogMark(message);
+ }
+
+ private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException {
+ if (TextUtils.isEmpty(peekNextArg())) {
+ return null;
+ }
+ final ComponentName component = parseComponentName(getNextArgRequired());
+ final String accountId = getNextArgRequired();
+ final String userSnInStr = getNextArgRequired();
+ UserHandle userHandle;
+ try {
+ final int userSn = Integer.parseInt(userSnInStr);
+ userHandle = UserHandle.of(getUserManager().getUserHandle(userSn));
+ } catch (NumberFormatException ex) {
+ Log.w(this, "getPhoneAccountHandleFromArgs - invalid user %s", userSnInStr);
+ throw new IllegalArgumentException ("Invalid user serial number " + userSnInStr);
+ }
+ return new PhoneAccountHandle(component, accountId, userHandle);
+ }
+
+ private boolean callerIsRoot() {
+ return Process.ROOT_UID == Process.myUid();
+ }
+
+ private ComponentName parseComponentName(String component) {
+ ComponentName cn = ComponentName.unflattenFromString(component);
+ if (cn == null) {
+ throw new IllegalArgumentException ("Invalid component " + component);
+ }
+ return cn;
+ }
+
+ private TelephonyManager getTelephonyManager() throws IllegalStateException {
+ if (mTelephonyManager == null) {
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ }
+ if (mTelephonyManager == null) {
+ Log.w(this, "getTelephonyManager: Can't access telephony service.");
+ throw new IllegalStateException("Could not access the Telephony Service. Is the system "
+ + "running?");
+ }
+ return mTelephonyManager;
+ }
+
+ private UserManager getUserManager() throws IllegalStateException {
+ if (mUserManager == null) {
+ mUserManager = mContext.getSystemService(UserManager.class);
+ }
+ if (mUserManager == null) {
+ Log.w(this, "getUserManager: Can't access UserManager service.");
+ throw new IllegalStateException("Could not access the UserManager Service. Is the "
+ + "system running?");
+ }
+ return mUserManager;
+ }
+}
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index d1a24ae..9f72604 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -230,7 +230,8 @@
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);
@@ -427,6 +428,7 @@
callStreamingNotification,
bluetoothDeviceManager,
featureFlags,
+ telephonyFlags,
IncomingCallFilterGraph::new);
mIncomingCallNotifier = incomingCallNotifier;
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 24e5d57..845f788 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -234,7 +234,8 @@
showNotification);
}
},
- new FeatureFlagsImpl()));
+ new FeatureFlagsImpl(),
+ new com.android.internal.telephony.flags.FeatureFlagsImpl()));
}
}
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index 645a42b..e048f21 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -34,6 +34,7 @@
<uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"/>
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
<application android:label="@string/app_name">
<uses-library android:name="android.test.runner"/>
diff --git a/testapps/res/layout/testdialer_main.xml b/testapps/res/layout/testdialer_main.xml
index 749d236..e4b5bef 100644
--- a/testapps/res/layout/testdialer_main.xml
+++ b/testapps/res/layout/testdialer_main.xml
@@ -54,6 +54,23 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancelMissedButton" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <EditText
+ android:id="@+id/set_composer_edit_text"
+ android:inputType="number"
+ android:layout_width="200dp"
+ android:layout_height="wrap_content" />
+ <Button
+ android:id="@+id/submit_composer_value"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submitCallComposerLabel" />
+ </LinearLayout>
+
<CheckBox
android:id="@+id/call_with_rtt_checkbox"
android:layout_width="wrap_content"
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index b1a1f80..39c2deb 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -100,6 +100,8 @@
<string name="postCallActivityLabel">Test Post Call Screen</string>
+ <string name="submitCallComposerLabel">Set Call Composer</string>
+
<string-array name="rtt_mode_array">
<item>Full</item>
<item>HCO</item>
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
index f17af2c..5a59c24 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -20,6 +20,7 @@
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.telephony.ims.ImsRcsManager;
import android.util.Log;
import android.view.View;
@@ -30,9 +31,11 @@
import android.widget.Toast;
public class TestDialerActivity extends Activity {
+ private static final String TAG = TestDialerActivity.class.getSimpleName();
private static final int REQUEST_CODE_SET_DEFAULT_DIALER = 1;
private EditText mNumberView;
+ private EditText mCallComposerView;
private CheckBox mRttCheckbox;
private CheckBox mComposerCheckbox;
private EditText mPriorityView;
@@ -57,6 +60,13 @@
}
});
+ findViewById(R.id.submit_composer_value).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setCallComposer();
+ }
+ });
+
findViewById(R.id.place_call_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -79,6 +89,7 @@
});
mNumberView = (EditText) findViewById(R.id.number);
+ mCallComposerView = (EditText) findViewById(R.id.set_composer_edit_text);
mRttCheckbox = (CheckBox) findViewById(R.id.call_with_rtt_checkbox);
mComposerCheckbox = (CheckBox) findViewById(R.id.add_composer_attachments_checkbox);
findViewById(R.id.enable_car_mode).setOnClickListener(new OnClickListener() {
@@ -141,6 +152,23 @@
}
}
+ // Testers need a way of setting the call composer since this is currently not supported by
+ // Dialer. In the future, this will be a Dialer setting that users can enable/disable.
+ private void setCallComposer() {
+ final TelephonyManager telephonyManager =
+ (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+ String number = mCallComposerView.getText().toString();
+ try {
+ Log.i(TAG, "setCallComposer: value=[" + number + "]");
+ telephonyManager.setCallComposerStatus(Integer.parseInt(number));
+ Log.i(TAG, "setCallComposer: successfully set composer");
+ } catch (Exception e) {
+ Log.i(TAG, "setCallComposer: hit exception while setting the call composer."
+ + " See stack trace below for more info!");
+ e.printStackTrace();
+ }
+ }
+
private void placeCall() {
final TelecomManager telecomManager =
(TelecomManager) getSystemService(Context.TELECOM_SERVICE);
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 2bf6f48..a5a811e 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -78,13 +78,13 @@
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneCapability;
import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Pair;
import android.widget.Toast;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
-import com.android.internal.telecom.IConnectionService;
import com.android.server.telecom.AnomalyReporterAdapter;
import com.android.server.telecom.AsyncRingtonePlayer;
import com.android.server.telecom.Call;
@@ -103,7 +103,6 @@
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory;
import com.android.server.telecom.ConnectionServiceWrapper;
-import com.android.server.telecom.CreateConnectionResponse;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.EmergencyCallDiagnosticLogger;
import com.android.server.telecom.EmergencyCallHelper;
@@ -112,7 +111,6 @@
import com.android.server.telecom.HeadsetMediaButtonFactory;
import com.android.server.telecom.InCallController;
import com.android.server.telecom.InCallControllerFactory;
-import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.InCallTonePlayer;
import com.android.server.telecom.InCallWakeLockController;
import com.android.server.telecom.InCallWakeLockControllerFactory;
@@ -140,6 +138,8 @@
import com.android.server.telecom.ui.ToastFactory;
import com.android.server.telecom.voip.TransactionManager;
+import com.google.common.base.Objects;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -148,7 +148,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
-import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -158,10 +157,12 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@RunWith(JUnit4.class)
public class CallsManagerTest extends TelecomTestCase {
@@ -177,6 +178,10 @@
new UserHandle(SECONDARY_USER_ID));
private static final PhoneAccountHandle SIM_2_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.foo/.Blah"), "Sim2");
+ private static final PhoneAccountHandle SIM_3_HANDLE = new PhoneAccountHandle(
+ ComponentName.unflattenFromString("com.foo/.Blah"), "Sim3");
+ private static final PhoneAccountHandle CALL_PROVIDER_HANDLE = new PhoneAccountHandle(
+ ComponentName.unflattenFromString("com.sip.foo/.Blah"), "sip1");
private static final PhoneAccountHandle CONNECTION_MGR_1_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.bar/.Conn"), "Cm1");
private static final PhoneAccountHandle CONNECTION_MGR_2_HANDLE = new PhoneAccountHandle(
@@ -210,6 +215,18 @@
| PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING)
.setIsEnabled(true)
.build();
+ private static final PhoneAccount SIM_3_ACCOUNT = new PhoneAccount.Builder(SIM_3_HANDLE, "Sim3")
+ .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
+ | PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING)
+ .setIsEnabled(true)
+ .build();
+ private static final PhoneAccount CALL_PROVIDER_ACCOUNT =
+ new PhoneAccount.Builder(CALL_PROVIDER_HANDLE, "sip1")
+ .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER
+ | PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING)
+ .setIsEnabled(true)
+ .build();
private static final PhoneAccount SELF_MANAGED_ACCOUNT = new PhoneAccount.Builder(
SELF_MANAGED_HANDLE, "Self")
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
@@ -293,6 +310,7 @@
@Mock private CallStreamingNotification mCallStreamingNotification;
@Mock private BluetoothDeviceManager mBluetoothDeviceManager;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private com.android.internal.telephony.flags.FeatureFlags mTelephonyFlags;
@Mock private IncomingCallFilterGraph mIncomingCallFilterGraph;
@Mock private Context mMockCreateContextAsUser;
@Mock private UserManager mMockCurrentUserManager;
@@ -372,6 +390,7 @@
mCallStreamingNotification,
mBluetoothDeviceManager,
mFeatureFlags,
+ mTelephonyFlags,
(call, listener, context, timeoutsAdapter, lock) -> mIncomingCallFilterGraph);
when(mPhoneAccountRegistrar.getPhoneAccount(
@@ -381,6 +400,10 @@
when(mPhoneAccountRegistrar.getPhoneAccount(
eq(SIM_2_HANDLE), any())).thenReturn(SIM_2_ACCOUNT);
when(mPhoneAccountRegistrar.getPhoneAccount(
+ eq(SIM_3_HANDLE), any())).thenReturn(SIM_3_ACCOUNT);
+ when(mPhoneAccountRegistrar.getPhoneAccount(
+ eq(CALL_PROVIDER_HANDLE), any())).thenReturn(CALL_PROVIDER_ACCOUNT);
+ when(mPhoneAccountRegistrar.getPhoneAccount(
eq(WORK_HANDLE), any())).thenReturn(WORK_ACCOUNT);
when(mToastFactory.makeText(any(), anyInt(), anyInt())).thenReturn(mToast);
when(mToastFactory.makeText(any(), any(), anyInt())).thenReturn(mToast);
@@ -401,8 +424,21 @@
@MediumTest
@Test
public void testConstructPossiblePhoneAccounts() throws Exception {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(false);
+ setupMsimAccounts();
// Should be empty since the URI is null.
- assertEquals(0, mCallsManager.constructPossiblePhoneAccounts(null, null, false, false).size());
+ assertEquals(0, mCallsManager.constructPossiblePhoneAccounts(null, null,
+ false, false, false).size());
+ }
+
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccounts_simulCalling() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupMsimAccounts();
+ // Should be empty since the URI is null.
+ assertEquals(0, mCallsManager.constructPossiblePhoneAccounts(null, null,
+ false, false, false).size());
}
private Call constructOngoingCall(String callId, PhoneAccountHandle phoneAccountHandle) {
@@ -426,6 +462,7 @@
ongoingCall.setState(CallState.ACTIVE, "just cuz");
return ongoingCall;
}
+
/**
* Verify behavior for multisim devices where we want to ensure that the active sim is used for
* placing a new call.
@@ -434,32 +471,127 @@
@MediumTest
@Test
public void testConstructPossiblePhoneAccountsMultiSimActive() throws Exception {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(false);
setupMsimAccounts();
Call ongoingCall = constructOngoingCall("1", SIM_2_HANDLE);
mCallsManager.addCall(ongoingCall);
List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
- TEST_ADDRESS, null, false, false);
+ TEST_ADDRESS, null, false, false, false);
assertEquals(1, phoneAccountHandles.size());
assertEquals(SIM_2_HANDLE, phoneAccountHandles.get(0));
}
/**
+ * Verify behavior for multisim devices where we want to ensure that the active sim is used for
+ * placing a new call when a restriction is set as well as other call providers from different
+ * apps.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimActive_simulCallingRestriction() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE,
+ CALL_PROVIDER_HANDLE), Collections.emptySet());
+
+ Call ongoingCall = constructOngoingCall("1", SIM_2_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false, false);
+ assertEquals(Arrays.asList(SIM_2_HANDLE, CALL_PROVIDER_HANDLE), phoneAccountHandles);
+ }
+
+ /**
+ * When we have 3 SIM PhoneAccounts on a device, but only 2 allow simultaneous calling, place a
+ * call on a SIM that allows simultaneous calling and verify that the subset of PhoneAccounts
+ * are available when in a call as well as the call provider.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimActive_simulCallingRestrictionSubset() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE, SIM_3_HANDLE,
+ CALL_PROVIDER_HANDLE), new ArraySet<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
+
+ Call ongoingCall = constructOngoingCall("1", SIM_2_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false, false);
+ assertEquals(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE, CALL_PROVIDER_HANDLE),
+ phoneAccountHandles);
+ }
+
+ /**
+ * When we have 3 SIM PhoneAccounts on a device, but only 2 allow simultaneous calling, place a
+ * call on the SIM that does not allow simultaneous calling and verify that only that SIM and
+ * the separate call provider are allowed to place a second call.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimActive_simulCallingRestrictionSubset2() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE, SIM_3_HANDLE,
+ CALL_PROVIDER_HANDLE), new ArraySet<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
+
+ Call ongoingCall = constructOngoingCall("1", SIM_3_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false, false);
+ assertEquals(Arrays.asList(SIM_3_HANDLE, CALL_PROVIDER_HANDLE),
+ phoneAccountHandles);
+ }
+
+ /**
* Verify behavior for multisim devices when there are no calls active; expect both accounts.
* @throws Exception
*/
@MediumTest
@Test
public void testConstructPossiblePhoneAccountsMultiSimIdle() throws Exception {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(false);
setupMsimAccounts();
List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
- TEST_ADDRESS, null, false, false);
+ TEST_ADDRESS, null, false, false, false);
assertEquals(2, phoneAccountHandles.size());
}
/**
+ * Verify behavior for multisim devices when there are no calls active and there are no calling
+ * restrictions set; expect both accounts.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimIdle_noSimulCallingRestriction() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsNoSimultaneousCallingRestriction();
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false, false);
+ assertEquals(3, phoneAccountHandles.size());
+ }
+
+ /**
+ * Verify behavior for multisim devices when there are no calls active and there are no calling
+ * restrictions set; expect both accounts.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimIdle_withSimulCallingRestriction() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE,
+ CALL_PROVIDER_HANDLE), Collections.emptySet());
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false, false);
+ assertEquals(3, phoneAccountHandles.size());
+ }
+
+ /**
* For DSDA-enabled multisim devices with an ongoing call, verify that both SIMs'
* PhoneAccountHandles are constructed while placing a new call.
* @throws Exception
@@ -468,6 +600,7 @@
@Test
public void testConstructPossiblePhoneAccountsMultiSimActive_dsdaCallingPossible() throws
Exception {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(false);
setupMsimAccounts();
setMaxActiveVoiceSubscriptions(2);
@@ -475,11 +608,29 @@
mCallsManager.addCall(ongoingCall);
List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
- TEST_ADDRESS, null, false, false);
+ TEST_ADDRESS, null, false, false, false);
assertEquals(2, phoneAccountHandles.size());
}
/**
+ * For multisim devices with an ongoing call, verify that all call capable PhoneAccounts are
+ * available when creating a second call.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimActive_simulCalling_dsdaPossible() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsNoSimultaneousCallingRestriction();
+
+ Call ongoingCall = constructOngoingCall("1", SIM_2_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false, false);
+ assertEquals(3, phoneAccountHandles.size());
+ }
+
+ /**
* For DSDA-enabled multisim devices with an ongoing call, verify that only the active SIMs'
* PhoneAccountHandle is constructed while placing an emergency call.
* @throws Exception
@@ -488,6 +639,7 @@
@Test
public void testConstructPossiblePhoneAccountsMultiSimActive_dsdaCallingPossible_emergencyCall()
throws Exception {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(false);
setupMsimAccounts();
setMaxActiveVoiceSubscriptions(2);
@@ -495,11 +647,96 @@
mCallsManager.addCall(ongoingCall);
List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
- TEST_ADDRESS, null, false, true /* isEmergency */);
+ TEST_ADDRESS, null, false, true /* isEmergency */, false);
assertEquals(1, phoneAccountHandles.size());
assertEquals(SIM_2_HANDLE, phoneAccountHandles.get(0));
}
+ /**
+ * For multisim devices with an ongoing call, verify that only the active SIM's
+ * PhoneAccountHandle is available if we have a calling restriction where only one SIM is
+ * active at a time.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimActive_simulCalling_emergencyCall() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE,
+ CALL_PROVIDER_HANDLE), Collections.emptySet());
+
+ Call ongoingCall = constructOngoingCall("1", SIM_2_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, true /* isEmergency */, false);
+ assertEquals(2, phoneAccountHandles.size());
+ assertTrue("Candidate PAHs must contain the SIM account hosting the emergency call",
+ phoneAccountHandles.contains(SIM_2_HANDLE));
+ assertFalse("Candidate PAHs must not contain other SIM accounts",
+ phoneAccountHandles.contains(SIM_1_HANDLE));
+ }
+
+ /**
+ * For devices with an ongoing call on a call provider, verify that when an emergency
+ * call is placed, all SIM accounts are still available for SIM selection.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccounts_callProvider_emergencyCall() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE,
+ CALL_PROVIDER_HANDLE), Collections.emptySet());
+
+ Call ongoingCall = constructOngoingCall("1", CALL_PROVIDER_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, true /* isEmergency */, false);
+ assertEquals(3, phoneAccountHandles.size());
+ }
+
+ /**
+ * For multisim devices with an ongoing call, for backwards compatibility, only allow the
+ * SIM with the active call to be chosen to place an emergency call, even if there is no
+ * calling restriction.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccountsMultiSimActive_simulCallingRest_emergencyCall() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsNoSimultaneousCallingRestriction();
+
+ Call ongoingCall = constructOngoingCall("1", SIM_2_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, true /* isEmergency */, false);
+ assertEquals(2, phoneAccountHandles.size());
+ assertTrue("Candidate PAHs must contain the SIM account hosting the emergency call",
+ phoneAccountHandles.contains(SIM_2_HANDLE));
+ assertFalse("Candidate PAHs must not contain other SIM accounts",
+ phoneAccountHandles.contains(SIM_1_HANDLE));
+ }
+
+ /**
+ * For multisim devices with an ongoing call on a call provider, it is still possible to place
+ * a SIM call on any SIM account.
+ */
+ @MediumTest
+ @Test
+ public void testConstructPossiblePhoneAccounts_crossAccount_simulCalling() {
+ when(mTelephonyFlags.simultaneousCallingIndications()).thenReturn(true);
+ setupAccountsWithCallingRestriction(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE,
+ CALL_PROVIDER_HANDLE), Collections.emptySet());
+
+ Call ongoingCall = constructOngoingCall("1", CALL_PROVIDER_HANDLE);
+ mCallsManager.addCall(ongoingCall);
+
+ List<PhoneAccountHandle> phoneAccountHandles = mCallsManager.constructPossiblePhoneAccounts(
+ TEST_ADDRESS, null, false, false /* isEmergency */, false);
+ assertEquals(3, phoneAccountHandles.size());
+ }
+
private void setupCallerInfoLookupHelper() {
doAnswer(invocation -> {
Uri handle = invocation.getArgument(0);
@@ -3433,6 +3670,9 @@
callback.onRequestFocusDone(call);
}
+ /**
+ * Set up 2 SIM accounts in DSDS mode, where only one SIM can be active at a time for calls.
+ */
private void setupMsimAccounts() {
TelephonyManager mockTelephonyManager = mComponentContextFixture.getTelephonyManager();
when(mockTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims()).thenReturn(1);
@@ -3443,6 +3683,54 @@
new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
}
+ /**
+ * Set up 2 SIM accounts in DSDS mode and one call provider, where there is no restriction on
+ * simultaneous calls across accounts.
+ */
+ private void setupAccountsNoSimultaneousCallingRestriction() {
+ when(mPhoneAccountRegistrar.getCallCapablePhoneAccounts(any(), anyBoolean(),
+ any(), anyInt(), anyInt(), anyBoolean())).thenReturn(
+ new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE, CALL_PROVIDER_HANDLE)));
+ when(mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser()).thenReturn(
+ new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
+ }
+
+ /**
+ * Set up the call capable PhoneAccounts passed in here to have simultaneous calling
+ * restrictions. If the callCapableHandle is a SIM account and it is in the restriction set, we
+ * will set that callCapableHandle's restriction to the Set. If not, we will set the restriction
+ * to allow no other simultaneous calls.
+ */
+ private void setupAccountsWithCallingRestriction(List<PhoneAccountHandle> callCapableHandles,
+ Set<PhoneAccountHandle> restrictions) {
+ when(mPhoneAccountRegistrar.getCallCapablePhoneAccounts(any(), anyBoolean(),
+ any(), anyInt(), anyInt(), anyBoolean())).thenReturn(
+ new ArrayList<>(callCapableHandles));
+ List<PhoneAccountHandle> allSims = Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE,
+ SIM_3_HANDLE);
+ List<PhoneAccountHandle> simsToTest = callCapableHandles.stream()
+ .filter(allSims::contains).toList();
+ when(mPhoneAccountRegistrar.getSimPhoneAccountsOfCurrentUser()).thenReturn(simsToTest);
+ // Remap the PhoneAccounts to inherit the restriction set
+ for (PhoneAccountHandle callCapableHandle : callCapableHandles) {
+ PhoneAccount pa = mPhoneAccountRegistrar.getPhoneAccount(
+ callCapableHandle, callCapableHandle.getUserHandle());
+ assertNotNull("test setup error: could not find PA for PAH:" + callCapableHandle,
+ pa);
+ // For simplicity, for testing only apply restrictions to SIM accounts
+ if (!allSims.contains(callCapableHandle)) continue;
+ if (restrictions.contains(callCapableHandle)) {
+ pa = new PhoneAccount.Builder(pa)
+ .setSimultaneousCallingRestriction(restrictions).build();
+ } else {
+ pa = new PhoneAccount.Builder(pa)
+ .setSimultaneousCallingRestriction(Collections.emptySet()).build();
+ }
+ when(mPhoneAccountRegistrar.getPhoneAccount(eq(callCapableHandle),
+ any())).thenReturn(pa);
+ }
+ }
+
private void setMaxActiveVoiceSubscriptions(int num) {
TelephonyManager mockTelephonyManager = mComponentContextFixture.getTelephonyManager();
when(mockTelephonyManager.getPhoneCapability()).thenReturn(mPhoneCapability);
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 659f192..a8663d6 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -221,6 +221,8 @@
CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker;
@Mock
FeatureFlags mFeatureFlags;
+ @Mock
+ com.android.internal.telephony.flags.FeatureFlags mTelephonyFlags;
final ComponentName mInCallServiceComponentNameX =
new ComponentName(
@@ -581,7 +583,8 @@
Runnable::run,
Runnable::run,
mBlockedNumbersAdapter,
- mFeatureFlags);
+ mFeatureFlags,
+ mTelephonyFlags);
mComponentContextFixture.setTelecomManager(new TelecomManager(
mComponentContextFixture.getTestDouble(),