Loading src/com/android/server/telecom/PhoneAccountRegistrar.java +52 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ import java.lang.SecurityException; import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; Loading Loading @@ -1089,6 +1090,52 @@ public class PhoneAccountRegistrar { } } private void sortPhoneAccounts() { if (mState.accounts.size() > 1) { // Sort the phone accounts using sort order: // 1) SIM accounts first, followed by non-sim accounts // 2) Sort order, with those specifying no sort order last. // 3) Label // Comparator to sort SIM subscriptions before non-sim subscriptions. Comparator<PhoneAccount> bySimCapability = (p1, p2) -> { if (p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && !p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { return -1; } else if (!p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { return 1; } else { return 0; } }; // Create a string comparator which will sort strings, placing nulls last. Comparator<String> nullSafeStringComparator = Comparator.nullsLast( String::compareTo); // Comparator which places PhoneAccounts with a specified sort order first, followed by // those with no sort order. Comparator<PhoneAccount> bySortOrder = (p1, p2) -> { String sort1 = p1.getExtras() == null ? null : p1.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null); String sort2 = p2.getExtras() == null ? null : p2.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null); return nullSafeStringComparator.compare(sort1, sort2); }; // Comparator which sorts PhoneAccounts by label. Comparator<PhoneAccount> byLabel = (p1, p2) -> { String s1 = p1.getLabel() == null ? null : p1.getLabel().toString(); String s2 = p2.getLabel() == null ? null : p2.getLabel().toString(); return nullSafeStringComparator.compare(s1, s2); }; // Sort the phone accounts. mState.accounts.sort(bySimCapability.thenComparing(bySortOrder.thenComparing(byLabel))); } } //////////////////////////////////////////////////////////////////////////////////////////////// // // State management Loading @@ -1115,6 +1162,7 @@ public class PhoneAccountRegistrar { private void write() { try { sortPhoneAccounts(); ByteArrayOutputStream os = new ByteArrayOutputStream(); XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(os, "utf-8"); Loading Loading @@ -1870,4 +1918,8 @@ public class PhoneAccountRegistrar { return null; } }; private String nullToEmpty(String str) { return str == null ? "" : str; } } tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +187 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Set; import static org.mockito.Matchers.anyInt; Loading Loading @@ -577,6 +578,192 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { assertEquals(PhoneAccount.CAPABILITY_SELF_MANAGED, registeredAccount.getCapabilities()); } @MediumTest public void testSortSimFirst() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); PhoneAccount simAccount = new PhoneAccount.Builder( makeQuickAccountHandle(componentB, "2"), "2") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .setIsEnabled(true) .build(); PhoneAccount nonSimAccount = new PhoneAccount.Builder( makeQuickAccountHandle(componentA, "1"), "1") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .setIsEnabled(true) .build(); registerAndEnableAccount(nonSimAccount); registerAndEnableAccount(simAccount); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); assertTrue(accounts.get(0).getLabel().toString().equals("2")); assertTrue(accounts.get(1).getLabel().toString().equals("1")); } @MediumTest public void testSortBySortOrder() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); ComponentName componentC = new ComponentName("c", "c"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentC, Mockito.mock(IConnectionService.class)); PhoneAccount account1 = new PhoneAccount.Builder( makeQuickAccountHandle(componentA, "c"), "c") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "A")) .build(); PhoneAccount account2 = new PhoneAccount.Builder( makeQuickAccountHandle(componentB, "b"), "b") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "B")) .build(); PhoneAccount account3 = new PhoneAccount.Builder( makeQuickAccountHandle(componentC, "c"), "a") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); registerAndEnableAccount(account3); registerAndEnableAccount(account2); registerAndEnableAccount(account1); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); assertTrue(accounts.get(0).getLabel().toString().equals("c")); assertTrue(accounts.get(1).getLabel().toString().equals("b")); assertTrue(accounts.get(2).getLabel().toString().equals("a")); } @MediumTest public void testSortByLabel() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); ComponentName componentC = new ComponentName("c", "c"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentC, Mockito.mock(IConnectionService.class)); PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle(componentA, "c"), "c") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle(componentB, "b"), "b") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle(componentC, "a"), "a") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); registerAndEnableAccount(account1); registerAndEnableAccount(account2); registerAndEnableAccount(account3); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); assertTrue(accounts.get(0).getLabel().toString().equals("a")); assertTrue(accounts.get(1).getLabel().toString().equals("b")); assertTrue(accounts.get(2).getLabel().toString().equals("c")); } @MediumTest public void testSortAll() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); ComponentName componentC = new ComponentName("c", "c"); ComponentName componentW = new ComponentName("w", "w"); ComponentName componentX = new ComponentName("x", "x"); ComponentName componentY = new ComponentName("y", "y"); ComponentName componentZ = new ComponentName("z", "z"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentC, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentW, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentX, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentY, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentZ, Mockito.mock(IConnectionService.class)); PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "y"), "y") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "2")) .build(); PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "z"), "z") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "1")) .build(); PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "x"), "x") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .build(); PhoneAccount account4 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "w"), "w") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .build(); PhoneAccount account5 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "b"), "b") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); PhoneAccount account6 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "c"), "a") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); registerAndEnableAccount(account1); registerAndEnableAccount(account2); registerAndEnableAccount(account3); registerAndEnableAccount(account4); registerAndEnableAccount(account5); registerAndEnableAccount(account6); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); // Sim accts ordered by sort order first assertTrue(accounts.get(0).getLabel().toString().equals("z")); assertTrue(accounts.get(1).getLabel().toString().equals("y")); // Sim accts with no sort order next assertTrue(accounts.get(2).getLabel().toString().equals("w")); assertTrue(accounts.get(3).getLabel().toString().equals("x")); // Other accts sorted by label next assertTrue(accounts.get(4).getLabel().toString().equals("a")); assertTrue(accounts.get(5).getLabel().toString().equals("b")); } private static ComponentName makeQuickConnectionServiceComponentName() { return new ComponentName( "com.android.server.telecom.tests", Loading Loading
src/com/android/server/telecom/PhoneAccountRegistrar.java +52 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ import java.lang.SecurityException; import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; Loading Loading @@ -1089,6 +1090,52 @@ public class PhoneAccountRegistrar { } } private void sortPhoneAccounts() { if (mState.accounts.size() > 1) { // Sort the phone accounts using sort order: // 1) SIM accounts first, followed by non-sim accounts // 2) Sort order, with those specifying no sort order last. // 3) Label // Comparator to sort SIM subscriptions before non-sim subscriptions. Comparator<PhoneAccount> bySimCapability = (p1, p2) -> { if (p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && !p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { return -1; } else if (!p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) && p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { return 1; } else { return 0; } }; // Create a string comparator which will sort strings, placing nulls last. Comparator<String> nullSafeStringComparator = Comparator.nullsLast( String::compareTo); // Comparator which places PhoneAccounts with a specified sort order first, followed by // those with no sort order. Comparator<PhoneAccount> bySortOrder = (p1, p2) -> { String sort1 = p1.getExtras() == null ? null : p1.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null); String sort2 = p2.getExtras() == null ? null : p2.getExtras().getString(PhoneAccount.EXTRA_SORT_ORDER, null); return nullSafeStringComparator.compare(sort1, sort2); }; // Comparator which sorts PhoneAccounts by label. Comparator<PhoneAccount> byLabel = (p1, p2) -> { String s1 = p1.getLabel() == null ? null : p1.getLabel().toString(); String s2 = p2.getLabel() == null ? null : p2.getLabel().toString(); return nullSafeStringComparator.compare(s1, s2); }; // Sort the phone accounts. mState.accounts.sort(bySimCapability.thenComparing(bySortOrder.thenComparing(byLabel))); } } //////////////////////////////////////////////////////////////////////////////////////////////// // // State management Loading @@ -1115,6 +1162,7 @@ public class PhoneAccountRegistrar { private void write() { try { sortPhoneAccounts(); ByteArrayOutputStream os = new ByteArrayOutputStream(); XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(os, "utf-8"); Loading Loading @@ -1870,4 +1918,8 @@ public class PhoneAccountRegistrar { return null; } }; private String nullToEmpty(String str) { return str == null ? "" : str; } }
tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +187 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.util.Arrays; import java.util.List; import java.util.Set; import static org.mockito.Matchers.anyInt; Loading Loading @@ -577,6 +578,192 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { assertEquals(PhoneAccount.CAPABILITY_SELF_MANAGED, registeredAccount.getCapabilities()); } @MediumTest public void testSortSimFirst() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); PhoneAccount simAccount = new PhoneAccount.Builder( makeQuickAccountHandle(componentB, "2"), "2") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .setIsEnabled(true) .build(); PhoneAccount nonSimAccount = new PhoneAccount.Builder( makeQuickAccountHandle(componentA, "1"), "1") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .setIsEnabled(true) .build(); registerAndEnableAccount(nonSimAccount); registerAndEnableAccount(simAccount); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); assertTrue(accounts.get(0).getLabel().toString().equals("2")); assertTrue(accounts.get(1).getLabel().toString().equals("1")); } @MediumTest public void testSortBySortOrder() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); ComponentName componentC = new ComponentName("c", "c"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentC, Mockito.mock(IConnectionService.class)); PhoneAccount account1 = new PhoneAccount.Builder( makeQuickAccountHandle(componentA, "c"), "c") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "A")) .build(); PhoneAccount account2 = new PhoneAccount.Builder( makeQuickAccountHandle(componentB, "b"), "b") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "B")) .build(); PhoneAccount account3 = new PhoneAccount.Builder( makeQuickAccountHandle(componentC, "c"), "a") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); registerAndEnableAccount(account3); registerAndEnableAccount(account2); registerAndEnableAccount(account1); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); assertTrue(accounts.get(0).getLabel().toString().equals("c")); assertTrue(accounts.get(1).getLabel().toString().equals("b")); assertTrue(accounts.get(2).getLabel().toString().equals("a")); } @MediumTest public void testSortByLabel() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); ComponentName componentC = new ComponentName("c", "c"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentC, Mockito.mock(IConnectionService.class)); PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle(componentA, "c"), "c") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle(componentB, "b"), "b") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle(componentC, "a"), "a") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); registerAndEnableAccount(account1); registerAndEnableAccount(account2); registerAndEnableAccount(account3); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); assertTrue(accounts.get(0).getLabel().toString().equals("a")); assertTrue(accounts.get(1).getLabel().toString().equals("b")); assertTrue(accounts.get(2).getLabel().toString().equals("c")); } @MediumTest public void testSortAll() throws Exception { ComponentName componentA = new ComponentName("a", "a"); ComponentName componentB = new ComponentName("b", "b"); ComponentName componentC = new ComponentName("c", "c"); ComponentName componentW = new ComponentName("w", "w"); ComponentName componentX = new ComponentName("x", "x"); ComponentName componentY = new ComponentName("y", "y"); ComponentName componentZ = new ComponentName("z", "z"); mComponentContextFixture.addConnectionService(componentA, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentB, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentC, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentW, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentX, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentY, Mockito.mock(IConnectionService.class)); mComponentContextFixture.addConnectionService(componentZ, Mockito.mock(IConnectionService.class)); PhoneAccount account1 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "y"), "y") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "2")) .build(); PhoneAccount account2 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "z"), "z") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .setExtras(Bundle.forPair(PhoneAccount.EXTRA_SORT_ORDER, "1")) .build(); PhoneAccount account3 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "x"), "x") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .build(); PhoneAccount account4 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "w"), "w") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .build(); PhoneAccount account5 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "b"), "b") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); PhoneAccount account6 = new PhoneAccount.Builder(makeQuickAccountHandle( makeQuickConnectionServiceComponentName(), "c"), "a") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER) .build(); registerAndEnableAccount(account1); registerAndEnableAccount(account2); registerAndEnableAccount(account3); registerAndEnableAccount(account4); registerAndEnableAccount(account5); registerAndEnableAccount(account6); List<PhoneAccount> accounts = mRegistrar.getAllPhoneAccounts(Process.myUserHandle()); // Sim accts ordered by sort order first assertTrue(accounts.get(0).getLabel().toString().equals("z")); assertTrue(accounts.get(1).getLabel().toString().equals("y")); // Sim accts with no sort order next assertTrue(accounts.get(2).getLabel().toString().equals("w")); assertTrue(accounts.get(3).getLabel().toString().equals("x")); // Other accts sorted by label next assertTrue(accounts.get(4).getLabel().toString().equals("a")); assertTrue(accounts.get(5).getLabel().toString().equals("b")); } private static ComponentName makeQuickConnectionServiceComponentName() { return new ComponentName( "com.android.server.telecom.tests", Loading