Merge "Add Group Id tracking in PhoneAccountRegistrar" into nyc-mr1-dev
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index 19c1a01..41eb9e4 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -59,7 +59,6 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -76,8 +75,12 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
@@ -244,6 +247,46 @@
     }
 
     /**
+     * @return The {@link DefaultPhoneAccountHandle} containing the user-selected default calling
+     * account and group Id for the {@link UserHandle} specified.
+     */
+    private DefaultPhoneAccountHandle getUserSelectedDefaultPhoneAccount(UserHandle userHandle) {
+        if (userHandle == null) {
+            return null;
+        }
+        DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
+                .get(userHandle);
+        if (defaultPhoneAccountHandle == null) {
+            return null;
+        }
+
+        return defaultPhoneAccountHandle;
+    }
+
+    /**
+     * @return The currently registered PhoneAccount in Telecom that has the same group Id.
+     */
+    private PhoneAccount getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName,
+            UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle) {
+        if (groupId == null || groupId.isEmpty() || userHandle == null) {
+            return null;
+        }
+        // Get the PhoneAccount with the same group Id (and same ComponentName) that is not the
+        // newAccount that was just added
+        List<PhoneAccount> accounts = getAllPhoneAccounts(userHandle).stream()
+                .filter(account -> groupId.equals(account.getGroupId()) &&
+                        !account.getAccountHandle().equals(excludePhoneAccountHandle) &&
+                        Objects.equals(account.getAccountHandle().getComponentName(),
+                                groupComponentName))
+                .collect(Collectors.toList());
+        // There should be one or no PhoneAccounts with the same group Id
+        if (accounts.size() > 1) {
+            Log.w(this, "Found multiple PhoneAccounts registered to the same Group Id!");
+        }
+        return accounts.isEmpty() ? null : accounts.get(0);
+    }
+
+    /**
      * Sets the phone account with which to place all calls by default. Set by the user
      * within phone settings.
      */
@@ -277,7 +320,8 @@
             }
 
             mState.defaultOutgoingAccountHandles
-                    .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle));
+                    .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle,
+                            account.getGroupId()));
         }
 
         write();
@@ -591,6 +635,8 @@
         }
 
         mState.accounts.add(account);
+        // Set defaults and replace based on the group Id.
+        maybeReplaceOldAccount(account);
         // Reset enabled state to whatever the value was if the account was already registered,
         // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled.
         account.setIsEnabled(
@@ -697,6 +743,40 @@
         }
     }
 
+    private void maybeReplaceOldAccount(PhoneAccount newAccount) {
+        UserHandle newAccountUserHandle = newAccount.getAccountHandle().getUserHandle();
+        DefaultPhoneAccountHandle defaultHandle =
+                getUserSelectedDefaultPhoneAccount(newAccountUserHandle);
+        if (defaultHandle == null || defaultHandle.groupId.isEmpty()) {
+            Log.v(this, "maybeReplaceOldAccount: Not replacing PhoneAccount, no group Id or " +
+                    "default.");
+            return;
+        }
+        if (!defaultHandle.groupId.equals(newAccount.getGroupId())) {
+            Log.v(this, "maybeReplaceOldAccount: group Ids are not equal.");
+            return;
+        }
+        if (Objects.equals(newAccount.getAccountHandle().getComponentName(),
+                defaultHandle.phoneAccountHandle.getComponentName())) {
+            // Move default calling account over to new user, since the ComponentNames and Group Ids
+            // are the same.
+            setUserSelectedOutgoingPhoneAccount(newAccount.getAccountHandle(),
+                    newAccountUserHandle);
+        } else {
+            Log.v(this, "maybeReplaceOldAccount: group Ids are equal, but ComponentName is not" +
+                    " the same as the default. Not replacing default PhoneAccount.");
+        }
+        PhoneAccount replacementAccount = getPhoneAccountByGroupId(newAccount.getGroupId(),
+                newAccount.getAccountHandle().getComponentName(), newAccountUserHandle,
+                newAccount.getAccountHandle());
+        if (replacementAccount != null) {
+            // Unregister the old PhoneAccount.
+            Log.v(this, "maybeReplaceOldAccount: Unregistering old PhoneAccount: " +
+                    replacementAccount.getAccountHandle());
+            unregisterPhoneAccount(replacementAccount.getAccountHandle());
+        }
+    }
+
     /**
      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
@@ -904,10 +984,13 @@
 
         public final PhoneAccountHandle phoneAccountHandle;
 
+        public final String groupId;
+
         public DefaultPhoneAccountHandle(UserHandle userHandle,
-                PhoneAccountHandle phoneAccountHandle) {
+                PhoneAccountHandle phoneAccountHandle, String groupId) {
             this.userHandle = userHandle;
             this.phoneAccountHandle = phoneAccountHandle;
+            this.groupId = groupId;
         }
     }
 
@@ -1154,6 +1237,13 @@
             serializer.endTag(null, tagName);
         }
 
+        protected void writeNonNullString(String tagName, String value, XmlSerializer serializer)
+                throws IOException {
+            serializer.startTag(null, tagName);
+            serializer.text(value != null ? value : "");
+            serializer.endTag(null, tagName);
+        }
+
         /**
          * Reads a string array from the XML parser.
          *
@@ -1292,8 +1382,9 @@
                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                     if (parser.getName().equals(DEFAULT_OUTGOING)) {
                         if (s.versionNumber < 9) {
-                            // Migration old default phone account handle here by assuming the
-                            // default phone account handle is belong to primary user.
+                            // Migrate old default phone account handle here by assuming the
+                            // default phone account handle belongs to the primary user. Also,
+                            // assume there are no groups.
                             parser.nextTag();
                             PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml
                                     .readFromXml(parser, s.versionNumber, context);
@@ -1303,7 +1394,7 @@
                                 UserHandle userHandle = primaryUser.getUserHandle();
                                 DefaultPhoneAccountHandle defaultPhoneAccountHandle
                                         = new DefaultPhoneAccountHandle(userHandle,
-                                        phoneAccountHandle);
+                                        phoneAccountHandle, "" /* groupId */);
                                 s.defaultOutgoingAccountHandles
                                         .put(userHandle, defaultPhoneAccountHandle);
                             }
@@ -1343,6 +1434,7 @@
                 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE
                         = "default_outgoing_phone_account_handle";
                 private static final String USER_SERIAL_NUMBER = "user_serial_number";
+                private static final String GROUP_ID = "group_id";
                 private static final String ACCOUNT_HANDLE = "account_handle";
 
                 @Override
@@ -1354,6 +1446,7 @@
                         if (serialNumber != -1) {
                             serializer.startTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
                             writeLong(USER_SERIAL_NUMBER, serialNumber, serializer);
+                            writeNonNullString(GROUP_ID, o.groupId, serializer);
                             serializer.startTag(null, ACCOUNT_HANDLE);
                             sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer,
                                     context);
@@ -1371,6 +1464,7 @@
                         int outerDepth = parser.getDepth();
                         PhoneAccountHandle accountHandle = null;
                         String userSerialNumberString = null;
+                        String groupId = "";
                         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
                             if (parser.getName().equals(ACCOUNT_HANDLE)) {
                                 parser.nextTag();
@@ -1379,6 +1473,9 @@
                             } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
                                 parser.next();
                                 userSerialNumberString = parser.getText();
+                            } else if (parser.getName().equals(GROUP_ID)) {
+                                parser.next();
+                                groupId = parser.getText();
                             }
                         }
                         UserHandle userHandle = null;
@@ -1392,8 +1489,9 @@
                                         "Could not parse UserHandle " + userSerialNumberString);
                             }
                         }
-                        if (accountHandle != null && userHandle != null) {
-                            return new DefaultPhoneAccountHandle(userHandle, accountHandle);
+                        if (accountHandle != null && userHandle != null && groupId != null) {
+                            return new DefaultPhoneAccountHandle(userHandle, accountHandle,
+                                    groupId);
                         }
                     }
                     return null;
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index ceabc58..12d24c4 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -171,8 +171,7 @@
     public void testAccounts() throws Exception {
         int i = 0;
 
-        mComponentContextFixture.addConnectionService(
-                makeQuickConnectionServiceComponentName(),
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
                 Mockito.mock(IConnectionService.class));
 
         registerAndEnableAccount(makeQuickAccountBuilder("id" + i, i++)
@@ -205,8 +204,7 @@
 
     @MediumTest
     public void testDefaultOutgoing() throws Exception {
-        mComponentContextFixture.addConnectionService(
-                makeQuickConnectionServiceComponentName(),
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
                 Mockito.mock(IConnectionService.class));
 
         // By default, there is no default outgoing account (nothing has been registered)
@@ -253,6 +251,229 @@
     }
 
     @MediumTest
+    public void testReplacePhoneAccountByGroup() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        // Add call capable SIP account, make sure tel: doesn't change
+        PhoneAccountHandle sipAccount = makeQuickAccountHandle("sip_acct");
+        registerAndEnableAccount(new PhoneAccount.Builder(sipAccount, "sip_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        // Replace tel: account with another in the same Group
+        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        defaultAccount = mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount2, defaultAccount);
+        assertNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+    }
+
+    @MediumTest
+    public void testAddSameDefault() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+        mRegistrar.unregisterPhoneAccount(telAccount1);
+
+        // Register Emergency Account and unregister
+        PhoneAccountHandle emerAccount = makeQuickAccountHandle("emer_acct");
+        registerAndEnableAccount(new PhoneAccount.Builder(emerAccount, "emer_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertNull(defaultAccount);
+        mRegistrar.unregisterPhoneAccount(emerAccount);
+
+        // Re-register the same account and make sure the default is in place
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+    }
+
+    @MediumTest
+    public void testAddSameGroup() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+        mRegistrar.unregisterPhoneAccount(telAccount1);
+
+        // Register Emergency Account and unregister
+        PhoneAccountHandle emerAccount = makeQuickAccountHandle("emer_acct");
+        registerAndEnableAccount(new PhoneAccount.Builder(emerAccount, "emer_acct")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertNull(defaultAccount);
+        mRegistrar.unregisterPhoneAccount(emerAccount);
+
+        // Re-register a new account with the same group
+        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount2, defaultAccount);
+    }
+
+    @MediumTest
+    public void testAddSameGroupButDifferentComponent() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL));
+
+        // Register one tel: account
+        PhoneAccountHandle telAccount1 = makeQuickAccountHandle("tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+
+        // Register a new account with the same group, but different Component, so don't replace
+        // Default
+        PhoneAccountHandle telAccount2 =  makeQuickAccountHandle(
+                new ComponentName("other1", "other2"), "tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount2));
+
+        defaultAccount =
+                mRegistrar.getUserSelectedOutgoingPhoneAccount(Process.myUserHandle());
+        assertEquals(telAccount1, defaultAccount);
+    }
+
+    @MediumTest
+    public void testAddSameGroupButDifferentComponent2() throws Exception {
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        // By default, there is no default outgoing account (nothing has been registered)
+        assertNull(mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
+                PhoneAccount.SCHEME_TEL));
+
+        // Register first tel: account
+        PhoneAccountHandle telAccount1 =  makeQuickAccountHandle(
+                new ComponentName("other1", "other2"), "tel_acct1");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount1, "tel_acct1")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+        mRegistrar.setUserSelectedOutgoingPhoneAccount(telAccount1, Process.myUserHandle());
+
+        // Register second account with the same group, but a second Component, so don't replace
+        // Default
+        PhoneAccountHandle telAccount2 = makeQuickAccountHandle("tel_acct2");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount2, "tel_acct2")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+
+        PhoneAccountHandle defaultAccount =
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        // Register third account with the second component name, but same group id
+        PhoneAccountHandle telAccount3 = makeQuickAccountHandle("tel_acct3");
+        registerAndEnableAccount(new PhoneAccount.Builder(telAccount3, "tel_acct3")
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .setGroupId("testGroup")
+                .build());
+
+        // Make sure that the default account is still the original PhoneAccount and that the
+        // second PhoneAccount with the second ComponentName was replaced by the third PhoneAccount
+        defaultAccount =
+                mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL);
+        assertEquals(telAccount1, defaultAccount);
+
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount1));
+        assertNull(mRegistrar.getPhoneAccountUnchecked(telAccount2));
+        assertNotNull(mRegistrar.getPhoneAccountUnchecked(telAccount3));
+    }
+
+    @MediumTest
     public void testPhoneAccountParceling() throws Exception {
         PhoneAccountHandle handle = makeQuickAccountHandle("foo");
         roundTripPhoneAccount(new PhoneAccount.Builder(handle, null).build());
@@ -268,6 +489,7 @@
                         .setShortDescription("short description")
                         .setSubscriptionAddress(Uri.parse("tel:2345678"))
                         .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
+                        .setGroupId("testGroup")
                         .build());
         roundTripPhoneAccount(
                 new PhoneAccount.Builder(handle, "foo")
@@ -281,6 +503,7 @@
                         .setShortDescription("short description")
                         .setSubscriptionAddress(Uri.parse("tel:2345678"))
                         .setSupportedUriSchemes(Arrays.asList("tel", "sip"))
+                        .setGroupId("testGroup")
                         .build());
     }
 
@@ -291,10 +514,11 @@
     }
 
     private static PhoneAccountHandle makeQuickAccountHandle(String id) {
-        return new PhoneAccountHandle(
-                makeQuickConnectionServiceComponentName(),
-                id,
-                Process.myUserHandle());
+        return makeQuickAccountHandle(makeQuickConnectionServiceComponentName(), id);
+    }
+
+    private static PhoneAccountHandle makeQuickAccountHandle(ComponentName name, String id) {
+        return new PhoneAccountHandle(name, id, Process.myUserHandle());
     }
 
     private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
@@ -457,7 +681,8 @@
                 new ComponentName("pkg0", "cls0"), "id0");
         UserHandle userHandle = phoneAccountHandle.getUserHandle();
         s.defaultOutgoingAccountHandles
-                .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle));
+                .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle,
+                        "testGroup"));
         return s;
     }
 }