From 96abd9452d4591256353ccd2ec670e61d908e310 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 29 Jul 2022 17:57:51 +0000 Subject: [PATCH 1/2] ArrayUtils: rename concatElements() to concat() concatElements() was probably named as it is to be like addElement() and removeElement(). However, that doesn't really make sense because the parameters of concatElements() are only arrays, not array elements. Rename it to concat(), as that is just as clear and follows the example of Guava's ObjectArrays.concat(). And I'd like to add a variant that operates on byte arrays, and would like to call it concat(). Also clean up the tests a bit. Test: atest com.android.internal.util.ArrayUtilsTest BYPASS_INCLUSIVE_LANGUAGE_REASON=existing code in SettingsBackupAgent Change-Id: I21e958d3d7b3366ec724e757ac4ccc50b36abee1 Merged-In: I21e958d3d7b3366ec724e757ac4ccc50b36abee1 (cherry picked from commit 1174b2fd681164499fb12082743e391e4c99994c) --- .../com/android/internal/util/ArrayUtils.java | 2 +- .../android/internal/util/ArrayUtilsTest.java | 74 +++++++++---------- .../settings/SettingsBackupAgent.java | 6 +- 3 files changed, 38 insertions(+), 44 deletions(-) diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 1fd04109ae455..19228bc290e5a 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -349,7 +349,7 @@ public class ArrayUtils { * @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); } 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..61f06bd515174 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,57 @@ 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 testConcatElements_oneNullElement() { - String[] expectation = new String[0]; - - String[] concatResult = ArrayUtils.concatElements(String.class, null); - assertArrayEquals(expectation, concatResult); - } - } 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 { From 43510a529117b03de3dd983c1baaa241d6cf2b57 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 29 Jul 2022 17:57:52 +0000 Subject: [PATCH 2/2] ArrayUtils: add concat() for byte arrays Concatenating byte arrays is a common thing that needs to be done, especially in the locksettings package, so add a utility method for it. Test: atest com.android.internal.util.ArrayUtilsTest Merged-In: I099c83155456139729f4d73f5873a172590ee7e9 Change-Id: I099c83155456139729f4d73f5873a172590ee7e9 (cherry picked from commit 4dd9540f0e1d157b233a4c0d27c7f350b93f18c0) --- .../com/android/internal/util/ArrayUtils.java | 31 ++++++++++-- .../android/internal/util/ArrayUtilsTest.java | 50 +++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 19228bc290e5a..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,10 +340,11 @@ 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. */ @@ -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 61f06bd515174..c66a743d8f530 100644 --- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java @@ -207,4 +207,54 @@ public class ArrayUtilsTest extends TestCase { assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3)); } + + public void testConcat_zeroByteArrays() { + // empty varargs array + assertArrayEquals(new byte[] {}, ArrayUtils.concat()); + // null varargs array + assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[][]) null)); + } + + 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)); + } }