Add cts tests for wallpaper effects generation API

Bug: 213238425
Test: atest CtsWallpaperEffectsGenerationServiceTestCases
Change-Id: Iebc2f7f2fd10db58bdb17f58a564e4f1e917b754
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 09c4067..4872c7d 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -2662,6 +2662,15 @@
     <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by a
+      android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService,
+      to ensure that only the system can bind to it.
+      @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+      <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
@@ -5868,6 +5877,12 @@
     <permission android:name="android.permission.MANAGE_SMARTSPACE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage the wallpaper effects
+      generation service.
+    @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to manage the cloudsearch service.
      @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_CLOUDSEARCH"
diff --git a/tests/wallpapereffectsgeneration/Android.bp b/tests/wallpapereffectsgeneration/Android.bp
new file mode 100644
index 0000000..a3f3145
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CtsWallpaperEffectsGenerationServiceTestCases",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "truth-prebuilt",
+    ],
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    sdk_version: "test_current",
+}
diff --git a/tests/wallpapereffectsgeneration/AndroidManifest.xml b/tests/wallpapereffectsgeneration/AndroidManifest.xml
new file mode 100644
index 0000000..80662d9
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.wallpapereffectsgeneration.cts"
+    android:targetSandboxVersion="2">
+
+    <application>
+        <service android:name=".CtsWallpaperEffectsGenerationService"
+            android:exported="true"
+            android:label="CtsTestWallpaperEffectsGenerationService"
+            android:permission="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE">
+            <intent-filter>
+                <!-- This constant must match WallpaperEffectsGenerationService.SERVICE_INTERFACE -->
+                <action android:name="android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService"/>
+            </intent-filter>
+        </service>
+
+        <uses-library android:name="android.test.runner"/>
+
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:label="CTS tests for the WallpaperEffectsGeneration System APIs."
+        android:targetPackage="android.wallpapereffectsgeneration.cts">
+    </instrumentation>
+
+</manifest>
\ No newline at end of file
diff --git a/tests/wallpapereffectsgeneration/AndroidTest.xml b/tests/wallpapereffectsgeneration/AndroidTest.xml
new file mode 100644
index 0000000..a60936f
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for WallpaperEffectsGeneration CTS tests.">
+    <option name="test-suite-tag" value="cts"/>
+    <option name="config-descriptor:metadata" key="component" value="framework"/>
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app"/>
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi"/>
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true"/>
+        <option name="test-file-name" value="CtsWallpaperEffectsGenerationServiceTestCases.apk"/>
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="android.wallpapereffectsgeneration.cts"/>
+    </test>
+
+</configuration>
\ No newline at end of file
diff --git a/tests/wallpapereffectsgeneration/OWNERS b/tests/wallpapereffectsgeneration/OWNERS
new file mode 100644
index 0000000..39cdd55
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/OWNERS
@@ -0,0 +1,4 @@
+susharon@google.com
+shanh@google.com
+huiwu@google.com
+srazdan@google.com
\ No newline at end of file
diff --git a/tests/wallpapereffectsgeneration/TEST_MAPPING b/tests/wallpapereffectsgeneration/TEST_MAPPING
new file mode 100644
index 0000000..1dbe8e1
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsWallpaperEffectsGenerationServiceTestCases"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CameraAttributesTest.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CameraAttributesTest.java
new file mode 100644
index 0000000..4a2d277
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CameraAttributesTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wallpapereffectsgeneration.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.wallpapereffectsgeneration.CameraAttributes;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link CameraAttributes}
+ *
+ * atest CtsWallpaperEffectsGenerationServiceTestCases
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class CameraAttributesTest {
+    private static final String TAG = "WallpaperEffectsGenerationTest";
+
+    @Test
+    public void testCreateCameraAttributesRequest() {
+        final float[] anchorPointInWorldSpace = new float[]{0.5f, 1.5f, -1.0f};
+        final float[] anchorPointInOutputUvSpace = new float[]{0.5f, 2.5f};
+        final float yaw = 35.2f;
+        final float pitch = 45.6f;
+        final float dolly = 0.3f;
+        final float fov = 60.0f;
+        final float frustumNear = 0.5f;
+        final float frustumFar = 200.0f;
+
+        CameraAttributes attributes = new CameraAttributes.Builder(anchorPointInWorldSpace,
+                anchorPointInOutputUvSpace)
+                .setCameraOrbitYawDegrees(yaw)
+                .setCameraOrbitPitchDegrees(pitch)
+                .setDollyDistanceInWorldSpace(dolly)
+                .setVerticalFovDegrees(fov)
+                .setFrustumNearInWorldSpace(frustumNear)
+                .setFrustumFarInWorldSpace(frustumFar)
+                .build();
+
+        /** Check the original attributes. */
+        assertThat(attributes.getAnchorPointInWorldSpace()).isEqualTo(anchorPointInWorldSpace);
+        assertThat(attributes.getAnchorPointInOutputUvSpace()).isEqualTo(
+                anchorPointInOutputUvSpace);
+        assertThat(attributes.getCameraOrbitYawDegrees()).isEqualTo(yaw);
+        assertThat(attributes.getCameraOrbitPitchDegrees()).isEqualTo(pitch);
+        assertThat(attributes.getDollyDistanceInWorldSpace()).isEqualTo(dolly);
+        assertThat(attributes.getVerticalFovDegrees()).isEqualTo(fov);
+        assertThat(attributes.getFrustumNearInWorldSpace()).isEqualTo(frustumNear);
+        assertThat(attributes.getFrustumFarInWorldSpace()).isEqualTo(frustumFar);
+
+        Parcel parcel = Parcel.obtain();
+        parcel.setDataPosition(0);
+        attributes.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        CameraAttributes copy =
+                CameraAttributes.CREATOR.createFromParcel(parcel);
+        /** Check the copied attributes */
+        assertThat(copy.getAnchorPointInWorldSpace()).isEqualTo(anchorPointInWorldSpace);
+        assertThat(copy.getAnchorPointInOutputUvSpace()).isEqualTo(anchorPointInOutputUvSpace);
+        assertThat(copy.getCameraOrbitYawDegrees()).isEqualTo(yaw);
+        assertThat(copy.getCameraOrbitPitchDegrees()).isEqualTo(pitch);
+        assertThat(copy.getDollyDistanceInWorldSpace()).isEqualTo(dolly);
+        assertThat(copy.getVerticalFovDegrees()).isEqualTo(fov);
+        assertThat(copy.getFrustumNearInWorldSpace()).isEqualTo(frustumNear);
+        assertThat(copy.getFrustumFarInWorldSpace()).isEqualTo(frustumFar);
+
+        parcel.recycle();
+    }
+}
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CinematicEffectRequestTest.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CinematicEffectRequestTest.java
new file mode 100644
index 0000000..23b2e7e
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CinematicEffectRequestTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wallpapereffectsgeneration.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.graphics.Bitmap;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.UUID;
+
+/**
+ * Tests for {@link CinematicEffectRequest}
+ *
+ * atest CtsWallpaperEffectsGenerationServiceTestCases
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class CinematicEffectRequestTest {
+    private static final String TAG = "WallpaperEffectsGenerationTest";
+
+    @Test
+    public void testCreateCinematicEffectRequest() {
+        final String taskId = UUID.randomUUID().toString();
+        final Bitmap bmp = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
+        CinematicEffectRequest request = new CinematicEffectRequest(taskId, bmp);
+
+        /** Check the original request. */
+        assertThat(request.getTaskId()).isEqualTo(taskId);
+        assertThat(request.getBitmap()).isEqualTo(bmp);
+
+        Parcel parcel = Parcel.obtain();
+        parcel.setDataPosition(0);
+        request.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        CinematicEffectRequest copy =
+                CinematicEffectRequest.CREATOR.createFromParcel(parcel);
+        /** Check the copied request. */
+        assertThat(copy.getTaskId()).isEqualTo(taskId);
+        assertThat(copy.getBitmap().sameAs(bmp)).isTrue();
+
+        parcel.recycle();
+    }
+}
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CinematicEffectResponseTest.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CinematicEffectResponseTest.java
new file mode 100644
index 0000000..0ec9131
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CinematicEffectResponseTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wallpapereffectsgeneration.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.wallpapereffectsgeneration.CameraAttributes;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.TexturedMesh;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Tests for {@link CinematicEffectResponse}
+ *
+ * atest CtsWallpaperEffectsGenerationServiceTestCases
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class CinematicEffectResponseTest {
+    private static final String TAG = "WallpaperEffectsGenerationTest";
+
+    @Test
+    public void testCreateCinematicEffectResponse() {
+        final int statusCode = CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_OK;
+        final String taskId = UUID.randomUUID().toString();
+        final int imageContentType = CinematicEffectResponse.IMAGE_CONTENT_TYPE_LANDSCAPE;
+        final Bitmap bmp = Bitmap.createBitmap(3200, 4800, Config.ARGB_8888);
+        final float[] vertices = WallpaperEffectsGenerationTestUtils.createVertices(1500000);
+        final int[] indices = WallpaperEffectsGenerationTestUtils.createIndices(1500000);
+        final int indicesLayoutType = TexturedMesh.INDICES_LAYOUT_TRIANGLES;
+        final int verticesLayoutType = TexturedMesh.VERTICES_LAYOUT_POSITION3_UV2;
+
+        final TexturedMesh texturedMesh = new TexturedMesh.Builder(bmp)
+                .setIndices(indices)
+                .setVertices(vertices)
+                .setIndicesLayoutType(indicesLayoutType)
+                .setVerticesLayoutType(verticesLayoutType).build();
+        List<TexturedMesh> texturedMeshes = new ArrayList<TexturedMesh>();
+        texturedMeshes.add(texturedMesh);
+
+        final float[] anchorPointInWorldSpace1 = new float[]{0.5f, 1.5f, -1.0f};
+        final float[] anchorPointInOutputUvSpace1 = new float[]{0.5f, 2.5f};
+        final float yaw1 = 35.2f;
+        final float pitch1 = 45.6f;
+        final float dolly1 = 0.3f;
+        final float fov1 = 60.0f;
+        final float frustumNear1 = 0.5f;
+        final float frustumFar1 = 200.0f;
+        final float[] anchorPointInWorldSpace2 = new float[]{0.6f, 1.6f, -1.1f};
+        final float[] anchorPointInOutputUvSpace2 = new float[]{0.6f, 2.6f};
+        final float yaw2 = 35.1f;
+        final float pitch2 = 45.4f;
+        final float dolly2 = 0.4f;
+        final float fov2 = 45.0f;
+        final float frustumNear2 = 0.6f;
+        final float frustumFar2 = 220.0f;
+
+        final CameraAttributes attributes1 =
+                new CameraAttributes.Builder(anchorPointInWorldSpace1,
+                        anchorPointInOutputUvSpace1)
+                        .setCameraOrbitYawDegrees(yaw1)
+                        .setCameraOrbitPitchDegrees(pitch1)
+                        .setDollyDistanceInWorldSpace(dolly1)
+                        .setVerticalFovDegrees(fov1)
+                        .setFrustumNearInWorldSpace(frustumNear1)
+                        .setFrustumFarInWorldSpace(frustumFar1)
+                        .build();
+        final CameraAttributes attributes2 =
+                new CameraAttributes.Builder(anchorPointInWorldSpace2,
+                        anchorPointInOutputUvSpace2)
+                        .setCameraOrbitYawDegrees(yaw2)
+                        .setCameraOrbitPitchDegrees(pitch2)
+                        .setDollyDistanceInWorldSpace(dolly2)
+                        .setVerticalFovDegrees(fov2)
+                        .setFrustumNearInWorldSpace(frustumNear2)
+                        .setFrustumFarInWorldSpace(frustumFar2)
+                        .build();
+
+        CinematicEffectResponse response =
+                new CinematicEffectResponse.Builder(statusCode, taskId)
+                        .setImageContentType(imageContentType)
+                        .setTexturedMeshes(texturedMeshes)
+                        .setStartKeyFrame(attributes1)
+                        .setEndKeyFrame(attributes2)
+                        .build();
+
+        /** Check the original request. */
+        assertThat(response.getStatusCode()).isEqualTo(statusCode);
+        assertThat(response.getTaskId()).isEqualTo(taskId);
+        assertThat(response.getImageContentType()).isEqualTo(imageContentType);
+
+        assertThat(response.getTexturedMeshes().size()).isEqualTo(1);
+        final TexturedMesh mesh = response.getTexturedMeshes().get(0);
+        assertThat(mesh.getBitmap()).isEqualTo(bmp);
+        assertThat(mesh.getIndices()).isEqualTo(indices);
+        assertThat(mesh.getVertices()).isEqualTo(vertices);
+        assertThat(mesh.getIndicesLayoutType()).isEqualTo(indicesLayoutType);
+        assertThat(mesh.getVerticesLayoutType()).isEqualTo(verticesLayoutType);
+
+        CameraAttributes startAttributes = response.getStartKeyFrame();
+        assertThat(startAttributes.getAnchorPointInWorldSpace()).isEqualTo(
+                anchorPointInWorldSpace1);
+        assertThat(startAttributes.getAnchorPointInOutputUvSpace()).isEqualTo(
+                anchorPointInOutputUvSpace1);
+        assertThat(startAttributes.getCameraOrbitYawDegrees()).isEqualTo(yaw1);
+        assertThat(startAttributes.getCameraOrbitPitchDegrees()).isEqualTo(pitch1);
+        assertThat(startAttributes.getDollyDistanceInWorldSpace()).isEqualTo(dolly1);
+        assertThat(startAttributes.getVerticalFovDegrees()).isEqualTo(fov1);
+        assertThat(startAttributes.getFrustumNearInWorldSpace()).isEqualTo(frustumNear1);
+        assertThat(startAttributes.getFrustumFarInWorldSpace()).isEqualTo(frustumFar1);
+
+        CameraAttributes endAttributes = response.getEndKeyFrame();
+        assertThat(endAttributes.getAnchorPointInWorldSpace()).isEqualTo(anchorPointInWorldSpace2);
+        assertThat(endAttributes.getAnchorPointInOutputUvSpace()).isEqualTo(
+                anchorPointInOutputUvSpace2);
+        assertThat(endAttributes.getCameraOrbitYawDegrees()).isEqualTo(yaw2);
+        assertThat(endAttributes.getCameraOrbitPitchDegrees()).isEqualTo(pitch2);
+        assertThat(endAttributes.getDollyDistanceInWorldSpace()).isEqualTo(dolly2);
+        assertThat(endAttributes.getVerticalFovDegrees()).isEqualTo(fov2);
+        assertThat(endAttributes.getFrustumNearInWorldSpace()).isEqualTo(frustumNear2);
+        assertThat(endAttributes.getFrustumFarInWorldSpace()).isEqualTo(frustumFar2);
+
+        Parcel parcel = Parcel.obtain();
+        parcel.setDataPosition(0);
+        response.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        CinematicEffectResponse copy =
+                CinematicEffectResponse.CREATOR.createFromParcel(parcel);
+
+        /** Check the copied response. */
+        assertThat(copy.getStatusCode()).isEqualTo(statusCode);
+        assertThat(copy.getTaskId()).isEqualTo(taskId);
+        assertThat(copy.getImageContentType()).isEqualTo(imageContentType);
+
+        assertThat(copy.getTexturedMeshes().size()).isEqualTo(1);
+        final TexturedMesh meshCopy = copy.getTexturedMeshes().get(0);
+        assertThat(meshCopy.getBitmap().sameAs(bmp)).isTrue();
+        assertThat(meshCopy.getIndices()).isEqualTo(indices);
+        assertThat(meshCopy.getVertices()).isEqualTo(vertices);
+        assertThat(meshCopy.getIndicesLayoutType()).isEqualTo(indicesLayoutType);
+        assertThat(meshCopy.getVerticesLayoutType()).isEqualTo(verticesLayoutType);
+
+        CameraAttributes startAttributesCopy = copy.getStartKeyFrame();
+        assertThat(startAttributesCopy.getAnchorPointInWorldSpace()).isEqualTo(
+                anchorPointInWorldSpace1);
+        assertThat(startAttributesCopy.getAnchorPointInOutputUvSpace()).isEqualTo(
+                anchorPointInOutputUvSpace1);
+        assertThat(startAttributesCopy.getCameraOrbitYawDegrees()).isEqualTo(yaw1);
+        assertThat(startAttributesCopy.getCameraOrbitPitchDegrees()).isEqualTo(pitch1);
+        assertThat(startAttributesCopy.getDollyDistanceInWorldSpace()).isEqualTo(dolly1);
+        assertThat(startAttributesCopy.getVerticalFovDegrees()).isEqualTo(fov1);
+        assertThat(startAttributesCopy.getFrustumNearInWorldSpace()).isEqualTo(frustumNear1);
+        assertThat(startAttributesCopy.getFrustumFarInWorldSpace()).isEqualTo(frustumFar1);
+
+        CameraAttributes endAttributesCopy = copy.getEndKeyFrame();
+        assertThat(endAttributesCopy.getAnchorPointInWorldSpace())
+                .isEqualTo(anchorPointInWorldSpace2);
+        assertThat(endAttributesCopy.getAnchorPointInOutputUvSpace()).isEqualTo(
+                anchorPointInOutputUvSpace2);
+        assertThat(endAttributesCopy.getCameraOrbitYawDegrees()).isEqualTo(yaw2);
+        assertThat(endAttributesCopy.getCameraOrbitPitchDegrees()).isEqualTo(pitch2);
+        assertThat(endAttributesCopy.getDollyDistanceInWorldSpace()).isEqualTo(dolly2);
+        assertThat(endAttributesCopy.getVerticalFovDegrees()).isEqualTo(fov2);
+        assertThat(endAttributesCopy.getFrustumNearInWorldSpace()).isEqualTo(frustumNear2);
+        assertThat(endAttributesCopy.getFrustumFarInWorldSpace()).isEqualTo(frustumFar2);
+
+        parcel.recycle();
+    }
+}
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CtsWallpaperEffectsGenerationService.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CtsWallpaperEffectsGenerationService.java
new file mode 100644
index 0000000..bf2be5e
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/CtsWallpaperEffectsGenerationService.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wallpapereffectsgeneration.cts;
+
+import static android.app.wallpapereffectsgeneration.CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR;
+import static android.app.wallpapereffectsgeneration.CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_OK;
+import static android.app.wallpapereffectsgeneration.CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_UNKNOWN;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * WallpaperEffectsGenerationService implementation for cts tests.
+ */
+public class CtsWallpaperEffectsGenerationService extends WallpaperEffectsGenerationService {
+    private static final String TAG =
+            "WallpaperEffectsGenerationTest["
+                    + CtsWallpaperEffectsGenerationService.class.getSimpleName() + "]";
+    private static final boolean DEBUG = false;
+    public static final String SERVICE_NAME = "android.wallpapereffectsgeneration.cts/."
+            + CtsWallpaperEffectsGenerationService.class.getSimpleName();
+
+    private static Watcher sWatcher;
+
+    @Override
+    public void onCreate() {
+        if (DEBUG) Log.d(TAG, "CtsWallpaperEffectsGenerationService onCreate");
+        super.onCreate();
+        sWatcher.created.countDown();
+    }
+
+    @Override
+    public void onGenerateCinematicEffect(CinematicEffectRequest cinematicEffectRequest) {
+        if (DEBUG) {
+            Log.d(TAG, "onGenerateCinematicEffect taskId = "
+                    + cinematicEffectRequest.getTaskId() + ".");
+        }
+
+        sWatcher.verifier.onGenerateCinematicEffect(cinematicEffectRequest);
+
+        String taskId = cinematicEffectRequest.getTaskId();
+        if (taskId.contains("pending")) {
+            // Do nothing. Simulate it takes a long time to process.
+            return;
+        }
+        if (taskId.contains("error")) {
+            returnCinematicEffectResponse(
+                    createCinematicEffectResponse(taskId, CINEMATIC_EFFECT_STATUS_ERROR));
+        } else if (taskId.contains("initial")) {
+            // Use this status code to tell the difference between initial call and calls in the
+            // real test case.
+            returnCinematicEffectResponse(
+                    createCinematicEffectResponse(taskId, CINEMATIC_EFFECT_STATUS_UNKNOWN));
+        } else {
+            returnCinematicEffectResponse(
+                    createCinematicEffectResponse(taskId, CINEMATIC_EFFECT_STATUS_OK));
+        }
+        sWatcher.requested.countDown();
+    }
+
+    private CinematicEffectResponse createCinematicEffectResponse(String taskId, int status) {
+        return new CinematicEffectResponse.Builder(status, taskId).build();
+    }
+
+
+    @Override
+    public void onDestroy() {
+        if (DEBUG) {
+            Log.d(TAG, "onDestroy");
+        }
+        super.onDestroy();
+        sWatcher.destroyed.countDown();
+    }
+
+    public static Watcher setWatcher() {
+        if (DEBUG) {
+            Log.d(TAG, " setWatcher");
+        }
+        if (sWatcher != null) {
+            throw new IllegalStateException("Set watcher with watcher already set");
+        }
+        sWatcher = new Watcher();
+        return sWatcher;
+    }
+
+    public static void clearWatcher() {
+        if (DEBUG) Log.d(TAG, "clearWatcher");
+        sWatcher = null;
+    }
+
+    public static final class Watcher {
+        public CountDownLatch created = new CountDownLatch(1);
+        public CountDownLatch requested = new CountDownLatch(1);
+        public CountDownLatch initialCallReturned = new CountDownLatch(1);
+        public CountDownLatch destroyed = new CountDownLatch(1);
+        public CountDownLatch okResponse = new CountDownLatch(1);
+        public CountDownLatch errorResponse = new CountDownLatch(1);
+        public CountDownLatch pendingResponse = new CountDownLatch(1);
+        public CountDownLatch tooManyRequestsResponse = new CountDownLatch(1);
+
+        /**
+         * Can be used to verify that API specific service methods are called. Not a real mock as
+         * the system isn't talking to this directly, it has calls proxied to it.
+         */
+        public CtsWallpaperEffectsGenerationService verifier;
+    }
+}
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/TexturedMeshTest.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/TexturedMeshTest.java
new file mode 100644
index 0000000..929c636
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/TexturedMeshTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wallpapereffectsgeneration.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.wallpapereffectsgeneration.TexturedMesh;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link TexturedMesh}
+ *
+ * atest CtsWallpaperEffectsGenerationServiceTestCases
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class TexturedMeshTest {
+    private static final String TAG = "WallpaperEffectsGenerationTest";
+
+    @Test
+    public void testCreateTexturedMeshRequest() {
+        final Bitmap bmp = Bitmap.createBitmap(3200, 4800, Config.ARGB_8888);
+        final float[] vertices = WallpaperEffectsGenerationTestUtils.createVertices(1500000);
+        final int[] indices = WallpaperEffectsGenerationTestUtils.createIndices(500000);
+        final int indicesLayoutType = TexturedMesh.INDICES_LAYOUT_TRIANGLES;
+        final int verticesLayoutType = TexturedMesh.VERTICES_LAYOUT_POSITION3_UV2;
+
+        TexturedMesh texturedMesh = new TexturedMesh.Builder(bmp)
+                .setIndices(indices)
+                .setVertices(vertices)
+                .setIndicesLayoutType(indicesLayoutType)
+                .setVerticesLayoutType(verticesLayoutType).build();
+
+        /** Check the original mesh. */
+        assertThat(texturedMesh.getBitmap()).isEqualTo(bmp);
+        assertThat(texturedMesh.getIndices()).isEqualTo(indices);
+        assertThat(texturedMesh.getVertices()).isEqualTo(vertices);
+        assertThat(texturedMesh.getIndicesLayoutType()).isEqualTo(indicesLayoutType);
+        assertThat(texturedMesh.getVerticesLayoutType()).isEqualTo(verticesLayoutType);
+
+        Parcel parcel = Parcel.obtain();
+        parcel.setDataPosition(0);
+        texturedMesh.writeToParcel(parcel, 0);
+        Log.i(TAG, "textured mesh size = " + parcel.dataSize());
+        parcel.setDataPosition(0);
+        TexturedMesh copy =
+                TexturedMesh.CREATOR.createFromParcel(parcel);
+        /** Check the copied mesh. */
+        assertThat(copy.getBitmap().sameAs(bmp)).isTrue();
+        assertThat(copy.getIndices()).isEqualTo(indices);
+        assertThat(copy.getVertices()).isEqualTo(vertices);
+        assertThat(copy.getIndicesLayoutType()).isEqualTo(indicesLayoutType);
+        assertThat(copy.getVerticesLayoutType()).isEqualTo(verticesLayoutType);
+
+        parcel.recycle();
+    }
+}
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/WallpaperEffectsGenerationManagerTest.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/WallpaperEffectsGenerationManagerTest.java
new file mode 100644
index 0000000..96a7720
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/WallpaperEffectsGenerationManagerTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tests for {@link android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager}
+ *
+ * atest CtsWallpaperEffectsGenerationServiceTestCases
+ */
+package android.wallpapereffectsgeneration.cts;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
+import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
+import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager;
+import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager.CinematicEffectListener;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.RequiredServiceRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link WallpaperEffectsGenerationManager}
+ *
+ * atest CtsWallpaperEffectsGenerationServiceTestCases
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class WallpaperEffectsGenerationManagerTest {
+    private static final String TAG = "WallpaperEffectsGenerationTest";
+    private static final boolean DEBUG = false;
+    private static final long VERIFY_TIMEOUT_MS = 5_000;
+    private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 20_000;
+
+    @Rule
+    public final RequiredServiceRule mRequiredServiceRule =
+            new RequiredServiceRule(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
+
+    private WallpaperEffectsGenerationManager mManager;
+    private CtsWallpaperEffectsGenerationService.Watcher mWatcher;
+    private CinematicEffectRequest mInitialTaskRequest =
+            createCinematicEffectRequest("initial-task");
+
+    @Before
+    public void setup() throws Exception {
+        mWatcher = CtsWallpaperEffectsGenerationService.setWatcher();
+        mManager = getContext().getSystemService(WallpaperEffectsGenerationManager.class);
+        setService(CtsWallpaperEffectsGenerationService.SERVICE_NAME);
+        // The wallpaper effects generation services are created lazily,
+        // call one method to start the service for these tests.
+        mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
+        reset(mWatcher.verifier);
+        mManager.generateCinematicEffect(mInitialTaskRequest,
+                Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        await(mWatcher.created, "Waiting for onCreated()");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        setService(null);
+        await(mWatcher.destroyed, "Waiting for onDestroyed()");
+        mWatcher = null;
+        CtsWallpaperEffectsGenerationService.clearWatcher();
+    }
+
+    @Test
+    public void testWallpaperEffectsGenerationServiceConnection() {
+        // In test setup, 1st request is already made.
+        assertNotNull(mManager);
+        // Check the 1st call in setup was received by service.
+        await(mWatcher.requested, "Waiting for requested.");
+        await(mWatcher.initialCallReturned, "Result is produced");
+        // Check the request the server received is the request sent.
+        verifyService().onGenerateCinematicEffect(eq(mInitialTaskRequest));
+    }
+
+    @Test
+    public void testGenerateCinematicEffect_okResponse() {
+        mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
+        reset(mWatcher.verifier);
+        assertNotNull(mManager);
+        // Let the initial request in setup finishes.
+        await(mWatcher.requested, "Waiting for connect call finishes.");
+        CinematicEffectRequest request = createSimpleCinematicEffectRequest("ok-task");
+
+        mManager.generateCinematicEffect(request, Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        await(mWatcher.okResponse, "Result is okay");
+        verifyService().onGenerateCinematicEffect(eq(request));
+    }
+
+    @Test
+    public void testGenerateCinematicEffect_errorResponse() {
+        mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
+        reset(mWatcher.verifier);
+        assertNotNull(mManager);
+        // Let the initial request in setup finishes.
+        await(mWatcher.initialCallReturned, "Waiting for connect call finishes.");
+        CinematicEffectRequest request = createSimpleCinematicEffectRequest("error-task");
+        mManager.generateCinematicEffect(request, Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        await(mWatcher.errorResponse, "Result is error");
+        verifyService().onGenerateCinematicEffect(eq(request));
+    }
+
+    @Test
+    public void testGenerateCinematicEffect_pendingResponse() {
+        mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
+        reset(mWatcher.verifier);
+        assertNotNull(mManager);
+        // Let the initial request in setup finishes.
+        await(mWatcher.initialCallReturned, "Waiting for requested call finishes.");
+        CinematicEffectRequest request1 = createCinematicEffectRequest("pending-task-id");
+        CinematicEffectRequest request2 = createCinematicEffectRequest("pending-task-id");
+        mManager.generateCinematicEffect(request1, Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        mManager.generateCinematicEffect(request2, Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        await(mWatcher.pendingResponse, "Second request immediately fail with pending response");
+    }
+
+    @Test
+    public void testGenerateCinematicEffect_tooManyRequestsResponse() {
+        mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
+        reset(mWatcher.verifier);
+        assertNotNull(mManager);
+        // Let the initial request in setup finishes.
+        await(mWatcher.initialCallReturned, "Waiting for connect call finishes.");
+        CinematicEffectRequest request1 = createCinematicEffectRequest("pending-task-id");
+        CinematicEffectRequest request2 = createCinematicEffectRequest("other-task-id");
+        mManager.generateCinematicEffect(request1, Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        mManager.generateCinematicEffect(request2, Executors.newSingleThreadExecutor(),
+                createCinematicEffectListener());
+        await(mWatcher.tooManyRequestsResponse,
+                "Second request immediately fail with too many requests response");
+    }
+
+    private CinematicEffectListener createCinematicEffectListener() {
+        return cinematicEffectResponse -> {
+            Log.d(TAG, "cinematic effect response taskId = " + cinematicEffectResponse.getTaskId()
+                    + ", status code = " + cinematicEffectResponse.getStatusCode());
+            if (cinematicEffectResponse.getStatusCode()
+                    == CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_OK) {
+                mWatcher.okResponse.countDown();
+            } else if (cinematicEffectResponse.getStatusCode()
+                    == CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING) {
+                mWatcher.pendingResponse.countDown();
+            } else if (cinematicEffectResponse.getStatusCode()
+                    == CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS) {
+                mWatcher.tooManyRequestsResponse.countDown();
+            } else if (cinematicEffectResponse.getStatusCode()
+                    == CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_UNKNOWN) {
+                // This case is used to check the 1st request in the "Setup" method finishes.
+                mWatcher.initialCallReturned.countDown();
+            } else if (cinematicEffectResponse.getStatusCode()
+                    == CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR) {
+                mWatcher.errorResponse.countDown();
+            }
+        };
+    }
+
+    private CinematicEffectRequest createCinematicEffectRequest(String taskId) {
+        Bitmap bmp = Bitmap.createBitmap(32, 48, Bitmap.Config.ARGB_8888);
+        return new CinematicEffectRequest(taskId, bmp);
+    }
+
+    private CtsWallpaperEffectsGenerationService verifyService() {
+        return verify(mWatcher.verifier, timeout(VERIFY_TIMEOUT_MS));
+    }
+
+    private void setService(String service) {
+        if (DEBUG) {
+            Log.d(TAG, "Setting WallpaperEffectsGeneration service to " + service);
+        }
+        int userId = Process.myUserHandle().getIdentifier();
+        String shellCommand = "";
+        if (service != null) {
+            shellCommand = "cmd wallpaper_effects_generation set temporary-service "
+                    + userId + " " + service + " 60000";
+        } else {
+            shellCommand = "cmd wallpaper_effects_generation set temporary-service " + userId;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "runShellCommand(): " + shellCommand);
+        }
+        runShellCommand(shellCommand);
+    }
+
+    private void await(@NonNull CountDownLatch latch, @NonNull String message) {
+        try {
+            assertWithMessage(message).that(
+                    latch.await(SERVICE_LIFECYCLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new IllegalStateException("Interrupted while: " + message);
+        }
+    }
+
+    private CinematicEffectRequest createSimpleCinematicEffectRequest(String taskId) {
+        return new CinematicEffectRequest(taskId,
+                Bitmap.createBitmap(32, 48, Bitmap.Config.ARGB_8888));
+    }
+}
diff --git a/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/WallpaperEffectsGenerationTestUtils.java b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/WallpaperEffectsGenerationTestUtils.java
new file mode 100644
index 0000000..50462d4
--- /dev/null
+++ b/tests/wallpapereffectsgeneration/src/android/wallpapereffectsgeneration/cts/WallpaperEffectsGenerationTestUtils.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.wallpapereffectsgeneration.cts;
+
+public class WallpaperEffectsGenerationTestUtils {
+
+    public static float[] createVertices(int verticesNum) {
+        float[] vertices = new float[verticesNum];
+        for (int i = 0; i < verticesNum; i++) {
+            vertices[i] = (float) i;
+        }
+        return vertices;
+    }
+
+    public static int[] createIndices(int indicesNum) {
+        int[] indices = new int[indicesNum];
+        for (int i = 0; i < indicesNum; i++) {
+            indices[i] =  i;
+        }
+        return indices;
+    }
+}