transcoding: Rework mediatranscoding test.

Create a sperate directory for all tests associated with
mediatranscoding.
This CL is a preparation of hooking with actual service,
adding perf benchamrk, power measurement.

Bug: 145628554
Test: MediaTranscodingTest.

Change-Id: Ifcdb26eae2e71599e2e19bb92b991f88809ec5e0
diff --git a/media/tests/MediaTranscodingTest/Android.bp b/media/tests/MediaTranscodingTest/Android.bp
new file mode 100644
index 0000000..fcf8f11
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/Android.bp
@@ -0,0 +1,15 @@
+android_test {
+    name: "mediatranscodingtest",
+    srcs: ["**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: [
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "android-support-test",
+        "testng"
+    ],
+    platform_apis: true,
+}
diff --git a/media/tests/MediaTranscodingTest/AndroidManifest.xml b/media/tests/MediaTranscodingTest/AndroidManifest.xml
new file mode 100644
index 0000000..07674da
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="com.android.mediatranscodingtest">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+
+    <application android:label="@string/app_name">
+        <uses-library android:name="android.test.runner"/>
+        <activity android:label="@string/app_name"
+             android:name="MediaTranscodingTest"
+             android:screenOrientation="landscape"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name=".MediaTranscodingTestRunner"
+         android:targetPackage="com.android.mediatranscodingtest"
+         android:label="MediaTranscoding tests InstrumentationRunner">
+    </instrumentation>
+</manifest>
diff --git a/media/tests/MediaTranscodingTest/AndroidTest.xml b/media/tests/MediaTranscodingTest/AndroidTest.xml
new file mode 100644
index 0000000..c2167e8
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="Runs MediaTranscoding Tests">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="mediatranscodingtest.apk" />
+    </target_preparer>
+
+    <option name="test-tag" value="MediaTranscodingTest" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.mediatranscodingtest" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/media/tests/MediaTranscodingTest/Readme.txt b/media/tests/MediaTranscodingTest/Readme.txt
new file mode 100644
index 0000000..e3b835b
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/Readme.txt
@@ -0,0 +1,8 @@
+MediaTranscodingTest/
+    Uses instrumentation and so can be run with runtest.
+    It assumes /sdcard/media_api/ has been populated.
+
+contents/media_api/
+    Push to /sdcard/media_api/ for use with MediaTranscodingTest:
+    adb shell mkdir /sdcard/media_api
+    adb push contents/media_api/ /sdcard/media_api/
diff --git a/media/tests/MediaTranscodingTest/res/drawable-hdpi/icon.png b/media/tests/MediaTranscodingTest/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..a02138e
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/media/tests/MediaTranscodingTest/res/drawable-mdpi/icon.png b/media/tests/MediaTranscodingTest/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..64e3601
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/media/tests/MediaTranscodingTest/res/layout/surface_view.xml b/media/tests/MediaTranscodingTest/res/layout/surface_view.xml
new file mode 100644
index 0000000..3b49db0
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/res/layout/surface_view.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent"
+  android:orientation="vertical">
+
+  <FrameLayout
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+  <SurfaceView
+     android:id="@+id/surface_view"
+     android:layout_width="match_parent"
+     android:layout_height="match_parent"
+     android:layout_centerInParent="true"
+     />
+
+  </FrameLayout>
+
+</LinearLayout>
diff --git a/media/tests/MediaTranscodingTest/res/raw/VideoOnlyHEVC.mp4 b/media/tests/MediaTranscodingTest/res/raw/VideoOnlyHEVC.mp4
new file mode 100644
index 0000000..7ac0024
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/res/raw/VideoOnlyHEVC.mp4
Binary files differ
diff --git a/media/tests/MediaTranscodingTest/res/values/strings.xml b/media/tests/MediaTranscodingTest/res/values/strings.xml
new file mode 100644
index 0000000..0e1f8eb
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+	<!-- Test application name [CHAR LIMIT=32] -->
+    <string name="app_name">MediaTranscodingTest</string>
+</resources>
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaConstants.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaConstants.java
new file mode 100644
index 0000000..52f2787
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaConstants.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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 com.android.mediatranscodingtest;
+
+/**
+ *
+ * This class has the names of the all the activity name and variables in the
+ * instrumentation test.
+ *
+ */
+public class MediaConstants {
+    /*
+     * Source test files.
+     */
+    public static final String[] SOURCE_HEVC_VIDEO_ONLY_TEST_FILES = {
+        "/sdcard/media_api/video/VideoOnlyHEVC.mp4",
+    };
+}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java
new file mode 100644
index 0000000..e886331
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerWithMockServiceTest.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2019 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 com.android.mediatranscodingtest;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.media.IMediaTranscodingService;
+import android.media.ITranscodingClient;
+import android.media.ITranscodingClientCallback;
+import android.media.MediaFormat;
+import android.media.MediaTranscodeManager;
+import android.media.MediaTranscodeManager.TranscodingJob;
+import android.media.MediaTranscodeManager.TranscodingRequest;
+import android.media.TranscodingJobParcel;
+import android.media.TranscodingRequestParcel;
+import android.media.TranscodingResultParcel;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import org.junit.Test;
+
+import java.io.File;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/*
+ * Functional tests for MediaTranscodeManager in the media framework.
+ * The test uses a mock Transcoding service as backend to test the API functionality.
+ *
+ * To run this test suite:
+     make frameworks/base/media/tests/MediaTranscodingTest
+     make mediatranscodingtest
+
+     adb install -r testcases/mediatranscodingtest/arm64/mediatranscodingtest.apk
+
+     adb shell am instrument -e class \
+     com.android.mediatranscodingtest.MediaTranscodeManagerWithMockServiceTest \
+     -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
+ *
+ */
+public class MediaTranscodeManagerWithMockServiceTest
+        extends ActivityInstrumentationTestCase2<MediaTranscodingTest> {
+    private static final String TAG = "MediaTranscodeManagerWithMockServiceTest";
+    /** The time to wait for the transcode operation to complete before failing the test. */
+    private static final int TRANSCODE_TIMEOUT_SECONDS = 2;
+    private Context mContext;
+    private MediaTranscodeManager mMediaTranscodeManager = null;
+    private Uri mSourceHEVCVideoUri = null;
+    private Uri mDestinationUri = null;
+
+    // Use mock transcoding service for testing the api.
+    private MockTranscodingService mTranscodingService = null;
+
+    // Setting for transcoding to H.264.
+    private static final String MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
+    private static final int BIT_RATE = 2000000;            // 2Mbps
+    private static final int WIDTH = 1920;
+    private static final int HEIGHT = 1080;
+
+    // A mock transcoding service that will take constant 300ms to process each transcoding job.
+    // Instead of doing real transcoding, it will return the dst uri directly.
+    class MockTranscodingService extends IMediaTranscodingService.Stub {
+        private final ScheduledExecutorService mJobScheduler = Executors.newScheduledThreadPool(1);
+        private int mNumOfClients = 0;
+        private AtomicInteger mJobId = new AtomicInteger();
+
+        // A runnable that will process the job.
+        private class ProcessingJobRunnable implements Runnable {
+            private TranscodingJobParcel mJob;
+            private ITranscodingClientCallback mCallback;
+            private ConcurrentMap<Integer, ScheduledFuture<?>> mJobMap;
+
+            ProcessingJobRunnable(ITranscodingClientCallback callback,
+                    TranscodingJobParcel job,
+                    ConcurrentMap<Integer, ScheduledFuture<?>> jobMap) {
+                mJob = job;
+                mCallback = callback;
+                mJobMap = jobMap;
+            }
+
+            @Override
+            public void run() {
+                Log.d(TAG, "Start to process job " + mJob.jobId);
+                TranscodingResultParcel result = new TranscodingResultParcel();
+                try {
+                    mCallback.onTranscodingFinished(mJob.jobId, result);
+                    // Removes the job from job map.
+                    mJobMap.remove(mJob.jobId);
+                } catch (RemoteException re) {
+                    Log.e(TAG, "Failed to callback to client");
+                }
+            }
+        }
+
+        @Override
+        public ITranscodingClient registerClient(ITranscodingClientCallback callback,
+                String clientName, String opPackageName, int clientUid, int clientPid)
+                throws RemoteException {
+            Log.d(TAG, "MockTranscodingService creates one client");
+
+            ITranscodingClient client = new ITranscodingClient.Stub() {
+                private final ConcurrentMap<Integer, ScheduledFuture<?>> mPendingTranscodingJobs =
+                        new ConcurrentHashMap<Integer, ScheduledFuture<?>>();
+
+                @Override
+                public boolean submitRequest(TranscodingRequestParcel inRequest,
+                        TranscodingJobParcel outjob) {
+                    Log.d(TAG, "Mock client gets submitRequest");
+                    try {
+                        outjob.request = inRequest;
+                        outjob.jobId = mJobId.getAndIncrement();
+                        Log.d(TAG, "Generate new job " + outjob.jobId);
+
+                        // Schedules the job to run after inRequest.processingDelayMs.
+                        ScheduledFuture<?> transcodingFuture = mJobScheduler.schedule(
+                                new ProcessingJobRunnable(callback, outjob,
+                                        mPendingTranscodingJobs),
+                                inRequest.testConfig == null ? 0
+                                        : inRequest.testConfig.processingDelayMs,
+                                TimeUnit.MILLISECONDS);
+                        mPendingTranscodingJobs.put(outjob.jobId, transcodingFuture);
+                    } catch (RejectedExecutionException e) {
+                        Log.e(TAG, "Failed to schedule transcoding job: " + e);
+                        return false;
+                    }
+
+                    return true;
+                }
+
+                @Override
+                public boolean cancelJob(int jobId) throws RemoteException {
+                    Log.d(TAG, "Mock client gets cancelJob " + jobId);
+                    // Cancels the job is still in the mPendingTranscodingJobs.
+                    if (mPendingTranscodingJobs.containsKey(jobId)) {
+                        // Cancel the future task for transcoding.
+                        mPendingTranscodingJobs.get(jobId).cancel(true);
+
+                        // Remove the job from the mPendingTranscodingJobs.
+                        mPendingTranscodingJobs.remove(jobId);
+                        return true;
+                    }
+                    return false;
+                }
+
+                @Override
+                public boolean getJobWithId(int jobId, TranscodingJobParcel job)
+                        throws RemoteException {
+                    // This will be implemented this if needed in the test.
+                    return true;
+                }
+
+                @Override
+                public void unregister() throws RemoteException {
+                    Log.d(TAG, "Mock client gets unregister");
+                    // This will be implemented this if needed in the test.
+                    mNumOfClients--;
+                }
+            };
+            mNumOfClients++;
+            return client;
+        }
+
+        @Override
+        public int getNumOfClients() throws RemoteException {
+            return mNumOfClients;
+        }
+    }
+
+    public MediaTranscodeManagerWithMockServiceTest() {
+        super("com.android.MediaTranscodeManagerWithMockServiceTest", MediaTranscodingTest.class);
+    }
+
+
+    private static Uri resourceToUri(Context context, int resId) {
+        Uri uri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+                .authority(context.getResources().getResourcePackageName(resId))
+                .appendPath(context.getResources().getResourceTypeName(resId))
+                .appendPath(context.getResources().getResourceEntryName(resId))
+                .build();
+        return uri;
+    }
+
+    private static Uri generateNewUri(Context context, String filename) {
+        File outFile = new File(context.getExternalCacheDir(), filename);
+        return Uri.fromFile(outFile);
+    }
+
+    // Generates a invalid uri which will let the mock service return transcoding failure.
+    private static Uri generateInvalidTranscodingUri(Context context) {
+        File outFile = new File(context.getExternalCacheDir(), "InvalidUri.mp4");
+        return Uri.fromFile(outFile);
+    }
+
+    /**
+     * Creates a MediaFormat with the basic set of values.
+     */
+    private static MediaFormat createMediaFormat() {
+        MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, WIDTH, HEIGHT);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+        return format;
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        Log.d(TAG, "setUp");
+        super.setUp();
+        mTranscodingService = new MockTranscodingService();
+        mContext = getInstrumentation().getContext();
+        mMediaTranscodeManager = MediaTranscodeManager.getInstance(mContext, mTranscodingService);
+        assertNotNull(mMediaTranscodeManager);
+
+        // Setup source HEVC file uri.
+        mSourceHEVCVideoUri = resourceToUri(mContext, R.raw.VideoOnlyHEVC);
+
+        // Setup destination file.
+        mDestinationUri = generateNewUri(mContext, "transcoded.mp4");
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Verify that setting null destination uri will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingRequestWithNullDestinationUri() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(mSourceHEVCVideoUri)
+                            .setDestinationUri(null)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setVideoTrackFormat(createMediaFormat())
+                            .build();
+        });
+    }
+
+    /**
+     * Verify that setting null source uri will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingRequestWithNullSourceUri() throws Exception {
+        assertThrows(IllegalArgumentException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(null)
+                            .setDestinationUri(mDestinationUri)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .build();
+        });
+    }
+
+    /**
+     * Verify that not setting source uri will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingRequestWithoutSourceUri() throws Exception {
+        assertThrows(UnsupportedOperationException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setDestinationUri(mDestinationUri)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setVideoTrackFormat(createMediaFormat())
+                            .build();
+        });
+    }
+
+    /**
+     * Verify that not setting destination uri will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingRequestWithoutDestinationUri() throws Exception {
+        assertThrows(UnsupportedOperationException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(mSourceHEVCVideoUri)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setVideoTrackFormat(createMediaFormat())
+                            .build();
+        });
+    }
+
+    /**
+     * Verify that setting image transcoding mode will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingRequestWithUnsupportedMode() throws Exception {
+        assertThrows(UnsupportedOperationException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(mSourceHEVCVideoUri)
+                            .setDestinationUri(mDestinationUri)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_IMAGE)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .setVideoTrackFormat(createMediaFormat())
+                            .build();
+        });
+    }
+
+    /**
+     * Verify that setting video transcoding without setting video format will throw exception.
+     */
+    @Test
+    public void testCreateTranscodingRequestWithoutVideoFormat() throws Exception {
+        assertThrows(UnsupportedOperationException.class, () -> {
+            TranscodingRequest request =
+                    new TranscodingRequest.Builder()
+                            .setSourceUri(mSourceHEVCVideoUri)
+                            .setDestinationUri(mDestinationUri)
+                            .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                            .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                            .build();
+        });
+    }
+
+    @Test
+    public void testTranscodingOneVideo() throws Exception {
+        Log.d(TAG, "Starting: testMediaTranscodeManager");
+
+        Semaphore transcodeCompleteSemaphore = new Semaphore(0);
+        TranscodingRequest request =
+                new TranscodingRequest.Builder()
+                        .setSourceUri(mSourceHEVCVideoUri)
+                        .setDestinationUri(mDestinationUri)
+                        .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+                        .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+                        .setVideoTrackFormat(createMediaFormat())
+                        .setProcessingDelayMs(300 /* delayMs */)
+                        .build();
+        Executor listenerExecutor = Executors.newSingleThreadExecutor();
+
+        TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
+                transcodingJob -> {
+                    Log.d(TAG, "Transcoding completed with result: ");
+                    transcodeCompleteSemaphore.release();
+                });
+        assertNotNull(job);
+
+        if (job != null) {
+            Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to complete.");
+            boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire(
+                    TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+            assertTrue("Transcode failed to complete in time.", finishedOnTime);
+        }
+    }
+
+}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTest.java
new file mode 100644
index 0000000..6f83bad
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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 com.android.mediatranscodingtest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.PowerManager;
+
+public class MediaTranscodingTest extends Activity {
+    private PowerManager.WakeLock mWakeLock = null;
+
+    public MediaTranscodingTest() {
+    }
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.surface_view);
+
+        //Acquire the full wake lock to keep the device up
+        PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "MediaTranscodingTest");
+        mWakeLock.acquire();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mWakeLock.release();
+    }
+}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
new file mode 100644
index 0000000..af0a754
--- /dev/null
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingTestRunner.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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 com.android.mediatranscodingtest;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation Test Runner for all MediaTranscoding tests.
+ *
+ * Running all tests:
+ *
+ * adb shell am instrument \
+ *  -w com.android.mediatranscodingtest/.MediaTranscodingTestRunner
+ */
+
+public class MediaTranscodingTestRunner extends InstrumentationTestRunner {
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(MediaTranscodeManagerWithMockServiceTest.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return MediaTranscodingTestRunner.class.getClassLoader();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    }
+}