Merge "Calculating jank from the timestamps."
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 3887c1d..4b7229d 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -132,16 +132,14 @@
 CTS_TEST_CASES := $(call cts-get-lib-paths,$(cts_host_libraries)) \
 		$(call cts-get-package-paths,$(cts_test_packages)) \
 		$(call cts-get-native-paths,$(cts_native_exes)) \
-		$(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
-		$(call cts-get-ui-lib-paths,$(PTS_UI_TESTS))
+		$(call cts-get-ui-lib-paths,$(cts_ui_tests))
 
 # All the XMLs that will end up under the repository/testcases
 # and that need to be created before making the final CTS distribution.
 CTS_TEST_XMLS := $(call cts-get-test-xmls,$(cts_host_libraries)) \
 		$(call cts-get-test-xmls,$(cts_test_packages)) \
 		$(call cts-get-test-xmls,$(cts_native_exes)) \
-		$(call cts-get-test-xmls,$(cts_ui_tests)) \
-		$(call cts-get-test-xmls,$(PTS_UI_TESTS))
+		$(call cts-get-test-xmls,$(cts_ui_tests))
 
 
 # The following files will be placed in the tools directory of the CTS distribution
diff --git a/suite/pts/PtsBenchmarkingList.mk b/suite/pts/PtsBenchmarkingList.mk
index 0aba241..ab79bca 100644
--- a/suite/pts/PtsBenchmarkingList.mk
+++ b/suite/pts/PtsBenchmarkingList.mk
@@ -34,7 +34,5 @@
 
 PTS_HOST_CASES := \
     PtsHostBootup \
-    PtsHostUi
-
-PTS_UI_TESTS := \
+    PtsHostUi \
     PtsHostJank
diff --git a/suite/pts/deviceTests/opengl/AndroidManifest.xml b/suite/pts/deviceTests/opengl/AndroidManifest.xml
index 86e21e2..6aa50cf 100644
--- a/suite/pts/deviceTests/opengl/AndroidManifest.xml
+++ b/suite/pts/deviceTests/opengl/AndroidManifest.xml
@@ -30,7 +30,8 @@
         </activity>
         <activity
             android:name="com.android.pts.opengl.reference.GLReferenceActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" >
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
diff --git a/suite/pts/deviceTests/opengl/assets/texture/arc.png b/suite/pts/deviceTests/opengl/assets/texture/arc.png
index 5a68acd..f95e7a0 100644
--- a/suite/pts/deviceTests/opengl/assets/texture/arc.png
+++ b/suite/pts/deviceTests/opengl/assets/texture/arc.png
Binary files differ
diff --git a/suite/pts/deviceTests/opengl/assets/texture/fish.png b/suite/pts/deviceTests/opengl/assets/texture/fish.png
index 6f62650..fdf1e2c 100644
--- a/suite/pts/deviceTests/opengl/assets/texture/fish.png
+++ b/suite/pts/deviceTests/opengl/assets/texture/fish.png
Binary files differ
diff --git a/suite/pts/deviceTests/opengl/assets/texture/water1.png b/suite/pts/deviceTests/opengl/assets/texture/water1.png
index 2fdefa1..96f4e62 100644
--- a/suite/pts/deviceTests/opengl/assets/texture/water1.png
+++ b/suite/pts/deviceTests/opengl/assets/texture/water1.png
Binary files differ
diff --git a/suite/pts/deviceTests/opengl/assets/texture/water2.png b/suite/pts/deviceTests/opengl/assets/texture/water2.png
index 7050e3d..92eebf9 100644
--- a/suite/pts/deviceTests/opengl/assets/texture/water2.png
+++ b/suite/pts/deviceTests/opengl/assets/texture/water2.png
Binary files differ
diff --git a/suite/pts/deviceTests/opengl/assets/vertex/basic b/suite/pts/deviceTests/opengl/assets/vertex/basic
index be831d0..88ba2ba 100644
--- a/suite/pts/deviceTests/opengl/assets/vertex/basic
+++ b/suite/pts/deviceTests/opengl/assets/vertex/basic
@@ -11,6 +11,7 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
+precision mediump float;
 attribute vec4 a_Position;
 attribute vec2 a_TexCoordinate;
 varying vec2 v_TexCoordinate;
diff --git a/suite/pts/deviceTests/opengl/assets/vertex/blur b/suite/pts/deviceTests/opengl/assets/vertex/blur
index ffb2bf0..ffd6a86 100644
--- a/suite/pts/deviceTests/opengl/assets/vertex/blur
+++ b/suite/pts/deviceTests/opengl/assets/vertex/blur
@@ -11,6 +11,7 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
+precision mediump float;
 attribute vec4 a_Position;
 attribute vec2 a_TexCoordinate;
 varying vec2 v_TexCoordinate;
diff --git a/suite/pts/deviceTests/opengl/assets/vertex/perspective b/suite/pts/deviceTests/opengl/assets/vertex/perspective
index 6889c72..14c8c30 100644
--- a/suite/pts/deviceTests/opengl/assets/vertex/perspective
+++ b/suite/pts/deviceTests/opengl/assets/vertex/perspective
@@ -11,6 +11,7 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
+precision mediump float;
 uniform mat4 u_MVPMatrix;
 uniform mat4 u_MVMatrix;
 attribute vec4 a_Position;
diff --git a/suite/pts/deviceTests/opengl/assets/vertex/water b/suite/pts/deviceTests/opengl/assets/vertex/water
index 05174e4..dc09a99 100644
--- a/suite/pts/deviceTests/opengl/assets/vertex/water
+++ b/suite/pts/deviceTests/opengl/assets/vertex/water
@@ -11,6 +11,7 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
+precision mediump float;
 uniform mat4 u_MVPMatrix;
 uniform mat4 u_MVMatrix;
 attribute vec4 a_Position;
diff --git a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/Benchmark.java b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/BenchmarkName.java
similarity index 96%
rename from suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/Benchmark.java
rename to suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/BenchmarkName.java
index d61f45d..e9f219b 100644
--- a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/Benchmark.java
+++ b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/BenchmarkName.java
@@ -16,7 +16,7 @@
 /**
  * Represents the different primitive benchmarks.
  */
-public enum Benchmark {
+public enum BenchmarkName {
     FullPipeline,
     PixelOutput,
     ShaderPerf,
diff --git a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveActivity.java b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveActivity.java
index 4db037c..377e851 100644
--- a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveActivity.java
+++ b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveActivity.java
@@ -39,7 +39,7 @@
     private CountDownLatch mStartSignal = new CountDownLatch(1);
     private Semaphore mSemaphore = new Semaphore(0);
 
-    private Benchmark mBenchmark;
+    private BenchmarkName mBenchmark;
     private boolean mOffscreen;
     private int mNumFrames;
     private int mNumIterations;
@@ -51,8 +51,8 @@
         super.onCreate(data);
         System.loadLibrary("ptsopengl_jni");
         Intent intent = getIntent();
-        mBenchmark = Benchmark.valueOf(
-                intent.getStringExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME));
+        mBenchmark = BenchmarkName.valueOf(intent.getStringExtra(
+                GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME));
         mOffscreen = intent.getBooleanExtra(GLActivityIntentKeys.INTENT_EXTRA_OFFSCREEN, false);
         mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 0);
         mNumIterations = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, 0);
diff --git a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveBenchmark.java b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveBenchmark.java
index 3efba20..1f40c7a 100644
--- a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveBenchmark.java
+++ b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/primitive/GLPrimitiveBenchmark.java
@@ -41,7 +41,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testFullPipelineOffscreen() throws Exception {
-        runBenchmark(Benchmark.FullPipeline, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.FullPipeline, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -49,7 +49,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testFullPipelineOnscreen() throws Exception {
-        runBenchmark(Benchmark.FullPipeline, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.FullPipeline, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -57,7 +57,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testPixelOutputOffscreen() throws Exception {
-        runBenchmark(Benchmark.PixelOutput, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.PixelOutput, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -65,7 +65,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testPixelOutputOnscreen() throws Exception {
-        runBenchmark(Benchmark.PixelOutput, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.PixelOutput, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -73,7 +73,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testShaderPerfOffscreen() throws Exception {
-        runBenchmark(Benchmark.ShaderPerf, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.ShaderPerf, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -81,7 +81,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testShaderPerfOnscreen() throws Exception {
-        runBenchmark(Benchmark.ShaderPerf, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.ShaderPerf, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -89,7 +89,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testContextSwitchOffscreen() throws Exception {
-        runBenchmark(Benchmark.ContextSwitch, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.ContextSwitch, true, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -97,7 +97,7 @@
      */
     @TimeoutReq(minutes = 100)
     public void testContextSwitchOnscreen() throws Exception {
-        runBenchmark(Benchmark.ContextSwitch, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
+        runBenchmark(BenchmarkName.ContextSwitch, false, NUM_FRAMES, NUM_ITERATIONS, TIMEOUT);
     }
 
     /**
@@ -110,9 +110,8 @@
      * @param timeout The milliseconds to wait for an iteration of the benchmark before timing out.
      * @throws Exception If the benchmark could not be run.
      */
-    private void runBenchmark(
-            Benchmark benchmark, boolean offscreen, int numFrames, int numIterations, int timeout)
-            throws Exception {
+    private void runBenchmark(BenchmarkName benchmark, boolean offscreen, int numFrames,
+            int numIterations, int timeout) throws Exception {
         String benchmarkName = benchmark.toString();
         Intent intent = new Intent();
         intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME, benchmarkName);
diff --git a/suite/pts/hostTests/jank/Android.mk b/suite/pts/hostTests/jank/Android.mk
index 936a850..efd0bd8 100644
--- a/suite/pts/hostTests/jank/Android.mk
+++ b/suite/pts/hostTests/jank/Android.mk
@@ -17,19 +17,16 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_MODULE := PtsHostJank
-LOCAL_JAVA_LIBRARIES := uiautomator.core
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.uiautomator.platform.common
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_CTS_TEST_APK := PtsDeviceJankApp
-LOCAL_CTS_TEST_APP_PACKAGE := com.android.pts.opengl
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt ddmlib-prebuilt ptscommonutilhost
+
 LOCAL_CTS_TEST_PACKAGE := com.android.pts.jank
 
-include $(BUILD_CTS_UI_JAVA_LIBRARY)
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APK using its own makefile, and any other CTS-related packages
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/pts/hostTests/jank/app/Android.mk b/suite/pts/hostTests/jank/app/Android.mk
index 257c552..5ef1a92 100644
--- a/suite/pts/hostTests/jank/app/Android.mk
+++ b/suite/pts/hostTests/jank/app/Android.mk
@@ -27,8 +27,11 @@
 LOCAL_JNI_SHARED_LIBRARIES := libptsopengl_jni
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-# add the src of the reference benchmark
-LOCAL_SRC_FILES += $(call all-java-files-under, ../../../deviceTests/opengl/src)
+# add the src of the benchmark, but filter out the tests
+BENCHMARK_SRC := $(call all-java-files-under, ../../../deviceTests/opengl/src)
+LOCAL_SRC_FILES += $(filter-out %Benchmark.java, $(BENCHMARK_SRC))
+
+#$(info $(LOCAL_SRC_FILES))
 
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/../../../deviceTests/opengl/assets
 
diff --git a/suite/pts/hostTests/jank/app/AndroidManifest.xml b/suite/pts/hostTests/jank/app/AndroidManifest.xml
index e75fd7a..8c2e577 100644
--- a/suite/pts/hostTests/jank/app/AndroidManifest.xml
+++ b/suite/pts/hostTests/jank/app/AndroidManifest.xml
@@ -25,20 +25,22 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
     <application>
+        <uses-library android:name="android.test.runner" />
         <activity
-            android:name=".JankActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" >
+            android:name="com.android.pts.opengl.primitive.GLPrimitiveActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-        <activity
-            android:name="com.android.pts.opengl.reference.GLGameActivity"
-            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
-            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
-        </activity>
     </application>
 
+    <instrumentation
+        android:name="android.test.InstrumentationCtsTestRunner"
+        android:label="Jank Test"
+        android:targetPackage="com.android.pts.jank" />
+
 </manifest>
\ No newline at end of file
diff --git a/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankActivity.java b/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankActivity.java
deleted file mode 100644
index 2c37922..0000000
--- a/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankActivity.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2013 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.pts.jank;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-
-import com.android.pts.opengl.reference.GLGameActivity;
-
-public class JankActivity extends Activity {
-    static final String TAG = "JankActivity";
-
-    private final static int GAME_ACTIVITY_CODE = 1;
-
-    public void onCreate(Bundle data) {
-        super.onCreate(data);
-        // Sets the view to be a big button. This is pressed by uiautomator when SurfaceFlinger's
-        // buffers have been cleared.
-        final Button start = new Button(this);
-        start.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final Intent intent = new Intent(JankActivity.this, GLGameActivity.class);
-                startActivityForResult(intent, GAME_ACTIVITY_CODE);
-            }
-        });
-        setContentView(start);
-    }
-
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == GAME_ACTIVITY_CODE) {
-            finish();
-        }
-    }
-}
diff --git a/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankTest.java b/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankTest.java
new file mode 100644
index 0000000..84caa63
--- /dev/null
+++ b/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 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.pts.jank;
+
+import com.android.pts.opengl.GLActivityIntentKeys;
+import com.android.pts.opengl.primitive.BenchmarkName;
+import com.android.pts.opengl.primitive.GLPrimitiveActivity;
+import com.android.pts.util.PtsActivityInstrumentationTestCase2;
+
+import android.content.Intent;
+
+public class JankTest extends PtsActivityInstrumentationTestCase2<GLPrimitiveActivity> {
+
+    public JankTest() {
+        super(GLPrimitiveActivity.class);
+    }
+
+    /**
+     * Runs the full OpenGL ES 2.0 pipeline test.
+     */
+    public void testFullPipeline() throws Exception {
+        runBenchmark(BenchmarkName.FullPipeline);
+    }
+
+    /**
+     * Runs the pixel output test.
+     */
+    public void testPixelOutput() throws Exception {
+        runBenchmark(BenchmarkName.PixelOutput);
+    }
+
+    /**
+     * Runs the shader performance test.
+     */
+    public void testShaderPerf() throws Exception {
+        runBenchmark(BenchmarkName.ShaderPerf);
+    }
+
+    /**
+     * Runs the context switch overhead test.
+     */
+    public void testContextSwitch() throws Exception {
+        runBenchmark(BenchmarkName.ContextSwitch);
+    }
+
+    /**
+     * Runs the benchhmark for jank test.
+     */
+    public void runBenchmark(BenchmarkName benchmark) throws Exception {
+        Intent intent = new Intent();
+        String benchmarkName = benchmark.toString();
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_BENCHMARK_NAME, benchmarkName);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_OFFSCREEN, false);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 200);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, 1);
+        intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 50000);
+        GLPrimitiveActivity activity = null;
+        setActivityIntent(intent);
+        try {
+            activity = getActivity();
+            activity.waitForCompletion();
+        } finally {
+            if (activity != null) {
+                activity.finish();
+            }
+        }
+    }
+}
diff --git a/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java b/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java
index b12908a..85a8f5e 100644
--- a/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java
+++ b/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java
@@ -13,55 +13,184 @@
  */
 package com.android.pts.jank;
 
-import android.util.Log;
-
-import com.android.uiautomator.core.UiDevice;
-import com.android.uiautomator.testrunner.UiAutomatorTestCase;
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.pts.util.HostReportLog;
+import com.android.pts.util.ReportLog;
+import com.android.pts.util.ResultType;
+import com.android.pts.util.ResultUnit;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
 
 import java.io.BufferedReader;
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.InputStreamReader;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
 
-import junit.framework.Assert;
+public class PtsHostJankTest extends DeviceTestCase implements IBuildReceiver {
 
-public class PtsHostJankTest extends UiAutomatorTestCase {
-    private static final String TAG = PtsHostJankTest.class.getSimpleName();
-    private static final int NUM_ITERATIONS = 5;
-    private static final String APP_WINDOW_NAME =
-            "SurfaceView";
-    private static final String LAUNCH_COMMAND =
-            "am start -a android.intent.action.MAIN -n com.android.pts.jank/.JankActivity -W";
+    private static final String TAG = "PtsHostJankTest";
+    private static final String CTS_RUNNER = "android.test.InstrumentationCtsTestRunner";
+    private static final String APP_WINDOW_NAME = "SurfaceView";
+    private static final String PACKAGE = "com.android.pts.jank";
+    private static final String APK = "PtsDeviceJankApp.apk";
     private static final String CLEAR_BUFFER_CMD =
-            "dumpsys SurfaceFlinger --latency-clear " + APP_WINDOW_NAME;
+            "adb -s %s shell dumpsys SurfaceFlinger --latency-clear %s";
     private static final String FRAME_LATENCY_CMD =
-            "dumpsys SurfaceFlinger --latency " + APP_WINDOW_NAME;
+            "adb -s %s shell dumpsys SurfaceFlinger --latency %s";
     private static final long PENDING_FENCE_TIMESTAMP = (1L << 63) - 1;
+    private static final double MILLISECOND = 1E3;
+    private static final int REQ_NUM_DELTAS = 100;
 
-    public void testGLReferenceBenchmark() throws Exception {
-        // Launch the app.
-        runShellCommand(LAUNCH_COMMAND);
+    private ArrayList<Double> mTimestamps = new ArrayList<Double>();
+    private double mRefreshPeriod;
+    private volatile int mNumDeltas = 0;
+    private volatile int mJankNumber = 0;
+    private volatile int mTotalJanks = 0;
+    private CtsBuildHelper mBuild;
+    private ITestDevice mDevice;
 
-        // Wait till the device is idle.
-        UiDevice device = UiDevice.getInstance();
-        device.waitForIdle();
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+    }
 
-        // This is batch is important because this is where jank caused by loading textures and
-        // meshes will be encountered. It also needs to be separated from the loop so that the
-        // start button can be pressed.
-        clearBuffer();
-        // Touch screen, which starts the rendering.
-        int width = device.getDisplayWidth();
-        int height = device.getDisplayHeight();
-        device.click(width / 2, height / 2);
-        Thread.sleep(2000);
-        dumpBuffer();
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        mDevice.uninstallPackage(PACKAGE);
+        File app = mBuild.getTestApp(APK);
+        mDevice.installPackage(app, false);
+    }
 
-        // Loop because SurfaceFlinger's buffer is small.
-        for (int i = 0; i < NUM_ITERATIONS; i++) {
-            clearBuffer();
-            Thread.sleep(2000);
-            dumpBuffer();
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDevice.uninstallPackage(PACKAGE);
+        super.tearDown();
+    }
+
+    public void testFullPipeline() throws Exception {
+        runGLPrimitiveBenchmark("testFullPipeline");
+    }
+
+    public void testPixelOutput() throws Exception {
+        runGLPrimitiveBenchmark("testPixelOutput");
+    }
+
+    public void testShaderPerf() throws Exception {
+        runGLPrimitiveBenchmark("testShaderPerf");
+    }
+
+    public void testContextSwitch() throws Exception {
+        runGLPrimitiveBenchmark("testContextSwitch");
+    }
+
+    public void runGLPrimitiveBenchmark(String benchmark) throws Exception {
+        // Collect timestamps.
+        final TimestampCollector worker = new TimestampCollector();
+        worker.start();
+
+        // Start the benchmark.
+        RemoteAndroidTestRunner testRunner =
+                new RemoteAndroidTestRunner(PACKAGE, CTS_RUNNER, mDevice.getIDevice());
+        testRunner.setMethodName("com.android.pts.jank.JankTest", benchmark);
+        CollectingTestListener listener = new CollectingTestListener();
+        mDevice.runInstrumentationTests(testRunner, listener);
+
+        // Wait for the worker.
+        worker.finish();
+
+        TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new Exception(result.getRunFailureMessage());
+        }
+
+        assertFalse("Couldn't get enough timestamps", needMoreDeltas());
+
+        // Create and deliver the report.
+        HostReportLog report = new HostReportLog(
+                mDevice.getSerialNumber(), PtsHostJankTest.class.getName() + "#" + benchmark);
+        report.printValue(
+                "Number of Janks", mJankNumber, ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        report.printValue("Total Janks", mTotalJanks, ResultType.LOWER_BETTER, ResultUnit.COUNT);
+        double jankiness = ((double) mJankNumber / mNumDeltas) * 100.0;
+        report.printSummary(
+                "Jankiness Percentage", jankiness, ResultType.LOWER_BETTER, ResultUnit.SCORE);
+        report.deliverReportToHost();
+    }
+
+    private boolean needMoreDeltas() {
+        return mNumDeltas < REQ_NUM_DELTAS;
+    }
+
+    private void calcJank() {
+        final int numTimestamps = mTimestamps.size();
+        if (numTimestamps > 2) {
+            final int numIntervals = numTimestamps - 1;
+            double[] intervals = new double[numIntervals];
+            for (int i = 0; i < numIntervals; i++) {
+                intervals[i] = mTimestamps.get(i + 1) - mTimestamps.get(i);
+            }
+            final int numDeltas = Math.min(numIntervals - 1, REQ_NUM_DELTAS - mNumDeltas);
+            for (int i = 0; i < numDeltas; i++) {
+                double delta = intervals[i + 1] - intervals[i];
+                double normalizedDelta = delta / mRefreshPeriod;
+                // This makes delay over 1.5 * frameIntervalNomial a jank.
+                // Note that too big delay is not excluded here as there should be no pause.
+                int jankiness = (int) Math.round(Math.max(normalizedDelta, 0.0));
+                if (jankiness > 0) {
+                    mJankNumber++;
+                    Log.i(TAG, "Jank at frame " + (mNumDeltas + i));
+                }
+                mTotalJanks += jankiness;
+            }
+            mNumDeltas += numDeltas;
+        }
+        mTimestamps.clear();
+    }
+
+    private class TimestampCollector extends Thread {
+        private volatile Exception mException = null;
+        private volatile boolean mRunning = true;
+
+        public void run() {
+            try {
+                // Loop because SurfaceFlinger's buffer is small.
+                while (mRunning) {
+                    clearBuffer();
+                    Thread.sleep(2000);
+                    dumpBuffer();
+                    calcJank();
+                    // Keep going till we have enough deltas
+                    mRunning = needMoreDeltas();
+                }
+            } catch (Exception e) {
+                mException = e;
+            }
+        }
+
+        public void finish() throws Exception {
+            mRunning = false;
+            try {
+                join(20000);// Wait 20s for thread to join
+            } catch (InterruptedException e) {
+                // Nobody cares
+            }
+            // If there was an error, throw it.
+            if (mException != null) {
+                throw mException;
+            }
         }
     }
 
@@ -69,7 +198,8 @@
         // Clear SurfaceFlinger latency buffer.
         Process p = null;
         try {
-            p = runShellCommand(CLEAR_BUFFER_CMD);
+            p = runShellCommand(
+                    String.format(CLEAR_BUFFER_CMD, mDevice.getSerialNumber(), APP_WINDOW_NAME));
         } finally {
             if (p != null) {
                 p.destroy();
@@ -82,16 +212,19 @@
         // Dump SurfaceFlinger latency buffer.
         Process p = null;
         try {
-            p = runShellCommand(FRAME_LATENCY_CMD);
+            p = runShellCommand(
+                    String.format(FRAME_LATENCY_CMD, mDevice.getSerialNumber(), APP_WINDOW_NAME));
             BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
             String line = reader.readLine();
-            long refreshPeriod = Long.parseLong(line.trim());
-            while ((line = reader.readLine()) != null) {
-                String[] values = line.split("\\s+");
-                if (values.length == 3) {
-                    long timestamp = Long.parseLong(values[1]);
-                    if (timestamp != PENDING_FENCE_TIMESTAMP && timestamp != 0) {
-                        Log.i(TAG, "Timestamp: " + timestamp);
+            if (line != null) {
+                mRefreshPeriod = Long.parseLong(line.trim()) / 1e6;// Convert from ns to ms
+                while ((line = reader.readLine()) != null) {
+                    String[] values = line.split("\\s+");
+                    if (values.length == 3) {
+                        long timestamp = Long.parseLong(values[1]);
+                        if (timestamp != PENDING_FENCE_TIMESTAMP && timestamp != 0) {
+                            mTimestamps.add(timestamp / 1e6);// Convert from ns to ms
+                        }
                     }
                 }
             }