Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 183d6db2 authored by Utkarsh Nigam's avatar Utkarsh Nigam
Browse files

Update shell command to handle return types other than serializable

types

This now prints androidAppFunctionReturnValue as well but I think that's
fine for now, we can take a look at handling all output types later.

Bug: NA
Test: Verified manually
Flag: EXEMPT shell command
Change-Id: Iaa3f8a268065ec10409c27b0cecf8dea3803e08c
parent a5a53920
Loading
Loading
Loading
Loading
+6 −15
Original line number Diff line number Diff line
@@ -20,10 +20,10 @@ import static android.app.appfunctions.AppFunctionManager.ACCESS_FLAG_MASK_OTHER
import static android.app.appfunctions.AppFunctionManager.ACCESS_FLAG_OTHER_DENIED;
import static android.app.appfunctions.AppFunctionManager.ACCESS_FLAG_OTHER_GRANTED;

import static com.android.server.appfunctions.AppSearchDataJsonConverter.convertGenericDocumentsToJsonArray;
import static com.android.server.appfunctions.AppSearchDataJsonConverter.convertGenericDocumentToJson;
import static com.android.server.appfunctions.AppSearchDataJsonConverter.convertJsonToGenericDocument;
import static com.android.server.appfunctions.AppSearchDataJsonConverter.searchResultToJsonObject;
import static com.android.server.appfunctions.AppSearchDataYamlConverter.convertGenericDocumentsToYaml;
import static com.android.server.appfunctions.AppSearchDataYamlConverter.convertGenericDocumentToYaml;

import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -449,29 +449,20 @@ public class AppFunctionManagerServiceShellCommand extends ShellCommand {
                    @Override
                    public void onSuccess(ExecuteAppFunctionResponse response) {
                        try {
                            GenericDocument[] functionReturn =
                                    response.getResultDocument()
                                            .getPropertyDocumentArray(
                                                    ExecuteAppFunctionResponse
                                                            .PROPERTY_RETURN_VALUE);
                            if (functionReturn == null || functionReturn.length == 0) {
                                pw.println(new JSONObject());
                                return;
                            }
                            // HACK: GenericDocument doesn't tell whether a property is singular
                            // or repeated. We always assume the return is an array here.
                            if (finalBriefYaml) {
                                String functionReturnYaml =
                                        convertGenericDocumentsToYaml(
                                            functionReturn,
                                        convertGenericDocumentToYaml(
                                                response.getResultDocument(),
                                            /*keepEmptyValues=*/ false,
                                            /*keepNullValues=*/ false,
                                            /*keepGenericDocumentProperties=*/ false
                                        );
                                pw.println(functionReturnYaml);
                            } else {
                                JSONArray functionReturnJson =
                                    convertGenericDocumentsToJsonArray(functionReturn);
                                JSONObject functionReturnJson =
                                        convertGenericDocumentToJson(response.getResultDocument());
                                pw.println(functionReturnJson.toString(/*indentSpace=*/ 2));
                            }
                        } catch (JSONException e) {
+0 −17
Original line number Diff line number Diff line
@@ -115,23 +115,6 @@ public class AppSearchDataJsonConverter {
        return builder.build();
    }

    /**
     * Converts an array of {@link GenericDocument} objects into a {@link JSONArray}.
     *
     * @param documents The array of {@link GenericDocument} to convert.
     * @return A {@link JSONArray} where each element is the JSON representation of a {@link
     *     GenericDocument}.
     * @throws JSONException if there is an error during JSON conversion.
     */
    public static JSONArray convertGenericDocumentsToJsonArray(GenericDocument[] documents)
            throws JSONException {
        JSONArray jsonArray = new JSONArray();
        for (GenericDocument doc : documents) {
            jsonArray.put(convertGenericDocumentToJson(doc));
        }
        return jsonArray;
    }

    /**
     * Converts a single {@link GenericDocument} into a {@link JSONObject}.
     *
+8 −13
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ public class AppSearchDataYamlConverter {
     * Converts an array of {@link GenericDocument} objects into a YAML string. This method provides
     * options to control the output.
     *
     * @param documents The array of {@link GenericDocument} to convert.
     * @param document The {@link GenericDocument} to convert.
     * @param keepEmptyValues If false, properties with empty values (empty strings, empty array)
     * will be excluded.
     * @param keepNullValues If false, properties with null values will be excluded.
@@ -44,22 +44,17 @@ public class AppSearchDataYamlConverter {
     *     not be included in the output.
     * @return A YAML string representing a list of documents.
     */
    public static String convertGenericDocumentsToYaml(
            GenericDocument[] documents,
    public static String convertGenericDocumentToYaml(
            GenericDocument document,
            boolean keepEmptyValues,
            boolean keepNullValues,
            boolean keepGenericDocumentProperties) {
        List<Map<String, Object>> list = new ArrayList<>();
        for (GenericDocument doc : documents) {
            list.add(
                    genericDocumentToMap(
                        doc,
        return MinimalYamlGenerator.dump(genericDocumentToMap(
                document,
                keepEmptyValues,
                keepNullValues,
                keepGenericDocumentProperties));
    }
        return MinimalYamlGenerator.dump(list);
    }

    /**
     * Recursively converts a {@link GenericDocument} into a {@link Map}, filtering based on flags.
+2 −6
Original line number Diff line number Diff line
@@ -204,12 +204,8 @@ class AppSearchDataJsonConverterTest {
            .setPropertyString("prop", "val2")
            .build()

        val jsonArray =
            AppSearchDataJsonConverter.convertGenericDocumentsToJsonArray(arrayOf(doc1, doc2))

        assertThat(jsonArray.length()).isEqualTo(2)
        assertThat(jsonArray.getJSONObject(0).getJSONArray("prop").getString(0)).isEqualTo("val1")
        assertThat(jsonArray.getJSONObject(1).getJSONArray("prop").getString(0)).isEqualTo("val2")
        assertThat(AppSearchDataJsonConverter.convertGenericDocumentToJson(doc1).getJSONArray("prop").getString(0)).isEqualTo("val1")
        assertThat(AppSearchDataJsonConverter.convertGenericDocumentToJson(doc2).getJSONArray("prop").getString(0)).isEqualTo("val2")
    }

    @Test
+24 −72
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ import org.junit.runners.JUnit4
class AppSearchDataYamlConverterTest {

    @Test
    fun convertGenericDocumentsToYaml_withScalarTypes_succeeds() {
    fun convertGenericDocumentToYaml_withScalarTypes_succeeds() {
        val doc = GenericDocument.Builder<GenericDocument.Builder<*>>("ns1", "doc1", "TestSchema")
          .setPropertyString("stringProp", "hello world")
          .setPropertyLong("longProp", 123L)
@@ -35,15 +35,15 @@ class AppSearchDataYamlConverterTest {
          .setCreationTimestampMillis(1000L)
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(doc),
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentToYaml(
          doc,
          /* keepEmptyValues= */ true,
          /* keepNullValues= */ true,
          /* keepGenericDocumentProperties= */ true
        )

        val expectedYaml = """
                - id: doc1
                  id: doc1
                  namespace: ns1
                  schemaType: TestSchema
                  creationTimestampMillis: 1000
@@ -58,7 +58,7 @@ class AppSearchDataYamlConverterTest {
    }

    @Test
    fun convertGenericDocumentsToYaml_withoutDefaultValues_filtersProperties() {
    fun convertGenericDocumentToYaml_withoutDefaultValues_filtersProperties() {
        val doc = GenericDocument.Builder<GenericDocument.Builder<*>>("ns2", "doc2", "FilterSchema")
          .setPropertyString("emptyString", "")
          .setPropertyString("realString", "value")
@@ -66,15 +66,15 @@ class AppSearchDataYamlConverterTest {
          .setPropertyBoolean("falseBoolean", false)
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(doc),
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentToYaml(
          doc,
          /* keepEmptyValues= */ false,
          /* keepNullValues= */ false,
          /* keepGenericDocumentProperties= */ false
        )

        val expectedYaml = """
              - falseBoolean: false
                falseBoolean: false
                realString: value
                zeroLong: 0
        """.trimIndent()
@@ -82,38 +82,38 @@ class AppSearchDataYamlConverterTest {
    }

    @Test
    fun convertGenericDocumentsToYaml_withoutDocProperties_filtersProperties() {
    fun convertGenericDocumentToYaml_withoutDocProperties_filtersProperties() {
        val doc = GenericDocument.Builder<GenericDocument.Builder<*>>("ns3", "doc3", "NoDocProps")
          .setPropertyString("prop", "value")
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(doc),
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentToYaml(
          doc,
          /* keepEmptyValues= */ true,
          /* keepNullValues= */ true,
          /* keepGenericDocumentProperties= */ false
        )

        val expectedYaml = "- prop: value"
        val expectedYaml = "prop: value"
        assertThat(yaml.trim()).isEqualTo(expectedYaml)
    }

    @Test
    fun convertGenericDocumentsToYaml_withArrayTypes_succeeds() {
    fun convertGenericDocumentToYaml_withArrayTypes_succeeds() {
        val doc = GenericDocument.Builder<GenericDocument.Builder<*>>("ns1", "doc4", "ArraySchema")
          .setPropertyString("stringArr", "a", "b", "c")
          .setPropertyLong("longArr", 1L, 2L)
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(doc),
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentToYaml(
          doc,
          /* keepEmptyValues= */ true,
          /* keepNullValues= */ true,
          /* keepGenericDocumentProperties= */ false
        )

        val expectedYaml = """
                - stringArr:
                  stringArr:
                    - a
                    - b
                    - c
@@ -125,7 +125,7 @@ class AppSearchDataYamlConverterTest {
    }

    @Test
    fun convertGenericDocumentsToYaml_withNestedDocument_succeeds() {
    fun convertGenericDocumentToYaml_withNestedDocument_succeeds() {
        val nestedDoc = GenericDocument.Builder<GenericDocument.Builder<*>>("nestedNs", "nestedId", "Nested")
          .setPropertyString("nestedProp", "I am nested")
          .build()
@@ -134,22 +134,22 @@ class AppSearchDataYamlConverterTest {
          .setPropertyDocument("nestedDoc", nestedDoc)
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(mainDoc),
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentToYaml(
          mainDoc,
          /* keepEmptyValues= */ true,
          /* keepNullValues= */ true,
          /* keepGenericDocumentProperties= */ false
        )

        val expectedYaml = """
                - nestedDoc:
                  nestedDoc:
                    nestedProp: I am nested
            """.trimIndent()
        assertThat(yaml.trim()).isEqualTo(expectedYaml)
    }

    @Test
    fun convertGenericDocumentsToYaml_withArrayOfNestedDocuments_succeeds() {
    fun convertGenericDocumentToYaml_withArrayOfNestedDocuments_succeeds() {
        val nestedDoc1 = GenericDocument.Builder<GenericDocument.Builder<*>>("ns", "n1", "Nested")
          .setPropertyString("prop", "first")
          .setCreationTimestampMillis(0L)
@@ -164,15 +164,15 @@ class AppSearchDataYamlConverterTest {
          .setCreationTimestampMillis(1000L)
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(mainDoc),
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentToYaml(
          mainDoc,
          /* keepEmptyValues= */ true,
          /* keepNullValues= */ true,
          /* keepGenericDocumentProperties= */ true
        )

      val expectedYaml = """
            - id: main
              id: main
              namespace: ns
              schemaType: Main
              creationTimestampMillis: 1000
@@ -193,52 +193,4 @@ class AppSearchDataYamlConverterTest {
        """.trimIndent()
        assertThat(yaml.trim()).isEqualTo(expectedYaml)
    }

    @Test
    fun convertGenericDocumentsToYaml_withMultipleDocuments_succeeds() {
        val doc1 = GenericDocument.Builder<GenericDocument.Builder<*>>("ns", "id1", "MySchema")
          .setPropertyString("prop", "val1")
          .setCreationTimestampMillis(0L)
          .build()
        val doc2 = GenericDocument.Builder<GenericDocument.Builder<*>>("ns", "id2", "MySchema")
          .setPropertyString("prop", "val2")
          .setCreationTimestampMillis(1L)
          .build()

        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(doc1, doc2),
          /* keepEmptyValues= */ false,
          /* keepNullValues= */ false,
          /* keepGenericDocumentProperties= */ true
        )

        val expectedYaml = """
                - id: id1
                  namespace: ns
                  schemaType: MySchema
                  creationTimestampMillis: 0
                  score: 0
                  prop: val1
                - id: id2
                  namespace: ns
                  schemaType: MySchema
                  creationTimestampMillis: 1
                  score: 0
                  prop: val2
            """.trimIndent()

        assertThat(yaml.trim()).isEqualTo(expectedYaml)
    }

    @Test
    fun convertGenericDocumentsToYaml_withEmptyArray_returnsEmptyList() {
        val yaml = AppSearchDataYamlConverter.convertGenericDocumentsToYaml(
          arrayOf(),
          /* keepEmptyValues= */ true,
          /* keepNullValues= */ true,
          /* keepGenericDocumentProperties= */ true
        )

        assertThat(yaml.trim()).isEqualTo("")
    }
}