aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--infra/cts/README.md12
-rw-r--r--infra/cts/run_testlab.go245
-rw-r--r--platform_tools/android/apps/skqp/build.gradle6
-rw-r--r--platform_tools/android/apps/skqp/src/main/AndroidManifest.xml25
-rw-r--r--platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/MainActivity.java21
-rw-r--r--platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQP.java88
-rw-r--r--platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPActivity.java35
-rw-r--r--platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPRunner.java73
-rw-r--r--platform_tools/android/apps/skqp/src/main/res/layout/activity_main.xml37
-rw-r--r--platform_tools/android/apps/skqp/src/main/res/layout/activity_skqp.xml25
-rw-r--r--platform_tools/android/apps/skqp/src/main/res/layout/content_skqp.xml19
-rw-r--r--platform_tools/android/apps/skqp/src/main/res/values/colors.xml6
-rw-r--r--platform_tools/android/apps/skqp/src/main/res/values/strings.xml4
-rw-r--r--platform_tools/android/apps/skqp/src/main/res/values/styles.xml20
-rw-r--r--tools/skqp/jni/org_skia_skqp_SkQPRunner.cpp16
15 files changed, 566 insertions, 66 deletions
diff --git a/infra/cts/README.md b/infra/cts/README.md
new file mode 100644
index 0000000000..d4e8c2c0a2
--- /dev/null
+++ b/infra/cts/README.md
@@ -0,0 +1,12 @@
+Running CTS on Firebase Testlab
+===============================
+
+The run_testlab.go script uploads a given apk to Firebase Testlab and
+runs them on the list of devices whitelisted in the script.
+See the WHITELIST\_DEV\_IDS variable.
+
+To run 'skqpapp.apk' on Testlab run the following command:
+
+```
+ $ go run run_testlab.go --logtostderr --service_account_file=service-account.json skqpapp.apk
+```
diff --git a/infra/cts/run_testlab.go b/infra/cts/run_testlab.go
new file mode 100644
index 0000000000..cf88c30cc9
--- /dev/null
+++ b/infra/cts/run_testlab.go
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "net/http"
+ "os"
+ "os/exec"
+ "sort"
+ "strings"
+ "syscall"
+ "time"
+
+ gstorage "google.golang.org/api/storage/v1"
+
+ "go.skia.org/infra/go/auth"
+ "go.skia.org/infra/go/common"
+ "go.skia.org/infra/go/sklog"
+ "go.skia.org/infra/go/util"
+ "go.skia.org/infra/golden/go/tsuite"
+)
+
+// TODO(stephana): Convert the hard coded whitelist to a command line flag that
+// loads a file with the whitelisted devices and versions. Make sure to include
+// human readable names for the devices.
+
+var (
+ // WHITELIST_DEV_IDS contains a mapping from the device id to the list of
+ // Android API versions that we should run agains. Usually this will be the
+ // latest version. To see available devices and version run with
+ // --dryrun flag or run '$ gcloud firebase test android models list'
+
+ WHITELIST_DEV_IDS = map[string][]string{
+ "A0001": {"22"},
+ // "E5803": {"22"}, deprecated
+ // "F5121": {"23"}, deprecated
+ "G8142": {"25"},
+ "HWMHA": {"24"},
+ "SH-04H": {"23"},
+ "athene": {"23"},
+ "athene_f": {"23"},
+ "hammerhead": {"23"},
+ "harpia": {"23"},
+ "hero2lte": {"23"},
+ "herolte": {"24v"},
+ "j1acevelte": {"22"},
+ "j5lte": {"23"},
+ "j7xelte": {"23"},
+ "lucye": {"24"},
+ "mako": {"22"},
+ "osprey_umts": {"22"},
+ "p1": {"22"},
+ "sailfish": {"26"},
+ "shamu": {"23"},
+ "trelte": {"22"},
+ "zeroflte": {"22"},
+ "zerolte": {"22"},
+ }
+)
+
+const (
+ META_DATA_FILENAME = "meta.json"
+)
+
+// Command line flags.
+var (
+ serviceAccountFile = flag.String("service_account_file", "", "Credentials file for service account.")
+ dryRun = flag.Bool("dryrun", false, "Print out the command and quit without triggering tests.")
+)
+
+const (
+ RUN_TESTS_TEMPLATE = `gcloud beta firebase test android run
+ --type=game-loop
+ --app=%s
+ --results-bucket=%s
+ --results-dir=%s
+ --directories-to-pull=/sdcard/Android/data/org.skia.skqpapp
+ %s
+`
+ MODEL_VERSION_TMPL = "--device model=%s,version=%s,orientation=portrait"
+ RESULT_BUCKET = "skia-firebase-test-lab"
+ RESULT_DIR_TMPL = "testruns/%s/%s"
+ RUN_ID_TMPL = "testrun-%d"
+ CMD_AVAILABE_DEVICES = "gcloud firebase test android models list --format json"
+)
+
+func main() {
+ common.Init()
+
+ // Get the apk.
+ args := flag.Args()
+ apk_path := args[0]
+
+ // Make sure we can get the service account client.
+ client, err := auth.NewJWTServiceAccountClient("", *serviceAccountFile, nil, gstorage.CloudPlatformScope, "https://www.googleapis.com/auth/userinfo.email")
+ if err != nil {
+ sklog.Fatalf("Failed to authenticate service account: %s. Run 'get_service_account' to obtain a service account file.", err)
+ }
+
+ // Get list of all available devices.
+ devices, ignoredDevices, err := getAvailableDevices(WHITELIST_DEV_IDS)
+ if err != nil {
+ sklog.Fatalf("Unable to retrieve available devices: %s", err)
+ }
+ sklog.Infof("---")
+ sklog.Infof("Selected devices:")
+ logDevices(devices)
+
+ if err := runTests(apk_path, devices, ignoredDevices, client, *dryRun); err != nil {
+ sklog.Fatalf("Error triggering tests on Firebase: %s", err)
+ }
+}
+
+// getAvailableDevices is given a whitelist. It queries Firebase Testlab for all
+// available devices and then returns a list of devices to be tested and the list
+// of ignored devices.
+func getAvailableDevices(whiteList map[string][]string) ([]*tsuite.DeviceVersions, []*tsuite.DeviceVersions, error) {
+ // Get the list of all devices in JSON format from Firebase testlab.
+ var buf bytes.Buffer
+ cmd := parseCommand(CMD_AVAILABE_DEVICES)
+ cmd.Stdout = &buf
+ cmd.Stderr = os.Stdout
+ if err := cmd.Run(); err != nil {
+ return nil, nil, err
+ }
+
+ // Unmarshal the result.
+ foundDevices := []*tsuite.FirebaseDevice{}
+ bufBytes := buf.Bytes()
+ if err := json.Unmarshal(bufBytes, &foundDevices); err != nil {
+ return nil, nil, sklog.FmtErrorf("Unmarshal of device information failed: %s \nJSON Input: %s\n", err, string(bufBytes))
+ }
+
+ // iterate over the available devices and partition them.
+ allDevices := make([]*tsuite.DeviceVersions, 0, len(foundDevices))
+ ret := make([]*tsuite.DeviceVersions, 0, len(foundDevices))
+ ignored := make([]*tsuite.DeviceVersions, 0, len(foundDevices))
+ for _, dev := range foundDevices {
+ // Filter out all the virtual devices.
+ if dev.Form == "PHYSICAL" {
+ // Only include devices that are on the whitelist and have versions defined.
+ if foundVersions, ok := whiteList[dev.ID]; ok && (len(foundVersions) > 0) {
+ versionSet := util.NewStringSet(dev.VersionIDs)
+ reqVersions := util.NewStringSet(foundVersions)
+ whiteListVersions := versionSet.Intersect(reqVersions).Keys()
+ ignoredVersions := versionSet.Complement(reqVersions).Keys()
+ sort.Strings(whiteListVersions)
+ sort.Strings(ignoredVersions)
+ ret = append(ret, &tsuite.DeviceVersions{Device: dev, Versions: whiteListVersions})
+ ignored = append(ignored, &tsuite.DeviceVersions{Device: dev, Versions: ignoredVersions})
+ } else {
+ ignored = append(ignored, &tsuite.DeviceVersions{Device: dev, Versions: dev.VersionIDs})
+ }
+ allDevices = append(allDevices, &tsuite.DeviceVersions{Device: dev, Versions: dev.VersionIDs})
+ }
+ }
+
+ sklog.Infof("All devices:")
+ logDevices(allDevices)
+
+ return ret, ignored, nil
+}
+
+// runTests runs the given apk on the given list of devices.
+func runTests(apk_path string, devices, ignoredDevices []*tsuite.DeviceVersions, client *http.Client, dryRun bool) error {
+ // Get the model-version we want to test. Assume on average each model has 5 supported versions.
+ modelSelectors := make([]string, 0, len(devices)*5)
+ for _, devRec := range devices {
+ for _, version := range devRec.Versions {
+ modelSelectors = append(modelSelectors, fmt.Sprintf(MODEL_VERSION_TMPL, devRec.Device.ID, version))
+ }
+ }
+
+ now := time.Now()
+ nowMs := now.UnixNano() / int64(time.Millisecond)
+ runID := fmt.Sprintf(RUN_ID_TMPL, nowMs)
+ resultsDir := fmt.Sprintf(RESULT_DIR_TMPL, now.Format("2006/01/02/15"), runID)
+ cmdStr := fmt.Sprintf(RUN_TESTS_TEMPLATE, apk_path, RESULT_BUCKET, resultsDir, strings.Join(modelSelectors, "\n"))
+ cmdStr = strings.TrimSpace(strings.Replace(cmdStr, "\n", " ", -1))
+
+ // Run the command.
+ cmd := parseCommand(cmdStr)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stdout
+ exitCode := 0
+
+ if dryRun {
+ fmt.Printf("[dry run]: Would have run this command: %s\n", cmdStr)
+ return nil
+ }
+
+ if err := cmd.Run(); err != nil {
+ // Get the exit code.
+ if exitError, ok := err.(*exec.ExitError); ok {
+ ws := exitError.Sys().(syscall.WaitStatus)
+ exitCode = ws.ExitStatus()
+ }
+ sklog.Errorf("Error running tests: %s", err)
+ sklog.Errorf("Exit code: %d", exitCode)
+
+ // Exit code 10 means triggering on Testlab succeeded, but but some of the
+ // runs on devices failed. We consider it a success for this script.
+ if exitCode != 10 {
+ return err
+ }
+ }
+
+ // Store the result in a meta json file.
+ meta := &tsuite.TestRunMeta{
+ ID: runID,
+ TS: nowMs,
+ Devices: devices,
+ IgnoredDevices: ignoredDevices,
+ ExitCode: exitCode,
+ }
+
+ meta.WriteToGCS(RESULT_BUCKET, resultsDir+"/"+META_DATA_FILENAME, client)
+ return nil
+}
+
+// logDevices logs the given list of devices.
+func logDevices(devices []*tsuite.DeviceVersions) {
+ sklog.Infof("Found %d devices.", len(devices))
+ for _, dev := range devices {
+ sklog.Infof("%-15s %-30s %v / %v", dev.Device.ID, dev.Device.Name, dev.Device.VersionIDs, dev.Versions)
+ }
+}
+
+// parseCommad parses a command line and wraps it in an exec.Command instance.
+func parseCommand(cmdStr string) *exec.Cmd {
+ cmdArgs := strings.Split(strings.TrimSpace(cmdStr), " ")
+ for idx := range cmdArgs {
+ cmdArgs[idx] = strings.TrimSpace(cmdArgs[idx])
+ }
+ return exec.Command(cmdArgs[0], cmdArgs[1:]...)
+}
diff --git a/platform_tools/android/apps/skqp/build.gradle b/platform_tools/android/apps/skqp/build.gradle
index 0a883ca869..67a89e52af 100644
--- a/platform_tools/android/apps/skqp/build.gradle
+++ b/platform_tools/android/apps/skqp/build.gradle
@@ -7,13 +7,13 @@
apply plugin: 'com.android.application'
dependencies {
- compile 'com.android.support:support-annotations:24.0.0'
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
+ compile 'com.android.support:design:26.+'
compile 'com.android.support.test:runner:0.5'
- compile group: 'junit', name: 'junit', version: '4.+'
}
android {
- compileSdkVersion 23
+ compileSdkVersion 26
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "org.skia.skqp"
diff --git a/platform_tools/android/apps/skqp/src/main/AndroidManifest.xml b/platform_tools/android/apps/skqp/src/main/AndroidManifest.xml
index 30028fb436..b080286f2f 100644
--- a/platform_tools/android/apps/skqp/src/main/AndroidManifest.xml
+++ b/platform_tools/android/apps/skqp/src/main/AndroidManifest.xml
@@ -3,7 +3,30 @@
package="org.skia.skqp"
android:versionCode="1"
android:versionName="1.0">
- <application><uses-library android:name="android.test.runner" /></application>
+ <application
+ android:allowBackup="false"
+ android:theme="@style/AppTheme"
+ android:label="SkQP"
+ android:debuggable="true">
+
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".SkQPActivity"
+ android:label="@string/title_activity_skqp"
+ android:theme="@style/AppTheme.NoActionBar">
+ <intent-filter>
+ <action android:name="com.google.intent.action.TEST_LOOP"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="application/javascript"/>
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="org.skia.skqp"></instrumentation>
</manifest>
diff --git a/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/MainActivity.java b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/MainActivity.java
new file mode 100644
index 0000000000..43320077ce
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/MainActivity.java
@@ -0,0 +1,21 @@
+package org.skia.skqp;
+
+import android.content.Intent;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ public void startTests(View view) {
+ Intent intent = new Intent(this, SkQPActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQP.java b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQP.java
index c5843f013e..8ced43dbe2 100644
--- a/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQP.java
+++ b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQP.java
@@ -7,8 +7,90 @@
package org.skia.skqp;
-import org.junit.runner.RunWith;
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.util.Log;
+import java.io.File;
+import java.io.IOException;
-@RunWith(SkQPRunner.class)
-public class SkQP {}
+public class SkQP {
+ protected native void nInit(AssetManager assetManager, String dataDir);
+ protected native float nExecuteGM(int gm, int backend) throws SkQPException;
+ protected native String[] nExecuteUnitTest(int test);
+ protected native void nMakeReport();
+
+ protected String[] mGMs;
+ protected String[] mBackends;
+ protected String[] mUnitTests;
+
+ protected static final String kSkiaGM = "SkiaGM_";
+ protected static final String kSkiaUnitTests = "Skia_UnitTests";
+ protected static final String LOG_PREFIX = "org.skis.skqp";
+
+ static {
+ System.loadLibrary("skqp_app");
+ }
+
+ protected void runTests(Context context, String outputDirPath) {
+ Log.w(LOG_PREFIX, "Output Dir: " + outputDirPath);
+ File outputDir = new File(outputDirPath);
+ if (outputDir.exists()) {
+ try {
+ deleteDirectoryContents(outputDir);
+ } catch (IOException e) {
+ Log.w(LOG_PREFIX, "DeleteDirectoryContents: " + e.getMessage());
+ }
+ }
+
+ // Note: nInit will initialize the mGMs, mBackends and mUnitTests fields.
+ AssetManager assetManager = context.getResources().getAssets();
+ this.nInit(assetManager, outputDirPath);
+
+ for (int backend = 0; backend < mBackends.length; backend++) {
+ String classname = kSkiaGM + mBackends[backend];
+ for (int gm = 0; gm < mGMs.length; gm++) {
+ String testName = kSkiaGM + mBackends[backend] + "_" +mGMs[gm];
+ float value = java.lang.Float.MAX_VALUE;
+ String error = null;
+ Log.w(LOG_PREFIX, "Running: " + testName);
+ try {
+ value = this.nExecuteGM(gm, backend);
+ } catch (SkQPException exept) {
+ error = exept.getMessage();
+ }
+ if (error != null) {
+ // Record error message and carry on.
+ } else if (value != 0) {
+ // Record failure and carry on.
+ // SkQPRunner.Fail(desc, notifier, String.format(
+ // "Image mismatch: max channel diff = %f", value));
+ } else {
+ // Record success for this test.
+ }
+ }
+ }
+ for (int unitTest = 0; unitTest < mUnitTests.length; unitTest++) {
+ String testName = kSkiaUnitTests + "_" + mUnitTests[unitTest];
+ Log.w(LOG_PREFIX, "Running: " + testName);
+ String[] errors = this.nExecuteUnitTest(unitTest);
+ if (errors != null && errors.length > 0) {
+ for (String error : errors) {
+ // Record unit test failures.
+ }
+ } else {
+ // Record success.
+ }
+ }
+ nMakeReport();
+ }
+
+ protected static void deleteDirectoryContents(File f) throws IOException {
+ for (File s : f.listFiles()) {
+ if (s.isDirectory()) {
+ deleteDirectoryContents(s);
+ }
+ s.delete();
+ }
+ }
+}
diff --git a/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPActivity.java b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPActivity.java
new file mode 100644
index 0000000000..ab7ce168b9
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPActivity.java
@@ -0,0 +1,35 @@
+package org.skia.skqp;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+
+public class SkQPActivity extends AppCompatActivity implements Runnable {
+ private SkQP testRunner = new SkQP();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_skqp);
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ // Start the tests.
+ run();
+ }
+
+ // run implements the Runnable interface.
+ public void run() {
+ // Note: /sdcard/Android/data/<package-name> is a location an app is allowed to write to.
+ // When running tests on Firebase it expects any result files to have a '/sdcard
+ // prefix or it won't trigger tests from the CLI.
+
+ Context context = getApplicationContext();
+ String outputDirPath = "/sdcard/Android/data/" + context.getPackageName();
+ testRunner.runTests(context, outputDirPath);
+ finish();
+ }
+}
+
diff --git a/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPRunner.java b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPRunner.java
index 464c9e2e71..dc9aea3f19 100644
--- a/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPRunner.java
+++ b/platform_tools/android/apps/skqp/src/main/java/org/skia/skqp/SkQPRunner.java
@@ -21,30 +21,8 @@ import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
public class SkQPRunner extends Runner {
- private native void nInit(AssetManager assetManager, String dataDir);
- private native float nExecuteGM(int gm, int backend) throws SkQPException;
- private native String[] nExecuteUnitTest(int test);
- private native void nMakeReport();
-
- private AssetManager mAssetManager;
- private String[] mGMs;
- private String[] mBackends;
- private String[] mUnitTests;
-
- private static boolean sOnceFlag = false;
- private static final String kSkiaGM = "SkiaGM_";
- private static final String kSkiaUnitTests = "Skia_UnitTests";
-
private Description mDescription;
-
- private static void DeleteDirectoryContents(File f) throws IOException {
- for (File s : f.listFiles()) {
- if (s.isDirectory()) {
- SkQPRunner.DeleteDirectoryContents(s);
- }
- s.delete();
- }
- }
+ private SkQP impl;
private static void Fail(Description desc, RunNotifier notifier, String failure) {
notifier.fireTestFailure(new Failure(desc, new Throwable(failure)));
@@ -53,37 +31,30 @@ public class SkQPRunner extends Runner {
////////////////////////////////////////////////////////////////////////////
public SkQPRunner(Class testClass) {
- synchronized (SkQPRunner.class) {
- if (sOnceFlag) {
- throw new IllegalStateException("Error multiple SkQPs defined");
- }
- sOnceFlag = true;
- }
- System.loadLibrary("skqp_app");
-
+ impl = new SkQP();
Context context = InstrumentationRegistry.getTargetContext();
File filesDir = context.getFilesDir();
try {
- SkQPRunner.DeleteDirectoryContents(filesDir);
+ SkQP.deleteDirectoryContents(filesDir);
} catch (IOException e) {
Log.w("org.skis.skqp", "DeleteDirectoryContents: " + e.getMessage());
}
Resources resources = context.getResources();
- mAssetManager = resources.getAssets();
- this.nInit(mAssetManager, filesDir.getAbsolutePath());
+ AssetManager mAssetManager = resources.getAssets();
+ impl.nInit(mAssetManager, filesDir.getAbsolutePath());
mDescription = Description.createSuiteDescription(testClass);
Annotation annots[] = new Annotation[0];
- for (int backend = 0; backend < mBackends.length; backend++) {
- String classname = kSkiaGM + mBackends[backend];
- for (int gm = 0; gm < mGMs.length; gm++) {
- mDescription.addChild(Description.createTestDescription(classname, mGMs[gm], annots));
+ for (int backend = 0; backend < impl.mBackends.length; backend++) {
+ String classname = SkQP.kSkiaGM + impl.mBackends[backend];
+ for (int gm = 0; gm < impl.mGMs.length; gm++) {
+ mDescription.addChild(Description.createTestDescription(classname, impl.mGMs[gm], annots));
}
}
- for (int unitTest = 0; unitTest < mUnitTests.length; unitTest++) {
- mDescription.addChild(Description.createTestDescription(kSkiaUnitTests,
- mUnitTests[unitTest], annots));
+ for (int unitTest = 0; unitTest < impl.mUnitTests.length; unitTest++) {
+ mDescription.addChild(Description.createTestDescription(SkQP.kSkiaUnitTests,
+ impl.mUnitTests[unitTest], annots));
}
}
@@ -91,20 +62,20 @@ public class SkQPRunner extends Runner {
public Description getDescription() { return mDescription; }
@Override
- public int testCount() { return mUnitTests.length + mGMs.length * mBackends.length; }
+ public int testCount() { return impl.mUnitTests.length + impl.mGMs.length * impl.mBackends.length; }
@Override
public void run(RunNotifier notifier) {
Annotation annots[] = new Annotation[0];
- for (int backend = 0; backend < mBackends.length; backend++) {
- String classname = kSkiaGM + mBackends[backend];
- for (int gm = 0; gm < mGMs.length; gm++) {
- Description desc = Description.createTestDescription(classname, mGMs[gm], annots);
+ for (int backend = 0; backend < impl.mBackends.length; backend++) {
+ String classname = SkQP.kSkiaGM + impl.mBackends[backend];
+ for (int gm = 0; gm < impl.mGMs.length; gm++) {
+ Description desc = Description.createTestDescription(classname, impl.mGMs[gm], annots);
notifier.fireTestStarted(desc);
float value = java.lang.Float.MAX_VALUE;
String error = null;
try {
- value = this.nExecuteGM(gm, backend);
+ value = impl.nExecuteGM(gm, backend);
} catch (SkQPException exept) {
error = exept.getMessage();
}
@@ -117,11 +88,11 @@ public class SkQPRunner extends Runner {
notifier.fireTestFinished(desc);
}
}
- for (int unitTest = 0; unitTest < mUnitTests.length; unitTest++) {
+ for (int unitTest = 0; unitTest < impl.mUnitTests.length; unitTest++) {
Description desc = Description.createTestDescription(
- kSkiaUnitTests, mUnitTests[unitTest], annots);
+ SkQP.kSkiaUnitTests, impl.mUnitTests[unitTest], annots);
notifier.fireTestStarted(desc);
- String[] errors = this.nExecuteUnitTest(unitTest);
+ String[] errors = impl.nExecuteUnitTest(unitTest);
if (errors != null && errors.length > 0) {
for (String error : errors) {
SkQPRunner.Fail(desc, notifier, error);
@@ -129,7 +100,7 @@ public class SkQPRunner extends Runner {
}
notifier.fireTestFinished(desc);
}
- this.nMakeReport();
+ impl.nMakeReport();
}
}
diff --git a/platform_tools/android/apps/skqp/src/main/res/layout/activity_main.xml b/platform_tools/android/apps/skqp/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000..45b9c77f05
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/res/layout/activity_main.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="org.skia.skqp.MainActivity">
+
+ <LinearLayout
+ android:layout_width="368dp"
+ android:layout_height="495dp"
+ android:orientation="vertical"
+ tools:layout_editor_absoluteX="8dp"
+ tools:layout_editor_absoluteY="8dp">
+
+ <TextView
+ android:id="@+id/textView2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="Nothing to see here !"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Button
+ android:id="@+id/button_start"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:keyboardNavigationCluster="false"
+ android:onClick="startTests"
+ android:text="Start Tests !" />
+ </LinearLayout>
+
+</android.support.constraint.ConstraintLayout>
diff --git a/platform_tools/android/apps/skqp/src/main/res/layout/activity_skqp.xml b/platform_tools/android/apps/skqp/src/main/res/layout/activity_skqp.xml
new file mode 100644
index 0000000000..b9e733644f
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/res/layout/activity_skqp.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="org.skia.skqp.SkQPActivity">
+
+ <android.support.design.widget.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="@style/AppTheme.AppBarOverlay">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+ </android.support.design.widget.AppBarLayout>
+
+ <include layout="@layout/content_skqp" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform_tools/android/apps/skqp/src/main/res/layout/content_skqp.xml b/platform_tools/android/apps/skqp/src/main/res/layout/content_skqp.xml
new file mode 100644
index 0000000000..352937adf7
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/res/layout/content_skqp.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:context="org.skia.skqp.SkQPActivity"
+ tools:showIn="@layout/activity_skqp">
+
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Running SkQP tests ..."
+ android:textSize="18sp"
+ android:textStyle="bold"
+ android:visibility="visible" />
+</android.support.constraint.ConstraintLayout>
diff --git a/platform_tools/android/apps/skqp/src/main/res/values/colors.xml b/platform_tools/android/apps/skqp/src/main/res/values/colors.xml
new file mode 100644
index 0000000000..3ab3e9cbce
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/platform_tools/android/apps/skqp/src/main/res/values/strings.xml b/platform_tools/android/apps/skqp/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..fb39759ca1
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="app_name">SkQP App</string>
+ <string name="title_activity_skqp">SkQP Activity</string>
+</resources>
diff --git a/platform_tools/android/apps/skqp/src/main/res/values/styles.xml b/platform_tools/android/apps/skqp/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..545b9c6d2c
--- /dev/null
+++ b/platform_tools/android/apps/skqp/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+</resources>
diff --git a/tools/skqp/jni/org_skia_skqp_SkQPRunner.cpp b/tools/skqp/jni/org_skia_skqp_SkQPRunner.cpp
index 22d2c03488..7347f28ff9 100644
--- a/tools/skqp/jni/org_skia_skqp_SkQPRunner.cpp
+++ b/tools/skqp/jni/org_skia_skqp_SkQPRunner.cpp
@@ -19,11 +19,11 @@
////////////////////////////////////////////////////////////////////////////////
extern "C" {
-JNIEXPORT void JNICALL Java_org_skia_skqp_SkQPRunner_nInit(JNIEnv*, jobject, jobject, jstring);
-JNIEXPORT jfloat JNICALL Java_org_skia_skqp_SkQPRunner_nExecuteGM(JNIEnv*, jobject, jint, jint);
-JNIEXPORT jobjectArray JNICALL Java_org_skia_skqp_SkQPRunner_nExecuteUnitTest(JNIEnv*, jobject,
+JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nInit(JNIEnv*, jobject, jobject, jstring);
+JNIEXPORT jfloat JNICALL Java_org_skia_skqp_SkQP_nExecuteGM(JNIEnv*, jobject, jint, jint);
+JNIEXPORT jobjectArray JNICALL Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv*, jobject,
jint);
-JNIEXPORT void JNICALL Java_org_skia_skqp_SkQPRunner_nMakeReport(JNIEnv*, jobject);
+JNIEXPORT void JNICALL Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject);
} // extern "C"
////////////////////////////////////////////////////////////////////////////////
@@ -118,7 +118,7 @@ jobjectArray to_java_string_array(JNIEnv* env,
return jarray;
}
-void Java_org_skia_skqp_SkQPRunner_nInit(JNIEnv* env, jobject object, jobject assetManager,
+void Java_org_skia_skqp_SkQP_nInit(JNIEnv* env, jobject object, jobject assetManager,
jstring dataDir) {
jclass clazz = env->GetObjectClass(object);
jassert(env, assetManager);
@@ -147,7 +147,7 @@ void Java_org_skia_skqp_SkQPRunner_nInit(JNIEnv* env, jobject object, jobject as
to_java_string_array(env, gGMs, gm_runner::GetGMName));
}
-jfloat Java_org_skia_skqp_SkQPRunner_nExecuteGM(JNIEnv* env,
+jfloat Java_org_skia_skqp_SkQP_nExecuteGM(JNIEnv* env,
jobject object,
jint gmIndex,
jint backendIndex) {
@@ -173,7 +173,7 @@ jfloat Java_org_skia_skqp_SkQPRunner_nExecuteGM(JNIEnv* env,
return result;
}
-jobjectArray Java_org_skia_skqp_SkQPRunner_nExecuteUnitTest(JNIEnv* env,
+jobjectArray Java_org_skia_skqp_SkQP_nExecuteUnitTest(JNIEnv* env,
jobject object,
jint index) {
jassert(env, index < (jint)gUnitTests.size());
@@ -193,7 +193,7 @@ jobjectArray Java_org_skia_skqp_SkQPRunner_nExecuteUnitTest(JNIEnv* env,
return (jobjectArray)env->NewGlobalRef(array);
}
-void Java_org_skia_skqp_SkQPRunner_nMakeReport(JNIEnv*, jobject) {
+void Java_org_skia_skqp_SkQP_nMakeReport(JNIEnv*, jobject) {
std::string reportDirectoryPath;
{
std::lock_guard<std::mutex> lock(gMutex);