Vectors are now exposed as ArrayList<T> in the Java backend even for arguments

and return values to/from methods, they already were inside structures.
In addition vectors of arrays are now properly marshalled when used as arguments
or results to/from methods.

Bug: 32237331, 32180328
Test: hidl_test_java
Change-Id: Ie24f11668f22fc2c31fb7d8e8da534f1c970f58f
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 71d17bf..f8ddc06 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -451,9 +451,9 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    out << "public static final "
+    out << "public static final ArrayList<"
         << localName()
-        << "[] readVectorFromParcel(HwParcel parcel) {\n";
+        << "> readVectorFromParcel(HwParcel parcel) {\n";
     out.indent();
 
     out << "ArrayList<"
@@ -472,9 +472,7 @@
             "0",
             true /* isReader */);
 
-    out << "\nreturn _hidl_vec.toArray(new "
-        << localName()
-        << "[_hidl_vec.size()]);\n";
+    out << "\nreturn _hidl_vec;\n";
 
     out.unindent();
     out << "}\n\n";
@@ -535,15 +533,11 @@
     out << "public static final void writeVectorToParcel(\n";
     out.indent();
     out.indent();
-    out << "HwParcel parcel, "
+    out << "HwParcel parcel, ArrayList<"
         << localName()
-        << "[] _hidl_array) {\n";
+        << "> _hidl_vec) {\n";
     out.unindent();
 
-    out << "ArrayList<"
-        << localName()
-        << "> _hidl_vec = new ArrayList(Arrays.asList(_hidl_array));\n";
-
     out << "HwBlob _hidl_blob = new HwBlob(24 /* sizeof(hidl_vec<T>) */);\n";
 
     VectorType::EmitJavaFieldReaderWriterForElementType(
diff --git a/VectorType.cpp b/VectorType.cpp
index f656281..d7eb581 100644
--- a/VectorType.cpp
+++ b/VectorType.cpp
@@ -59,10 +59,18 @@
 
 std::string VectorType::getJavaType(
         std::string *extra, bool /* forInitializer */) const {
-    *extra = "[]";
+    extra->clear();
 
     std::string elementExtra;
-    return mElementType->getJavaType(&elementExtra) + elementExtra;
+    std::string elementJavaType = mElementType->getJavaType(&elementExtra);
+
+    CHECK(mElementType->isArray() || elementExtra.empty());
+
+    return "ArrayList<"
+        + (mElementType->isArray()
+                ? elementJavaType : mElementType->getJavaWrapperType())
+        + elementExtra
+        + ">";
 }
 
 std::string VectorType::getVtsType() const {
@@ -341,6 +349,50 @@
         return;
     }
 
+    if (mElementType->isArray()) {
+        if (isReader) {
+            std::string extra;
+            out << " new "
+                << getJavaType(&extra, false /* forInitializer */)
+                << "();\n";
+        }
+
+        out << "{\n";
+        out.indent();
+
+        out << "HwBlob _hidl_blob = ";
+
+        if (isReader) {
+            out << parcelObj
+                << ".readBuffer();\n";
+        } else {
+            size_t align, size;
+            getAlignmentAndSize(&align, &size);
+
+            out << "new HwBlob("
+                << size
+                << " /* size */);\n";
+        }
+
+        emitJavaFieldReaderWriter(
+                out,
+                0 /* depth */,
+                parcelObj,
+                "_hidl_blob",
+                argName,
+                "0 /* offset */",
+                isReader);
+
+        if (!isReader) {
+            out << parcelObj << ".writeBuffer(_hidl_blob);\n";
+        };
+
+        out.unindent();
+        out << "}\n";
+
+        return;
+    }
+
     emitJavaReaderWriterWithSuffix(
             out,
             parcelObj,
@@ -353,19 +405,15 @@
 void VectorType::emitJavaFieldInitializer(
         Formatter &out, const std::string &fieldName) const {
     std::string extra;
-    mElementType->getJavaType(&extra);
+    std::string javaType = getJavaType(&extra, false /* forInitializer */);
 
-    const std::string wrapperType = mElementType->getJavaWrapperType();
-
-    out << "final ArrayList<"
-        << wrapperType
-        << extra
-        << "> "
+    out << "final "
+        << javaType
+        << " "
         << fieldName
-        << " = new ArrayList<"
-        << wrapperType
-        << extra
-        << ">();\n";
+        << " = new "
+        << javaType
+        << "();\n";
 }
 
 void VectorType::emitJavaFieldReaderWriter(
@@ -450,16 +498,8 @@
                 iteratorName + " * " + std::to_string(elementSize),
                 true /* isReader */);
 
-        out << fieldName;
-
-        if (elementType->isArray()
-                && static_cast<const ArrayType *>(
-                    elementType)->getElementType()->resolveToScalarType()
-                        != nullptr) {
-            out << ".add(HwBlob.wrapArray(_hidl_vec_element));\n";
-        } else {
-            out << ".add(_hidl_vec_element);\n";
-        }
+        out << fieldName
+            << ".add(_hidl_vec_element);\n";
 
         out.unindent();
 
@@ -577,6 +617,10 @@
         return static_cast<ArrayType *>(mElementType)->countDimensions() == 1;
     }
 
+    if (mElementType->isVector()) {
+        return false;
+    }
+
     return true;
 }
 
diff --git a/generateJava.cpp b/generateJava.cpp
index 1e0c478..2b14cf0 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -108,7 +108,8 @@
                 "ERROR: This interface is not Java compatible. The Java backend"
                 " does NOT support union types nor native handles. "
                 "In addition, vectors of arrays are limited to at most "
-                "one-dimensional arrays.\n");
+                "one-dimensional arrays and vectors of vectors are not "
+                "supported.\n");
 
         return UNKNOWN_ERROR;
     }
diff --git a/test/java_test/hidl_test_java_native.cpp b/test/java_test/hidl_test_java_native.cpp
index 5c95948..56410b4 100644
--- a/test/java_test/hidl_test_java_native.cpp
+++ b/test/java_test/hidl_test_java_native.cpp
@@ -52,6 +52,10 @@
             const IBase::VectorOfArray &in,
             someMethodWithVectorOfArray_cb _hidl_cb) override;
 
+    Return<void> someMethodTakingAVectorOfArray(
+            const hidl_vec<hidl_array<uint8_t, 6> > &in,
+            someMethodTakingAVectorOfArray_cb _hidl_cb) override;
+
     Return<void> transpose(
             const IBase::StringMatrix5x3 &in,
             transpose_cb _hidl_cb) override;
@@ -118,6 +122,12 @@
 static std::string to_string(const IBase::StringMatrix5x3 &M);
 static std::string to_string(const IBase::StringMatrix3x5 &M);
 
+template<typename T, size_t SIZE>
+static std::string to_string(const hidl_array<T, SIZE> &array);
+
+template<size_t SIZE>
+static std::string to_string(const hidl_array<uint8_t, SIZE> &array);
+
 template<typename T>
 static std::string to_string(const hidl_vec<T> &vec) {
     std::string out;
@@ -148,6 +158,23 @@
     return out;
 }
 
+template<size_t SIZE>
+static std::string to_string(const hidl_array<uint8_t, SIZE> &array) {
+    std::string out;
+    for (size_t i = 0; i < SIZE; ++i) {
+        if (i > 0) {
+            out += ":";
+        }
+
+        char tmp[3];
+        sprintf(tmp, "%02x", array[i]);
+
+        out += tmp;
+    }
+
+    return out;
+}
+
 template<typename T, size_t SIZE1, size_t SIZE2>
 static std::string to_string(const hidl_array<T, SIZE1, SIZE2> &array) {
     std::string out;
@@ -296,6 +323,26 @@
     return Void();
 }
 
+Return<void> Baz::someMethodTakingAVectorOfArray(
+        const hidl_vec<hidl_array<uint8_t, 6> > &in,
+        someMethodTakingAVectorOfArray_cb _hidl_cb) {
+    LOG(INFO) << "Baz::someMethodTakingAVectorOfArray "
+              << to_string(in);
+
+    const size_t n = in.size();
+
+    hidl_vec<hidl_array<uint8_t, 6> > out;
+    out.resize(n);
+
+    for (size_t i = 0; i < n; ++i) {
+        out[i] = in[n - 1 - i];
+    }
+
+    _hidl_cb(out);
+
+    return Void();
+}
+
 Return<void> Baz::transpose(
         const IBase::StringMatrix5x3 &in, transpose_cb _hidl_cb) {
     LOG(INFO) << "Baz::transpose " << to_string(in);
@@ -678,6 +725,27 @@
                 }));
 }
 
+TEST_F(HidlTest, BazSomeMethodTakingAVectorOfArray) {
+    hidl_vec<hidl_array<uint8_t, 6> > in;
+    in.resize(3);
+
+    size_t k = 0;
+    for (size_t i = 0; i < in.size(); ++i) {
+        for (size_t j = 0; j < 6; ++j, ++k) {
+            in[i][j] = k;
+        }
+    }
+
+    EXPECT_OK(
+            baz->someMethodTakingAVectorOfArray(
+                in,
+                [&](const auto &out) {
+                    EXPECT_EQ(
+                        to_string(out),
+                        "[0c:0d:0e:0f:10:11, 06:07:08:09:0a:0b, 00:01:02:03:04:05]");
+                }));
+}
+
 static std::string numberToEnglish(int x) {
     static const char *const kDigits[] = {
         "zero",
diff --git a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
index 17bef99..efb055c 100644
--- a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
+++ b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
@@ -93,6 +93,76 @@
         return builder.toString();
     }
 
+    public static String fooVecToString(ArrayList<IBase.Foo> vec) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        for (int i = 0; i < vec.size(); ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(vec.get(i)));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    public static String macAddressVecToString(ArrayList<byte[]> vec) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        for (int i = 0; i < vec.size(); ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(vec.get(i)));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    public static String booleanVecToString(ArrayList<Boolean> vec) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        for (int i = 0; i < vec.size(); ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(vec.get(i)));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    public static String integerVecToString(ArrayList<Integer> vec) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        for (int i = 0; i < vec.size(); ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(vec.get(i)));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
+    public static String stringVecToString(ArrayList<String> vec) {
+        StringBuilder builder = new StringBuilder();
+        builder.append("[");
+        for (int i = 0; i < vec.size(); ++i) {
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(toString(vec.get(i)));
+        }
+        builder.append("]");
+
+        return builder.toString();
+    }
+
     public static String toString(IBase.Foo[] array) {
         StringBuilder builder = new StringBuilder();
         builder.append("[");
@@ -163,6 +233,23 @@
         return builder.toString();
     }
 
+    public static String toString(byte[] val) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < val.length; ++i) {
+            if (i > 0) {
+                builder.append(":");
+            }
+
+            byte b = val[i];
+            if (b < 16) {
+                builder.append("0");
+            }
+            builder.append(Integer.toHexString(b));
+        }
+
+        return builder.toString();
+    }
+
     public static String toString(boolean x) {
         return x ? "true" : "false";
     }
@@ -211,7 +298,7 @@
                 out.append(", ");
             }
 
-            Byte[] address = vec.addresses.get(i);
+            byte[] address = vec.addresses.get(i);
 
             for (int j = 0; j < 6; ++j) {
                 if (j > 0) {
@@ -399,7 +486,7 @@
         }
 
         {
-            IBase.Foo[] inputArray = new IBase.Foo[2];
+            ArrayList<IBase.Foo> inputVec = new ArrayList<IBase.Foo>();
 
             IBase.Foo foo = new IBase.Foo();
             foo.x = 1;
@@ -414,7 +501,7 @@
             foo.y.z = 3.14f;
             foo.y.s = "Lorem ipsum...";
 
-            inputArray[0] = foo;
+            inputVec.add(foo);
 
             foo = new IBase.Foo();
             foo.x = 2;
@@ -429,11 +516,12 @@
             foo.y.z = 1.1414f;
             foo.y.s = "Et tu brute?";
 
-            inputArray[1] = foo;
+            inputVec.add(foo);
 
-            IBase.Foo[] outputArray = proxy.someMethodWithFooVectors(inputArray);
+            ArrayList<IBase.Foo> outputVec =
+                proxy.someMethodWithFooVectors(inputVec);
 
-            Expect(toString(outputArray),
+            Expect(fooVecToString(outputVec),
                    "[Foo(x = 2, " +
                         "y = Bar(z = 1.1414, s = 'Et tu brute?'), " +
                         "aaa = [Bar(z = 2.0, s = 'Lorem ipsum 0'), " +
@@ -453,7 +541,7 @@
 
             int k = 0;
             for (int i = 0; i < 3; ++i) {
-                Byte[] mac = new Byte[6];
+                byte[] mac = new byte[6];
                 for (int j = 0; j < 6; ++j, ++k) {
                     mac[j] = (byte)k;
                 }
@@ -471,6 +559,25 @@
         }
 
         {
+            ArrayList<byte[]> in = new ArrayList<byte[]>();
+
+            int k = 0;
+            for (int i = 0; i < 3; ++i) {
+                byte[] mac = new byte[6];
+                for (int j = 0; j < 6; ++j, ++k) {
+                    mac[j] = (byte)k;
+                }
+
+                in.add(mac);
+            }
+
+            ArrayList<byte[]> out = proxy.someMethodTakingAVectorOfArray(in);
+
+            Expect(macAddressVecToString(out),
+                   "[0c:0d:0e:0f:10:11, 06:07:08:09:0a:0b, 00:01:02:03:04:05]");
+        }
+
+        {
             IBase.StringMatrix5x3 in = new IBase.StringMatrix5x3();
             for (int i = 0; i < 5; ++i) {
                 for (int j = 0; j < 3; ++j) {
@@ -517,7 +624,12 @@
             Expect(toString(proxy.someBoolArrayMethod(someBoolArray)),
                    "[false, true, false, true]");
 
-            Expect(toString(proxy.someBoolVectorMethod(someBoolArray)),
+            ArrayList<Boolean> someBoolVec = new ArrayList<Boolean>();
+            someBoolVec.add(true);
+            someBoolVec.add(false);
+            someBoolVec.add(true);
+
+            Expect(booleanVecToString(proxy.someBoolVectorMethod(someBoolVec)),
                    "[false, true, false]");
         }
 
@@ -527,16 +639,18 @@
         Expect(toString(proxy.doQuiteABit(1, 2L, 3.0f, 4.0)), "666.5");
 
         {
-            int[] param = new int[15];
-            for (int i = 0; i < param.length; ++i) {
-                param[i] = i;
+            int[] paramArray = new int[15];
+            ArrayList<Integer> paramVec = new ArrayList<Integer>();
+            for (int i = 0; i < paramArray.length; ++i) {
+                paramArray[i] = i;
+                paramVec.add(i);
             }
 
-            Expect(toString(proxy.doSomethingElse(param)),
+            Expect(toString(proxy.doSomethingElse(paramArray)),
                    "[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, " +
                    "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1, 2]");
 
-            Expect(toString(proxy.mapThisVector(param)),
+            Expect(integerVecToString(proxy.mapThisVector(paramVec)),
                    "[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28]");
         }
 
@@ -550,15 +664,20 @@
         Expect(toString(proxy.useAnEnum(IBaz.SomeEnum.goober)), "-64");
 
         {
-            String[] strings = new String[3];
-            strings[0] = "one";
-            strings[1] = "two";
-            strings[2] = "three";
+            String[] stringArray = new String[3];
+            stringArray[0] = "one";
+            stringArray[1] = "two";
+            stringArray[2] = "three";
 
-            Expect(toString(proxy.haveSomeStrings(strings)),
+            Expect(toString(proxy.haveSomeStrings(stringArray)),
                    "['Hello', 'World']");
 
-            Expect(toString(proxy.haveAStringVec(strings)),
+            ArrayList<String> stringVec = new ArrayList<String>();
+            stringVec.add("one");
+            stringVec.add("two");
+            stringVec.add("three");
+
+            Expect(stringVecToString(proxy.haveAStringVec(stringVec)),
                    "['Hello', 'World']");
         }
 
@@ -594,12 +713,13 @@
             return fooOutput;
         }
 
-        public IBase.Foo[] someMethodWithFooVectors(IBase.Foo[] fooInput) {
-            Log.d(TAG, "Baz someMethodWithFooVectors " + HidlTestJava.toString(fooInput));
+        public ArrayList<IBase.Foo> someMethodWithFooVectors(
+                ArrayList<IBase.Foo> fooInput) {
+            Log.d(TAG, "Baz someMethodWithFooVectors " + HidlTestJava.fooVecToString(fooInput));
 
-            IBase.Foo[] fooOutput = new IBase.Foo[2];
-            fooOutput[0] = fooInput[1];
-            fooOutput[1] = fooInput[0];
+            ArrayList<IBase.Foo> fooOutput = new ArrayList<IBase.Foo>();
+            fooOutput.add(fooInput.get(1));
+            fooOutput.add(fooInput.get(0));
 
             return fooOutput;
         }
@@ -617,6 +737,19 @@
             return out;
         }
 
+        public ArrayList<byte[/* 6 */]> someMethodTakingAVectorOfArray(
+                ArrayList<byte[/* 6 */]> in) {
+            Log.d(TAG, "Baz someMethodTakingAVectorOfArray");
+
+            int n = in.size();
+            ArrayList<byte[]> out = new ArrayList<byte[]>();
+            for (int i = 0; i < n; ++i) {
+                out.add(in.get(n - i - 1));
+            }
+
+            return out;
+        }
+
         public IBase.StringMatrix3x5 transpose(IBase.StringMatrix5x3 in) {
             Log.d(TAG, "Baz transpose " + HidlTestJava.toString(in));
 
@@ -662,12 +795,12 @@
             return out;
         }
 
-        public boolean[] someBoolVectorMethod(boolean[] x) {
-            Log.d(TAG, "Baz someBoolVectorMethod(" + HidlTestJava.toString(x) + ")");
+        public ArrayList<Boolean> someBoolVectorMethod(ArrayList<Boolean> x) {
+            Log.d(TAG, "Baz someBoolVectorMethod(" + HidlTestJava.booleanVecToString(x) + ")");
 
-            boolean[] out = new boolean[x.length];
-            for (int i = 0; i < x.length; ++i) {
-                out[i] = !x[i];
+            ArrayList<Boolean> out = new ArrayList<Boolean>();
+            for (int i = 0; i < x.size(); ++i) {
+                out.add(!x.get(i));
             }
 
             return out;
@@ -706,14 +839,16 @@
             return "Hello, world!";
         }
 
-        public int[] mapThisVector(int[] param) {
-            Log.d(TAG, "mapThisVector " + HidlTestJava.toString(param));
+        public ArrayList<Integer> mapThisVector(ArrayList<Integer> param) {
+            Log.d(TAG, "mapThisVector " + HidlTestJava.integerVecToString(param));
 
-            for (int i = 0; i < param.length; ++i) {
-                param[i] *= 2;
+            ArrayList<Integer> out = new ArrayList<Integer>();
+
+            for (int i = 0; i < param.size(); ++i) {
+                out.add(2 * param.get(i));
             }
 
-            return param;
+            return out;
         }
 
         class BazCallback extends IBazCallback.Stub {
@@ -745,15 +880,15 @@
             return result;
         }
 
-        public String[] haveAStringVec(String[] vector) {
+        public ArrayList<String> haveAStringVec(ArrayList<String> vector) {
             Log.d(TAG, "haveAStringVec ["
-                        + "\"" + vector[0] + "\", "
-                        + "\"" + vector[1] + "\", "
-                        + "\"" + vector[2] + "\"]");
+                        + "\"" + vector.get(0) + "\", "
+                        + "\"" + vector.get(1) + "\", "
+                        + "\"" + vector.get(2) + "\"]");
 
-            String[] result = new String[2];
-            result[0] = "Hello";
-            result[1] = "World";
+            ArrayList<String> result = new ArrayList<String>();
+            result.add("Hello");
+            result.add("World");
 
             return result;
         }