diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 1fd04109ae455..d192ad932a623 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -39,8 +39,7 @@ import java.util.Set; import java.util.function.IntFunction; /** - * ArrayUtils contains some methods that you can call to find out - * the most efficient increments by which to grow arrays. + * Static utility methods for arrays that aren't already included in {@link java.util.Arrays}. */ public class ArrayUtils { private static final int CACHE_SIZE = 73; @@ -341,15 +340,16 @@ public class ArrayUtils { } /** - * Combine multiple arrays into a single array. + * Returns the concatenation of the given arrays. Only works for object arrays, not for + * primitive arrays. See {@link #concat(byte[]...)} for a variant that works on byte arrays. * * @param kind The class of the array elements - * @param arrays The arrays to combine + * @param arrays The arrays to concatenate. Null arrays are treated as empty. * @param The class of the array elements (inferred from kind). * @return A single array containing all the elements of the parameter arrays. */ @SuppressWarnings("unchecked") - public static @NonNull T[] concatElements(Class kind, @Nullable T[]... arrays) { + public static @NonNull T[] concat(Class kind, @Nullable T[]... arrays) { if (arrays == null || arrays.length == 0) { return createEmptyArray(kind); } @@ -390,6 +390,29 @@ public class ArrayUtils { return (T[]) Array.newInstance(kind, 0); } + /** + * Returns the concatenation of the given byte arrays. Null arrays are treated as empty. + */ + public static @NonNull byte[] concat(@Nullable byte[]... arrays) { + if (arrays == null) { + return new byte[0]; + } + int totalLength = 0; + for (byte[] a : arrays) { + if (a != null) { + totalLength += a.length; + } + } + final byte[] result = new byte[totalLength]; + int pos = 0; + for (byte[] a : arrays) { + if (a != null) { + System.arraycopy(a, 0, result, pos, a.length); + pos += a.length; + } + } + return result; + } /** * Adds value to given array if not already present, providing set-like diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java index cb30b3fe5b826..c66a743d8f530 100644 --- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java @@ -16,8 +16,6 @@ package com.android.internal.util; -import static com.android.internal.util.ArrayUtils.concatElements; - import static org.junit.Assert.assertArrayEquals; import junit.framework.TestCase; @@ -156,61 +154,107 @@ public class ArrayUtilsTest extends TestCase { ArrayUtils.removeLong(new long[] { 1, 2, 3, 1 }, 1)); } - public void testConcatEmpty() throws Exception { - assertArrayEquals(new Long[] {}, - concatElements(Long.class, null, null)); - assertArrayEquals(new Long[] {}, - concatElements(Long.class, new Long[] {}, null)); - assertArrayEquals(new Long[] {}, - concatElements(Long.class, null, new Long[] {})); - assertArrayEquals(new Long[] {}, - concatElements(Long.class, new Long[] {}, new Long[] {})); + public void testConcat_zeroObjectArrays() { + // empty varargs array + assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class)); + // null varargs array + assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[][]) null)); } - public void testconcatElements() throws Exception { + public void testConcat_oneObjectArray() { + assertArrayEquals(new String[] { "1", "2" }, + ArrayUtils.concat(String.class, new String[] { "1", "2" })); + } + + public void testConcat_oneEmptyObjectArray() { + assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[]) null)); + assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, new String[] {})); + } + + public void testConcat_twoObjectArrays() { assertArrayEquals(new Long[] { 1L }, - concatElements(Long.class, new Long[] { 1L }, new Long[] {})); + ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] {})); assertArrayEquals(new Long[] { 1L }, - concatElements(Long.class, new Long[] {}, new Long[] { 1L })); + ArrayUtils.concat(Long.class, new Long[] {}, new Long[] { 1L })); assertArrayEquals(new Long[] { 1L, 2L }, - concatElements(Long.class, new Long[] { 1L }, new Long[] { 2L })); + ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] { 2L })); assertArrayEquals(new Long[] { 1L, 2L, 3L, 4L }, - concatElements(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L })); + ArrayUtils.concat(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L })); } - public void testConcatElements_threeWay() { + public void testConcat_twoEmptyObjectArrays() { + assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, null)); + assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, new Long[] {}, null)); + assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, new Long[] {})); + assertArrayEquals(new Long[] {}, + ArrayUtils.concat(Long.class, new Long[] {}, new Long[] {})); + } + + public void testConcat_threeObjectArrays() { String[] array1 = { "1", "2" }; String[] array2 = { "3", "4" }; String[] array3 = { "5", "6" }; - String[] expectation = {"1", "2", "3", "4", "5", "6"}; + String[] expectation = { "1", "2", "3", "4", "5", "6" }; - String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3); - assertArrayEquals(expectation, concatResult); + assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3)); } - - public void testConcatElements_threeWayWithNull() { + public void testConcat_threeObjectArraysWithNull() { String[] array1 = { "1", "2" }; String[] array2 = null; String[] array3 = { "5", "6" }; - String[] expectation = {"1", "2", "5", "6"}; + String[] expectation = { "1", "2", "5", "6" }; - String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3); - assertArrayEquals(expectation, concatResult); + assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3)); } - public void testConcatElements_zeroElements() { - String[] expectation = new String[0]; - - String[] concatResult = ArrayUtils.concatElements(String.class); - assertArrayEquals(expectation, concatResult); + public void testConcat_zeroByteArrays() { + // empty varargs array + assertArrayEquals(new byte[] {}, ArrayUtils.concat()); + // null varargs array + assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[][]) null)); } - public void testConcatElements_oneNullElement() { - String[] expectation = new String[0]; - - String[] concatResult = ArrayUtils.concatElements(String.class, null); - assertArrayEquals(expectation, concatResult); + public void testConcat_oneByteArray() { + assertArrayEquals(new byte[] { 1, 2 }, ArrayUtils.concat(new byte[] { 1, 2 })); } + public void testConcat_oneEmptyByteArray() { + assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null)); + assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {})); + } + + public void testConcat_twoByteArrays() { + assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] { 1 }, new byte[] {})); + assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] {}, new byte[] { 1 })); + assertArrayEquals(new byte[] { 1, 2 }, + ArrayUtils.concat(new byte[] { 1 }, new byte[] { 2 })); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, + ArrayUtils.concat(new byte[] { 1, 2 }, new byte[] { 3, 4 })); + } + + public void testConcat_twoEmptyByteArrays() { + assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, null)); + assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, null)); + assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, new byte[] {})); + assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, new byte[] {})); + } + + public void testConcat_threeByteArrays() { + byte[] array1 = { 1, 2 }; + byte[] array2 = { 3, 4 }; + byte[] array3 = { 5, 6 }; + byte[] expectation = { 1, 2, 3, 4, 5, 6 }; + + assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3)); + } + + public void testConcat_threeByteArraysWithNull() { + byte[] array1 = { 1, 2 }; + byte[] array2 = null; + byte[] array3 = { 5, 6 }; + byte[] expectation = { 1, 2, 5, 6 }; + + assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3)); + } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index d3afccc9dcb1a..6aa08f22c3336 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -875,16 +875,16 @@ public class SettingsBackupAgent extends BackupAgentHelper { String[] whitelist; Map validators = null; if (contentUri.equals(Settings.Secure.CONTENT_URI)) { - whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP, + whitelist = ArrayUtils.concat(String.class, SecureSettings.SETTINGS_TO_BACKUP, Settings.Secure.LEGACY_RESTORE_SETTINGS, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); validators = SecureSettingsValidators.VALIDATORS; } else if (contentUri.equals(Settings.System.CONTENT_URI)) { - whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP, + whitelist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP, Settings.System.LEGACY_RESTORE_SETTINGS); validators = SystemSettingsValidators.VALIDATORS; } else if (contentUri.equals(Settings.Global.CONTENT_URI)) { - whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP, + whitelist = ArrayUtils.concat(String.class, GlobalSettings.SETTINGS_TO_BACKUP, Settings.Global.LEGACY_RESTORE_SETTINGS); validators = GlobalSettingsValidators.VALIDATORS; } else {