Merge "Rename EmergencyCallDiagnosticParam API" into main
diff --git a/OWNERS b/OWNERS
index 7e68aea..6f90d48 100644
--- a/OWNERS
+++ b/OWNERS
@@ -5,3 +5,4 @@
 rgreenwalt@google.com
 pmadapurmath@google.com
 grantmenke@google.com
+huiwang@google.com
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 9ead5f4..c9e5593 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -19,7 +19,7 @@
     <string name="telecommAppLabel" product="default" msgid="1825598513414129827">"ဖုန်းခေါ်ဆိုမှုများ"</string>
     <string name="userCallActivityLabel" product="default" msgid="3605391260292846248">"ဖုန်း"</string>
     <string name="unknown" msgid="6993977514360123431">"မသိပါ"</string>
-    <string name="notification_missedCallTitle" msgid="5060387047205532974">"လွဲသွားသော ဖုန်းခေါ်မှု"</string>
+    <string name="notification_missedCallTitle" msgid="5060387047205532974">"လွတ်သွားသော ခေါ်ဆိုမှု"</string>
     <string name="notification_missedWorkCallTitle" msgid="6965463282259034953">"လွတ်သွားသည့် အလုပ်ဆိုင်ရာ ခ​ေါ်ဆိုမှု"</string>
     <string name="notification_missedCallsTitle" msgid="3910479625507893809">"လွဲသွားသော ဖုန်းခေါ်မှုများ"</string>
     <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> လွဲသွားသော ဖုန်းခေါ်မှုများ"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 787711b..6f3ebe3 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -24,7 +24,7 @@
     <string name="notification_missedCallsTitle" msgid="3910479625507893809">"ମିସ୍ଡ କଲ୍"</string>
     <string name="notification_missedCallsMsg" msgid="5055782736170916682">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>ଟି ମିସ୍ଡ କଲ୍"</string>
     <string name="notification_missedCallTicker" msgid="6731461957487087769">"<xliff:g id="MISSED_CALL_FROM">%s</xliff:g>ଙ୍କ ଠାରୁ ମିସ୍-କଲ୍ ମିଳିଛି"</string>
-    <string name="notification_missedCall_call_back" msgid="7900333283939789732">"କଲବ୍ୟାକ୍ କରନ୍ତୁ"</string>
+    <string name="notification_missedCall_call_back" msgid="7900333283939789732">"କଲବେକ କରନ୍ତୁ"</string>
     <string name="notification_missedCall_message" msgid="4054698824390076431">"ମେସେଜ୍‍ ଦିଅନ୍ତୁ"</string>
     <string name="notification_disconnectedCall_title" msgid="1790131923692416928">"କଲ୍ ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି"</string>
     <string name="notification_disconnectedCall_body" msgid="600491714584417536">"ଏକ ଜରୁରୀକାଳୀନ କଲ୍ କରାଯାଇଥିବାରୁ <xliff:g id="CALLER">%s</xliff:g>ଙ୍କୁ କରାଯାଇଥିବା କଲ୍ ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି।"</string>
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index 062c872..c02d20d 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -172,9 +172,14 @@
             // Show the toast to warn user that it is a personal call though initiated in work
             // profile.
             if (fixedInitiatingUser) {
-                Toast.makeText(context, Looper.getMainLooper(),
-                        context.getString(R.string.toast_personal_call_msg),
-                        Toast.LENGTH_LONG).show();
+                if (featureFlags.telecomResolveHiddenDependencies()) {
+                    Toast.makeText(context, context.getString(R.string.toast_personal_call_msg),
+                            Toast.LENGTH_LONG).show();
+                } else {
+                    Toast.makeText(context, Looper.getMainLooper(),
+                            context.getString(R.string.toast_personal_call_msg),
+                            Toast.LENGTH_LONG).show();
+                }
             }
         } else {
             Log.i(CallIntentProcessor.class,
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index cc5a15d..a3b423a 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -4669,18 +4669,35 @@
     }
 
     /**
-     * Determines if there are any ongoing self managed calls for the given package/user.
+     * Determines if there are any ongoing self-managed calls for the given package/user.
      * @param packageName The package name to check.
-     * @param userHandle The userhandle to check.
+     * @param userHandle The {@link UserHandle} to check.
      * @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) {
         return mSelfManagedCallsBeingSetup.stream().anyMatch(c -> c.isSelfManaged()
                 && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
-                && c.getTargetPhoneAccount().getUserHandle().equals(userHandle)) ||
-                mCalls.stream().anyMatch(c -> c.isSelfManaged()
+                && (!hasCrossUserAccess
+                        ? c.getTargetPhoneAccount().getUserHandle().equals(userHandle)
+                        : true))
+                || mCalls.stream().anyMatch(c -> c.isSelfManaged()
                 && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
-                && c.getTargetPhoneAccount().getUserHandle().equals(userHandle));
+                && (!hasCrossUserAccess
+                        ? c.getTargetPhoneAccount().getUserHandle().equals(userHandle)
+                        : true));
     }
 
     @VisibleForTesting
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index 9ce10bd..514ba48 100755
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -20,6 +20,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.ResultReceiver;
+import android.os.UserHandle;
 import android.telecom.CallEndpoint;
 import android.telecom.Log;
 import android.telecom.PhoneAccountHandle;
@@ -420,7 +421,8 @@
             Log.startSession(LogUtils.Sessions.ICA_ENTER_AUDIO_PROCESSING,
                     mOwnerPackageAbbreviation);
             // TODO: enforce the extra permission.
-            Binder.withCleanCallingIdentity(() -> {
+            long token = Binder.clearCallingIdentity();
+            try {
                 synchronized (mLock) {
                     Call call = mCallIdMapper.getCall(callId);
                     if (call != null) {
@@ -429,7 +431,9 @@
                         Log.w(this, "enterBackgroundAudioProcessing, unknown call id: %s", callId);
                     }
                 }
-            });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         } finally {
             Log.endSession();
         }
@@ -440,7 +444,8 @@
         try {
             Log.startSession(LogUtils.Sessions.ICA_EXIT_AUDIO_PROCESSING,
                     mOwnerPackageAbbreviation);
-            Binder.withCleanCallingIdentity(() -> {
+            long token = Binder.clearCallingIdentity();
+            try {
                 synchronized (mLock) {
                     Call call = mCallIdMapper.getCall(callId);
                     if (call != null) {
@@ -450,7 +455,9 @@
                                 "exitBackgroundAudioProcessing, unknown call id: %s", callId);
                     }
                 }
-            });
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         } finally {
             Log.endSession();
         }
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index de73269..fc90edd 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -58,6 +58,7 @@
 
 // TODO: Needed for move to system service: import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.ModifiedUtf8;
@@ -81,10 +82,12 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.stream.Collectors;
@@ -181,19 +184,19 @@
     private interface PhoneAccountRegistrarWriteLock {}
     private final PhoneAccountRegistrarWriteLock mWriteLock =
             new PhoneAccountRegistrarWriteLock() {};
-    private final com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags;
+    private final FeatureFlags mTelephonyFeatureFlags;
 
     @VisibleForTesting
     public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock,
             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy,
-            com.android.internal.telephony.flags.FeatureFlags telephonyFeatureFlags) {
+            FeatureFlags telephonyFeatureFlags) {
         this(context, lock, FILE_NAME, defaultDialerCache, appLabelProxy, telephonyFeatureFlags);
     }
 
     @VisibleForTesting
     public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName,
             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy,
-            com.android.internal.telephony.flags.FeatureFlags telephonyFeatureFlags) {
+            FeatureFlags telephonyFeatureFlags) {
 
         mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
 
@@ -951,6 +954,9 @@
         enforceCharacterLimit(account);
         enforceIconSizeLimit(account);
         enforceMaxPhoneAccountLimit(account);
+        if (mTelephonyFeatureFlags.simultaneousCallingIndications()) {
+            enforceSimultaneousCallingRestrictionLimit(account);
+        }
         addOrReplacePhoneAccount(account);
     }
 
@@ -1079,6 +1085,43 @@
     }
 
     /**
+     * Enforce size limits on the simultaneous calling restriction of a PhoneAccount.
+     * If a PhoneAccount has a simultaneous calling restriction on it, enforce the following: the
+     * number of PhoneAccountHandles in the Set can not exceed the per app restriction on
+     * PhoneAccounts registered and each PhoneAccountHandle's fields must not exceed the per field
+     * character limit.
+     * @param account The PhoneAccount to enforce simultaneous calling restrictions on.
+     * @throws IllegalArgumentException if the PhoneAccount exceeds size limits.
+     */
+    public void enforceSimultaneousCallingRestrictionLimit(@NonNull PhoneAccount account) {
+        if (!account.hasSimultaneousCallingRestriction()) return;
+        Set<PhoneAccountHandle> restrictions = account.getSimultaneousCallingRestriction();
+        if (restrictions.size() > MAX_PHONE_ACCOUNT_REGISTRATIONS) {
+            throw new IllegalArgumentException("Can not register a PhoneAccount with a number"
+                    + "of simultaneous calling restrictions that is greater than "
+                    + MAX_PHONE_ACCOUNT_REGISTRATIONS);
+        }
+        for (PhoneAccountHandle handle : restrictions) {
+            ComponentName component = handle.getComponentName();
+            if (component.getPackageName().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
+                throw new IllegalArgumentException("A PhoneAccountHandle added as part of "
+                        + "a simultaneous calling restriction has a package name that has exceeded "
+                        + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT);
+            }
+            if (component.getClassName().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
+                throw new IllegalArgumentException("A PhoneAccountHandle added as part of "
+                        + "a simultaneous calling restriction has a class name that has exceeded "
+                        + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT);
+            }
+            if (handle.getId().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
+                throw new IllegalArgumentException("A PhoneAccountHandle added as part of "
+                        + "a simultaneous calling restriction has an ID that has exceeded "
+                        + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT);
+            }
+        }
+    }
+
+    /**
      * Enforce a character limit on all PA and PAH string or char-sequence fields.
      *
      * @param account to enforce check on
@@ -1878,7 +1921,7 @@
             sortPhoneAccounts();
             ByteArrayOutputStream os = new ByteArrayOutputStream();
             XmlSerializer serializer = Xml.resolveSerializer(os);
-            writeToXml(mState, serializer, mContext);
+            writeToXml(mState, serializer, mContext, mTelephonyFeatureFlags);
             serializer.flush();
             new AsyncXmlWriter().execute(os);
         } catch (IOException e) {
@@ -1899,7 +1942,7 @@
         try {
             XmlPullParser parser = Xml.resolvePullParser(is);
             parser.nextTag();
-            mState = readFromXml(parser, mContext);
+            mState = readFromXml(parser, mContext, mTelephonyFeatureFlags);
             migratePhoneAccountHandle(mState);
             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
 
@@ -1934,14 +1977,14 @@
         }
     }
 
-    private static void writeToXml(State state, XmlSerializer serializer, Context context)
-            throws IOException {
-        sStateXml.writeToXml(state, serializer, context);
+    private static void writeToXml(State state, XmlSerializer serializer, Context context,
+            FeatureFlags telephonyFeatureFlags) throws IOException {
+        sStateXml.writeToXml(state, serializer, context, telephonyFeatureFlags);
     }
 
-    private static State readFromXml(XmlPullParser parser, Context context)
-            throws IOException, XmlPullParserException {
-        State s = sStateXml.readFromXml(parser, 0, context);
+    private static State readFromXml(XmlPullParser parser, Context context,
+            FeatureFlags telephonyFeatureFlags) throws IOException, XmlPullParserException {
+        State s = sStateXml.readFromXml(parser, 0, context, telephonyFeatureFlags);
         return s != null ? s : new State();
     }
 
@@ -2007,8 +2050,8 @@
         /**
          * Write the supplied object to XML
          */
-        public abstract void writeToXml(T o, XmlSerializer serializer, Context context)
-                throws IOException;
+        public abstract void writeToXml(T o, XmlSerializer serializer, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException;
 
         /**
          * Read from the supplied XML into a new object, returning null in case of an
@@ -2017,8 +2060,8 @@
          * object's writeToXml(). This object tries to fail early without modifying
          * 'parser' if it does not recognize the data it sees.
          */
-        public abstract T readFromXml(XmlPullParser parser, int version, Context context)
-                throws IOException, XmlPullParserException;
+        public abstract T readFromXml(XmlPullParser parser, int version, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException, XmlPullParserException;
 
         protected void writeTextIfNonNull(String tagName, Object value, XmlSerializer serializer)
                 throws IOException {
@@ -2030,6 +2073,29 @@
         }
 
         /**
+         * Serializes a List of PhoneAccountHandles.
+         * @param tagName The tag for the List
+         * @param handles The List of PhoneAccountHandles to serialize
+         * @param serializer The serializer
+         * @throws IOException if serialization fails.
+         */
+        protected void writePhoneAccountHandleSet(String tagName, Set<PhoneAccountHandle> handles,
+                XmlSerializer serializer, Context context, FeatureFlags telephonyFeatureFlags)
+                throws IOException {
+            serializer.startTag(null, tagName);
+            if (handles != null) {
+                serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(handles.size()));
+                for (PhoneAccountHandle handle : handles) {
+                    sPhoneAccountHandleXml.writeToXml(handle, serializer, context,
+                            telephonyFeatureFlags);
+                }
+            } else {
+                serializer.attribute(null, ATTRIBUTE_LENGTH, "0");
+            }
+            serializer.endTag(null, tagName);
+        }
+
+        /**
          * Serializes a string array.
          *
          * @param tagName The tag name for the string array.
@@ -2123,6 +2189,21 @@
             serializer.endTag(null, tagName);
         }
 
+        protected Set<PhoneAccountHandle> readPhoneAccountHandleSet(XmlPullParser parser,
+                int version, Context context, FeatureFlags telephonyFeatureFlags)
+                throws IOException, XmlPullParserException {
+            int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH));
+            Set<PhoneAccountHandle> handles = new HashSet<>(length);
+            if (length == 0) return handles;
+
+            int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                handles.add(sPhoneAccountHandleXml.readFromXml(parser, version, context,
+                        telephonyFeatureFlags));
+            }
+            return handles;
+        }
+
         /**
          * Reads a string array from the XML parser.
          *
@@ -2230,8 +2311,8 @@
         private static final String VERSION = "version";
 
         @Override
-        public void writeToXml(State o, XmlSerializer serializer, Context context)
-                throws IOException {
+        public void writeToXml(State o, XmlSerializer serializer, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException {
             if (o != null) {
                 serializer.startTag(null, CLASS_STATE);
                 serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION));
@@ -2239,14 +2320,15 @@
                 serializer.startTag(null, DEFAULT_OUTGOING);
                 for (DefaultPhoneAccountHandle defaultPhoneAccountHandle : o
                         .defaultOutgoingAccountHandles.values()) {
-                    sDefaultPhoneAcountHandleXml
-                            .writeToXml(defaultPhoneAccountHandle, serializer, context);
+                    sDefaultPhoneAccountHandleXml
+                            .writeToXml(defaultPhoneAccountHandle, serializer, context,
+                                    telephonyFeatureFlags);
                 }
                 serializer.endTag(null, DEFAULT_OUTGOING);
 
                 serializer.startTag(null, ACCOUNTS);
                 for (PhoneAccount m : o.accounts) {
-                    sPhoneAccountXml.writeToXml(m, serializer, context);
+                    sPhoneAccountXml.writeToXml(m, serializer, context, telephonyFeatureFlags);
                 }
                 serializer.endTag(null, ACCOUNTS);
 
@@ -2255,8 +2337,8 @@
         }
 
         @Override
-        public State readFromXml(XmlPullParser parser, int version, Context context)
-                throws IOException, XmlPullParserException {
+        public State readFromXml(XmlPullParser parser, int version, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException, XmlPullParserException {
             if (parser.getName().equals(CLASS_STATE)) {
                 State s = new State();
 
@@ -2272,7 +2354,8 @@
                             // assume there are no groups.
                             parser.nextTag();
                             PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml
-                                    .readFromXml(parser, s.versionNumber, context);
+                                    .readFromXml(parser, s.versionNumber, context,
+                                            telephonyFeatureFlags);
                             UserManager userManager = UserManager.get(context);
                             UserInfo primaryUser = userManager.getPrimaryUser();
                             if (primaryUser != null) {
@@ -2287,8 +2370,9 @@
                             int defaultAccountHandlesDepth = parser.getDepth();
                             while (XmlUtils.nextElementWithin(parser, defaultAccountHandlesDepth)) {
                                 DefaultPhoneAccountHandle accountHandle
-                                        = sDefaultPhoneAcountHandleXml
-                                        .readFromXml(parser, s.versionNumber, context);
+                                        = sDefaultPhoneAccountHandleXml
+                                        .readFromXml(parser, s.versionNumber, context,
+                                                telephonyFeatureFlags);
                                 if (accountHandle != null && s.accounts != null) {
                                     s.defaultOutgoingAccountHandles
                                             .put(accountHandle.userHandle, accountHandle);
@@ -2299,7 +2383,7 @@
                         int accountsDepth = parser.getDepth();
                         while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
                             PhoneAccount account = sPhoneAccountXml.readFromXml(parser,
-                                    s.versionNumber, context);
+                                    s.versionNumber, context, telephonyFeatureFlags);
 
                             if (account != null && s.accounts != null) {
                                 s.accounts.add(account);
@@ -2314,7 +2398,7 @@
     };
 
     @VisibleForTesting
-    public static final XmlSerialization<DefaultPhoneAccountHandle> sDefaultPhoneAcountHandleXml  =
+    public static final XmlSerialization<DefaultPhoneAccountHandle> sDefaultPhoneAccountHandleXml =
             new XmlSerialization<DefaultPhoneAccountHandle>() {
                 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE
                         = "default_outgoing_phone_account_handle";
@@ -2324,7 +2408,7 @@
 
                 @Override
                 public void writeToXml(DefaultPhoneAccountHandle o, XmlSerializer serializer,
-                        Context context) throws IOException {
+                        Context context, FeatureFlags telephonyFeatureFlags) throws IOException {
                     if (o != null) {
                         final UserManager userManager = UserManager.get(context);
                         final long serialNumber = userManager.getSerialNumberForUser(o.userHandle);
@@ -2334,7 +2418,7 @@
                             writeNonNullString(GROUP_ID, o.groupId, serializer);
                             serializer.startTag(null, ACCOUNT_HANDLE);
                             sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer,
-                                    context);
+                                    context, telephonyFeatureFlags);
                             serializer.endTag(null, ACCOUNT_HANDLE);
                             serializer.endTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
                         }
@@ -2343,7 +2427,7 @@
 
                 @Override
                 public DefaultPhoneAccountHandle readFromXml(XmlPullParser parser, int version,
-                        Context context)
+                        Context context, FeatureFlags telephonyFeatureFlags)
                         throws IOException, XmlPullParserException {
                     if (parser.getName().equals(CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE)) {
                         int outerDepth = parser.getDepth();
@@ -2354,7 +2438,7 @@
                             if (parser.getName().equals(ACCOUNT_HANDLE)) {
                                 parser.nextTag();
                                 accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
-                                        context);
+                                        context, telephonyFeatureFlags);
                             } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
                                 parser.next();
                                 userSerialNumberString = parser.getText();
@@ -2405,16 +2489,19 @@
         private static final String ICON = "icon";
         private static final String EXTRAS = "extras";
         private static final String ENABLED = "enabled";
+        private static final String SIMULTANEOUS_CALLING_RESTRICTION
+                = "simultaneous_calling_restriction";
 
         @Override
-        public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context)
-                throws IOException {
+        public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException {
             if (o != null) {
                 serializer.startTag(null, CLASS_PHONE_ACCOUNT);
 
                 if (o.getAccountHandle() != null) {
                     serializer.startTag(null, ACCOUNT_HANDLE);
-                    sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context);
+                    sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context,
+                            telephonyFeatureFlags);
                     serializer.endTag(null, ACCOUNT_HANDLE);
                 }
 
@@ -2431,13 +2518,19 @@
                 writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
                 writeTextIfNonNull(SUPPORTED_AUDIO_ROUTES, Integer.toString(
                         o.getSupportedAudioRoutes()), serializer);
+                if (o.hasSimultaneousCallingRestriction()
+                        && telephonyFeatureFlags.simultaneousCallingIndications()) {
+                    writePhoneAccountHandleSet(SIMULTANEOUS_CALLING_RESTRICTION,
+                            o.getSimultaneousCallingRestriction(), serializer, context,
+                            telephonyFeatureFlags);
+                }
 
                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
             }
         }
 
-        public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context)
-                throws IOException, XmlPullParserException {
+        public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException, XmlPullParserException {
             if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) {
                 int outerDepth = parser.getDepth();
                 PhoneAccountHandle accountHandle = null;
@@ -2456,12 +2549,13 @@
                 Icon icon = null;
                 boolean enabled = false;
                 Bundle extras = null;
+                Set<PhoneAccountHandle> simultaneousCallingRestriction = null;
 
                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
                         parser.nextTag();
                         accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
-                                context);
+                                context, telephonyFeatureFlags);
                     } else if (parser.getName().equals(ADDRESS)) {
                         parser.next();
                         address = Uri.parse(parser.getText());
@@ -2506,6 +2600,12 @@
                     } else if (parser.getName().equals(SUPPORTED_AUDIO_ROUTES)) {
                         parser.next();
                         supportedAudioRoutes = Integer.parseInt(parser.getText());
+                    } else if (parser.getName().equals(SIMULTANEOUS_CALLING_RESTRICTION)) {
+                        // We can not flag this because we always need to handle the case where
+                        // this info is in the XML for parsing reasons. We only flag setting the
+                        // parsed value below based on the flag.
+                        simultaneousCallingRestriction = readPhoneAccountHandleSet(parser, version,
+                                context, telephonyFeatureFlags);
                     }
                 }
 
@@ -2587,6 +2687,9 @@
                 } else if (!TextUtils.isEmpty(iconPackageName)) {
                     builder.setIcon(Icon.createWithResource(iconPackageName, iconResId));
                     // TODO: Need to set tint.
+                } else if (simultaneousCallingRestriction != null
+                        && telephonyFeatureFlags.simultaneousCallingIndications()) {
+                    builder.setSimultaneousCallingRestriction(simultaneousCallingRestriction);
                 }
 
                 return builder.build();
@@ -2618,8 +2721,8 @@
         private static final String USER_SERIAL_NUMBER = "user_serial_number";
 
         @Override
-        public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context)
-                throws IOException {
+        public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException {
             if (o != null) {
                 serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
 
@@ -2641,8 +2744,8 @@
         }
 
         @Override
-        public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context)
-                throws IOException, XmlPullParserException {
+        public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context,
+                FeatureFlags telephonyFeatureFlags) throws IOException, XmlPullParserException {
             if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) {
                 String componentNameString = null;
                 String idString = null;
@@ -2682,8 +2785,4 @@
             return null;
         }
     };
-
-    private String nullToEmpty(String str) {
-        return str == null ? "" : str;
-    }
 }
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 61fa9ba..b954588 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -1994,8 +1994,12 @@
 
             if (args != null && args.length > 0 && Analytics.ANALYTICS_DUMPSYS_ARG.equals(
                     args[0])) {
-                Binder.withCleanCallingIdentity(() ->
-                        Analytics.dumpToEncodedProto(mContext, writer, args));
+                long token = Binder.clearCallingIdentity();
+                try {
+                    Analytics.dumpToEncodedProto(mContext, writer, args);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
                 return;
             }
 
@@ -2243,7 +2247,8 @@
             try {
                 synchronized (mLock) {
                     enforceShellOnly(Binder.getCallingUid(), "cleanupStuckCalls");
-                    Binder.withCleanCallingIdentity(() -> {
+                    long token = Binder.clearCallingIdentity();
+                    try {
                         Set<UserHandle> userHandles = new HashSet<>();
                         for (Call call : mCallsManager.getCalls()) {
                             call.cleanup();
@@ -2256,7 +2261,9 @@
                         for (UserHandle userHandle : userHandles) {
                             mCallsManager.getInCallController().unbindFromServices(userHandle);
                         }
-                    });
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
                 }
             } finally {
                 Log.endSession();
@@ -2333,11 +2340,14 @@
             try {
                 synchronized (mLock) {
                     enforceShellOnly(Binder.getCallingUid(), "resetCarMode");
-                    Binder.withCleanCallingIdentity(() -> {
+                    long token = Binder.clearCallingIdentity();
+                    try {
                         UiModeManager uiModeManager =
                                 mContext.getSystemService(UiModeManager.class);
                         uiModeManager.disableCarMode(UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES);
-                    });
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
                 }
             } finally {
                 Log.endSession();
@@ -2500,19 +2510,18 @@
          */
         @Override
         public boolean isInSelfManagedCall(String packageName, UserHandle userHandle,
-                String callingPackage) {
+                String callingPackage, boolean hasCrossUserAccess) {
             try {
-                if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                    throw new SecurityException("Only the system can call this API");
-                }
                 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
                         "READ_PRIVILEGED_PHONE_STATE required.");
+                enforceInAppCrossUserPermission();
 
                 Log.startSession("TSI.iISMC", Log.getPackageAbbreviation(callingPackage));
                 synchronized (mLock) {
                     long token = Binder.clearCallingIdentity();
                     try {
-                        return mCallsManager.isInSelfManagedCall(packageName, userHandle);
+                        return mCallsManager.isInSelfManagedCallCrossUsers(
+                                packageName, userHandle, hasCrossUserAccess);
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 4310945..9f6fcba 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -141,6 +141,7 @@
     private final TelecomServiceImpl mTelecomServiceImpl;
     private final ContactsAsyncHelper mContactsAsyncHelper;
     private final DialerCodeReceiver mDialerCodeReceiver;
+    private final FeatureFlags mFeatureFlags;
 
     private boolean mIsBootComplete = false;
 
@@ -231,6 +232,7 @@
             BlockedNumbersAdapter blockedNumbersAdapter,
             FeatureFlags featureFlags) {
         mContext = context.getApplicationContext();
+        mFeatureFlags = featureFlags;
         LogUtils.initLogging(mContext);
         android.telecom.Log.setLock(mLock);
         AnomalyReporter.initialize(mContext);
@@ -347,14 +349,22 @@
             ToastFactory toastFactory = new ToastFactory() {
                 @Override
                 public Toast makeText(Context context, int resId, int duration) {
-                    return Toast.makeText(context, context.getMainLooper(),
-                            context.getString(resId),
-                            duration);
+                    if (mFeatureFlags.telecomResolveHiddenDependencies()) {
+                        return Toast.makeText(context, resId, duration);
+                    } else {
+                        return Toast.makeText(context, context.getMainLooper(),
+                                context.getString(resId),
+                                duration);
+                    }
                 }
 
                 @Override
                 public Toast makeText(Context context, CharSequence text, int duration) {
-                    return Toast.makeText(context, context.getMainLooper(), text, duration);
+                    if (mFeatureFlags.telecomResolveHiddenDependencies()) {
+                        return Toast.makeText(context, text, duration);
+                    } else {
+                        return Toast.makeText(context, context.getMainLooper(), text, duration);
+                    }
                 }
             };
 
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 2d10f40..0ce5836 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -26,7 +26,9 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -62,6 +64,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.telecom.IConnectionService;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.server.telecom.AppLabelProxy;
 import com.android.server.telecom.DefaultDialerCache;
@@ -90,6 +93,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -115,7 +119,7 @@
     @Mock private TelecomManager mTelecomManager;
     @Mock private DefaultDialerCache mDefaultDialerCache;
     @Mock private AppLabelProxy mAppLabelProxy;
-    @Mock private com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags;
+    @Mock private FeatureFlags mTelephonyFeatureFlags;
 
     @Override
     @Before
@@ -155,12 +159,12 @@
     public void testPhoneAccountHandle() throws Exception {
         PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
         PhoneAccountHandle result = roundTripXml(this, input,
-                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
+                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext, mTelephonyFeatureFlags);
         assertPhoneAccountHandleEquals(input, result);
 
         PhoneAccountHandle inputN = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), null);
         PhoneAccountHandle resultN = roundTripXml(this, inputN,
-                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext);
+                PhoneAccountRegistrar.sPhoneAccountHandleXml, mContext, mTelephonyFeatureFlags);
         Log.i(this, "inputN = %s, resultN = %s", inputN, resultN);
         assertPhoneAccountHandleEquals(inputN, resultN);
     }
@@ -183,7 +187,112 @@
                 .setIsEnabled(true)
                 .build();
         PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
-                mContext);
+                mContext, mTelephonyFeatureFlags);
+
+        assertPhoneAccountEquals(input, result);
+    }
+
+    @MediumTest
+    @Test
+    public void testPhoneAccountParsing_simultaneousCallingRestriction() throws Exception {
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        // workaround: UserManager converts the user to a serial and back, we need to mock this
+        // behavior, unfortunately: USER_HANDLE_10 <-> 10L
+        UserManager userManager = UserManager.get(mContext);
+        doReturn(10L).when(userManager).getSerialNumberForUser(eq(USER_HANDLE_10));
+        doReturn(USER_HANDLE_10).when(userManager).getUserForSerialNumber(eq(10L));
+        Bundle testBundle = new Bundle();
+        testBundle.putInt("EXTRA_INT_1", 1);
+        testBundle.putInt("EXTRA_INT_100", 100);
+        testBundle.putBoolean("EXTRA_BOOL_TRUE", true);
+        testBundle.putBoolean("EXTRA_BOOL_FALSE", false);
+        testBundle.putString("EXTRA_STR1", "Hello");
+        testBundle.putString("EXTRA_STR2", "There");
+
+        Set<PhoneAccountHandle> restriction = new HashSet<>(10);
+        for (int i = 0; i < 10; i++) {
+            restriction.add(makeQuickAccountHandleForUser("id" + i, USER_HANDLE_10));
+        }
+
+        PhoneAccount input = makeQuickAccountBuilder("id0", 0, USER_HANDLE_10)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+                .setExtras(testBundle)
+                .setIsEnabled(true)
+                .setSimultaneousCallingRestriction(restriction)
+                .build();
+        PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
+                mContext, mTelephonyFeatureFlags);
+
+        assertPhoneAccountEquals(input, result);
+    }
+
+    @MediumTest
+    @Test
+    public void testPhoneAccountParsing_simultaneousCallingRestrictionOnOffFlag() throws Exception {
+        // Start the test with the flag on
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        // workaround: UserManager converts the user to a serial and back, we need to mock this
+        // behavior, unfortunately: USER_HANDLE_10 <-> 10L
+        UserManager userManager = UserManager.get(mContext);
+        doReturn(10L).when(userManager).getSerialNumberForUser(eq(USER_HANDLE_10));
+        doReturn(USER_HANDLE_10).when(userManager).getUserForSerialNumber(eq(10L));
+        Bundle testBundle = new Bundle();
+        testBundle.putInt("EXTRA_INT_1", 1);
+        testBundle.putInt("EXTRA_INT_100", 100);
+        testBundle.putBoolean("EXTRA_BOOL_TRUE", true);
+        testBundle.putBoolean("EXTRA_BOOL_FALSE", false);
+        testBundle.putString("EXTRA_STR1", "Hello");
+        testBundle.putString("EXTRA_STR2", "There");
+
+        Set<PhoneAccountHandle> restriction = new HashSet<>(10);
+        for (int i = 0; i < 10; i++) {
+            restriction.add(makeQuickAccountHandleForUser("id" + i, USER_HANDLE_10));
+        }
+
+        PhoneAccount input = makeQuickAccountBuilder("id0", 0, USER_HANDLE_10)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+                .setExtras(testBundle)
+                .setIsEnabled(true)
+                .setSimultaneousCallingRestriction(restriction)
+                .build();
+        byte[] xmlData = toXml(input, PhoneAccountRegistrar.sPhoneAccountXml, mContext,
+                mTelephonyFeatureFlags);
+        // Simulate turning off the flag after reboot
+        doReturn(false).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        PhoneAccount result = fromXml(xmlData, PhoneAccountRegistrar.sPhoneAccountXml, mContext,
+                mTelephonyFeatureFlags);
+
+        assertNotNull(result);
+        assertFalse(result.hasSimultaneousCallingRestriction());
+    }
+
+    @MediumTest
+    @Test
+    public void testPhoneAccountParsing_simultaneousCallingRestrictionOffOnFlag() throws Exception {
+        // Start the test with the flag on
+        doReturn(false).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        Bundle testBundle = new Bundle();
+        testBundle.putInt("EXTRA_INT_1", 1);
+        testBundle.putInt("EXTRA_INT_100", 100);
+        testBundle.putBoolean("EXTRA_BOOL_TRUE", true);
+        testBundle.putBoolean("EXTRA_BOOL_FALSE", false);
+        testBundle.putString("EXTRA_STR1", "Hello");
+        testBundle.putString("EXTRA_STR2", "There");
+
+        PhoneAccount input = makeQuickAccountBuilder("id0", 0, USER_HANDLE_10)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+                .setExtras(testBundle)
+                .setIsEnabled(true)
+                .build();
+        byte[] xmlData = toXml(input, PhoneAccountRegistrar.sPhoneAccountXml, mContext,
+                mTelephonyFeatureFlags);
+        // Simulate turning on the flag after reboot
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        PhoneAccount result = fromXml(xmlData, PhoneAccountRegistrar.sPhoneAccountXml, mContext,
+                mTelephonyFeatureFlags);
 
         assertPhoneAccountEquals(input, result);
     }
@@ -260,7 +369,8 @@
         when(UserManager.get(mContext).getUserForSerialNumber(0L))
                 .thenReturn(input.userHandle);
         DefaultPhoneAccountHandle result = roundTripXml(this, input,
-                PhoneAccountRegistrar.sDefaultPhoneAcountHandleXml, mContext);
+                PhoneAccountRegistrar.sDefaultPhoneAccountHandleXml, mContext,
+                mTelephonyFeatureFlags);
 
         assertDefaultPhoneAccountHandleEquals(input, result);
     }
@@ -290,7 +400,7 @@
                 .setExtras(testBundle)
                 .build();
         PhoneAccount result = roundTripXml(this, input, PhoneAccountRegistrar.sPhoneAccountXml,
-                mContext);
+                mContext, mTelephonyFeatureFlags);
 
         Bundle extras = result.getExtras();
         assertFalse(extras.keySet().contains("EXTRA_STR2"));
@@ -304,8 +414,7 @@
     public void testState() throws Exception {
         PhoneAccountRegistrar.State input = makeQuickState();
         PhoneAccountRegistrar.State result = roundTripXml(this, input,
-                PhoneAccountRegistrar.sStateXml,
-                mContext);
+                PhoneAccountRegistrar.sStateXml, mContext, mTelephonyFeatureFlags);
         assertStateEquals(input, result);
     }
 
@@ -1625,6 +1734,107 @@
     }
 
     /**
+     * Ensure an IllegalArgumentException is thrown when adding too many PhoneAccountHandles to
+     * a PhoneAccount.
+     */
+    @Test
+    public void testLimitOnSimultaneousCallingRestriction_tooManyElements() throws Exception {
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+        Set<PhoneAccountHandle> tooManyElements = new HashSet<>(11);
+        for (int i = 0; i < 11; i++) {
+            tooManyElements.add(makeQuickAccountHandle(TEST_ID + i));
+        }
+        PhoneAccount tooManyRestrictionsPA = new PhoneAccount.Builder(
+                makeQuickAccountHandle(TEST_ID), TEST_LABEL)
+                .setSimultaneousCallingRestriction(tooManyElements)
+                .build();
+        try {
+            mRegistrar.registerPhoneAccount(tooManyRestrictionsPA);
+            fail("should have hit registrations exception in "
+                    + "enforceSimultaneousCallingRestrictionLimit");
+        } catch (IllegalArgumentException e) {
+            // pass test
+        }
+    }
+
+    /**
+     * Ensure an IllegalArgumentException is thrown when adding a PhoneAccountHandle where the
+     * package name field is too large.
+     */
+    @Test
+    public void testLimitOnSimultaneousCallingRestriction_InvalidPackageName() throws Exception {
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+        Set<PhoneAccountHandle> invalidElement = new HashSet<>(1);
+        invalidElement.add(new PhoneAccountHandle(new ComponentName(INVALID_STR, "Class"),
+                TEST_ID));
+        PhoneAccount invalidRestrictionPA = new PhoneAccount.Builder(
+                makeQuickAccountHandle(TEST_ID), TEST_LABEL)
+                .setSimultaneousCallingRestriction(invalidElement)
+                .build();
+        try {
+            mRegistrar.registerPhoneAccount(invalidRestrictionPA);
+            fail("should have hit package name size limit exception in "
+                    + "enforceSimultaneousCallingRestrictionLimit");
+        } catch (IllegalArgumentException e) {
+            // pass test
+        }
+    }
+
+    /**
+     * Ensure an IllegalArgumentException is thrown when adding a PhoneAccountHandle where the
+     * class name field is too large.
+     */
+    @Test
+    public void testLimitOnSimultaneousCallingRestriction_InvalidClassName() throws Exception {
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+        Set<PhoneAccountHandle> invalidElement = new HashSet<>(1);
+        invalidElement.add(new PhoneAccountHandle(new ComponentName("pkg", INVALID_STR),
+                TEST_ID));
+        PhoneAccount invalidRestrictionPA = new PhoneAccount.Builder(
+                makeQuickAccountHandle(TEST_ID), TEST_LABEL)
+                .setSimultaneousCallingRestriction(invalidElement)
+                .build();
+        try {
+            mRegistrar.registerPhoneAccount(invalidRestrictionPA);
+            fail("should have hit class name size limit exception in "
+                    + "enforceSimultaneousCallingRestrictionLimit");
+        } catch (IllegalArgumentException e) {
+            // pass test
+        }
+    }
+
+    /**
+     * Ensure an IllegalArgumentException is thrown when adding a PhoneAccountHandle where the
+     * ID field is too large.
+     */
+    @Test
+    public void testLimitOnSimultaneousCallingRestriction_InvalidIdSize() throws Exception {
+        doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+        Set<PhoneAccountHandle> invalidIdElement = new HashSet<>(1);
+        invalidIdElement.add(new PhoneAccountHandle(makeQuickConnectionServiceComponentName(),
+                INVALID_STR));
+        PhoneAccount invalidRestrictionPA = new PhoneAccount.Builder(
+                makeQuickAccountHandle(TEST_ID), TEST_LABEL)
+                .setSimultaneousCallingRestriction(invalidIdElement)
+                .build();
+        try {
+            mRegistrar.registerPhoneAccount(invalidRestrictionPA);
+            fail("should have hit ID size limit exception in "
+                    + "enforceSimultaneousCallingRestrictionLimit");
+        } catch (IllegalArgumentException e) {
+            // pass test
+        }
+    }
+
+    /**
      * Ensure an IllegalArgumentException is thrown when adding an address over the limit
      */
     @Test
@@ -1869,35 +2079,41 @@
             Object self,
             T input,
             PhoneAccountRegistrar.XmlSerialization<T> xml,
-            Context context)
+            Context context,
+            FeatureFlags telephonyFeatureFlags)
             throws Exception {
         Log.d(self, "Input = %s", input);
 
-        byte[] data;
-        {
-            XmlSerializer serializer = new FastXmlSerializer();
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
-            xml.writeToXml(input, serializer, context);
-            serializer.flush();
-            data = baos.toByteArray();
-        }
+        byte[] data = toXml(input, xml, context, telephonyFeatureFlags);
 
         Log.i(self, "====== XML data ======\n%s", new String(data));
 
-        T result = null;
-        {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(new BufferedInputStream(new ByteArrayInputStream(data)), null);
-            parser.nextTag();
-            result = xml.readFromXml(parser, MAX_VERSION, context);
-        }
+        T result = fromXml(data, xml, context, telephonyFeatureFlags);
 
         Log.i(self, "result = " + result);
 
         return result;
     }
 
+    private static <T> byte[] toXml(T input, PhoneAccountRegistrar.XmlSerialization<T> xml,
+            Context context, FeatureFlags telephonyFeatureFlags) throws Exception {
+        XmlSerializer serializer = new FastXmlSerializer();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+        xml.writeToXml(input, serializer, context, telephonyFeatureFlags);
+        serializer.flush();
+        return baos.toByteArray();
+    }
+
+    private static <T> T fromXml(byte[] data, PhoneAccountRegistrar.XmlSerialization<T> xml,
+            Context context, FeatureFlags telephonyFeatureFlags) throws Exception {
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(data)), null);
+        parser.nextTag();
+        return xml.readFromXml(parser, MAX_VERSION, context, telephonyFeatureFlags);
+
+    }
+
     private static void assertPhoneAccountHandleEquals(PhoneAccountHandle a, PhoneAccountHandle b) {
         if (a != b) {
             assertEquals(
@@ -1946,6 +2162,12 @@
                 assertEquals(a.getSupportedUriSchemes(), b.getSupportedUriSchemes());
                 assertBundlesEqual(a.getExtras(), b.getExtras());
                 assertEquals(a.isEnabled(), b.isEnabled());
+                assertEquals(a.hasSimultaneousCallingRestriction(),
+                        b.hasSimultaneousCallingRestriction());
+                if (a.hasSimultaneousCallingRestriction()) {
+                    assertEquals(a.getSimultaneousCallingRestriction(),
+                            b.getSimultaneousCallingRestriction());
+                }
             } else {
                 fail("Phone accounts not equal: " + a + ", " + b);
             }