Remove CanvasCompare.

As part of renderscript deprecation/removal, of the two pieces of
renderscript in this app, one already had a Java alternative but the
heatmap code didn't. Rather than reimplement that, though, it appears
that this project has been obsoleted by CtsUiRenderingTestCases. So
let's remove it instead. (Even if we're wrong, this still gives us more
time to work out what, if anything, is actually needed.)

Bug: http://b/255624710
Test: treehugger
Change-Id: I7cf64a28bd3c7edea061fafc5e06d4134cc79b05
This commit is contained in:
Elliott Hughes
2023-01-23 21:15:43 +00:00
parent 5e947c04e5
commit 2ae77029fd
17 changed files with 0 additions and 1958 deletions

View File

@@ -1,63 +0,0 @@
//
// Copyright (C) 2012 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 {
// See: http://go/android-license-faq
default_applicable_licenses: [
"frameworks_base_license",
],
}
android_test {
name: "CanvasCompare",
srcs: [
"src/**/*.java",
":CanvasCompare-rscript{CanvasCompare.srcjar}",
],
resource_zips: [
":CanvasCompare-rscript{CanvasCompare.res.zip}",
],
platform_apis: true,
libs: [
"android.test.runner",
"android.test.base",
],
static_libs: ["junit"],
}
genrule {
name: "CanvasCompare-rscript",
srcs: [
"src/**/*.rscript",
":rs_script_api",
":rs_clang_headers",
],
tools: [
"llvm-rs-cc",
"soong_zip",
],
out: [
"CanvasCompare.srcjar",
"CanvasCompare.res.zip",
],
cmd: "for f in $(locations src/**/*.rscript); do " +
" $(location llvm-rs-cc) -o $(genDir)/res/raw -p $(genDir)/src " +
" -I $$(dirname $$(echo $(locations :rs_script_api) | awk '{ print $$1 }')) " +
" -I $$(dirname $$(echo $(locations :rs_clang_headers) | awk '{ print $$1 }')) $${f}; " +
"done && " +
"$(location soong_zip) -srcjar -o $(location CanvasCompare.srcjar) -C $(genDir)/src -D $(genDir)/src &&" +
"$(location soong_zip) -o $(location CanvasCompare.res.zip) -C $(genDir)/res -D $(genDir)/res",
}

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 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.test.hwuicompare">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light.NoActionBar">
<activity android:name="AutomaticActivity"
android:label="CanvasAutoCompare"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="ManualActivity"
android:label="CanvasManualCompare"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.test.hwuicompare"
android:label="HW/SW Canvas comparison tool."/>
</manifest>

View File

@@ -1 +0,0 @@
include /libs/hwui/OWNERS

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.android.test.hwuicompare.MainView
android:id="@+id/hardware_view"
android:layout_width="@dimen/layer_width"
android:layout_height="@dimen/layer_width" />
<ImageView
android:id="@+id/software_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true" />
<ImageView
android:id="@+id/hardware_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true" />
</RelativeLayout>

View File

@@ -1,119 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 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:gravity="center_horizontal"
android:orientation="vertical" >
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<LinearLayout
android:id="@+id/spinner_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />
</HorizontalScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:baselineAligned="true"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal" >
<com.android.test.hwuicompare.MainView
android:id="@+id/hardware_view"
android:layout_width="@dimen/layer_width"
android:layout_height="@dimen/layer_width" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal" >
<com.android.test.hwuicompare.MainView
android:id="@+id/software_view"
android:layout_width="@dimen/layer_width"
android:layout_height="@dimen/layer_width" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/compare_image_view"
android:layout_width="@dimen/layer_width_double"
android:layout_height="@dimen/layer_height_double"
android:filter="false" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<ImageButton
android:id="@+id/previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/previous_combination"
android:src="@android:drawable/ic_media_previous" />
<ImageButton
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/next_combination"
android:src="@android:drawable/ic_media_next" />
<TextView
android:id="@+id/current_error"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/show_hardware_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/show_hardware_version" />
<Button
android:id="@+id/show_software_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/show_software_version" />
<Button
android:id="@+id/show_error_heatmap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/show_error_heatmap" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 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.
-->
<resources>
<string name="app_name">Canvas Compare Test</string>
<!-- show hardware rendered version of the layer -->
<string name="show_hardware_version">Hardware</string>
<!-- show software rendered version of the layer -->
<string name="show_software_version">Software</string>
<!-- show layer error -->
<string name="show_error_values">Error</string>
<!-- show layer error heatmap -->
<string name="show_error_heatmap">Heatmap</string>
<!-- select and display the next combination of painting options-->
<string name="next_combination">Next Combination</string>
<!-- select and display the previous combination of painting options-->
<string name="previous_combination">Previous Combination</string>
</resources>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 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.
-->
<resources>
<!-- NOTE: the below MUST be multiples of 64 -->
<dimen name="layer_height">320px</dimen>
<dimen name="layer_width">320px</dimen>
<dimen name="layer_height_double">640px</dimen>
<dimen name="layer_width_double">640px</dimen>
</resources>

View File

@@ -1,310 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeSet;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.os.Environment;
import android.os.Trace;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;
public class AutomaticActivity extends CompareActivity {
private static final String LOG_TAG = "AutomaticActivity";
private static final float ERROR_DISPLAY_THRESHOLD = 0.01f;
protected static final boolean DRAW_BITMAPS = false;
/**
* Threshold of error change required to consider a test regressed/improved
*/
private static final float ERROR_CHANGE_THRESHOLD = 0.001f;
private static final float[] ERROR_CUTOFFS = {
0, 0.005f, 0.01f, 0.02f, 0.05f, 0.1f, 0.25f, 0.5f, 1f, 2f
};
private final float[] mErrorRates = new float[ERROR_CUTOFFS.length];
private float mTotalTests = 0;
private float mTotalError = 0;
private int mTestsRegressed = 0;
private int mTestsImproved = 0;
private ImageView mSoftwareImageView = null;
private ImageView mHardwareImageView = null;
public abstract static class FinalCallback {
abstract void report(String name, float value);
void complete() {};
}
private final ArrayList<FinalCallback> mFinalCallbacks = new ArrayList<FinalCallback>();
Runnable mRunnable = new Runnable() {
@Override
public void run() {
loadBitmaps();
if (mSoftwareBitmap == null || mHardwareBitmap == null) {
Log.e(LOG_TAG, "bitmap is null");
return;
}
if (DRAW_BITMAPS) {
mSoftwareImageView.setImageBitmap(mSoftwareBitmap);
mHardwareImageView.setImageBitmap(mHardwareBitmap);
}
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "calculateError");
float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
final String[] modifierNames = DisplayModifier.getLastAppliedModifications();
handleError(modifierNames, error);
if (DisplayModifier.step()) {
finishTest();
} else {
mHardwareView.invalidate();
if (DRAW_BITMAPS) {
mSoftwareImageView.invalidate();
mHardwareImageView.invalidate();
}
}
mHandler.removeCallbacks(mRunnable);
}
};
@Override
protected void onPause() {
super.onPause();
mHandler.removeCallbacks(mRunnable);
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.automatic_layout);
mSoftwareImageView = findViewById(R.id.software_image_view);
mHardwareImageView = findViewById(R.id.hardware_image_view);
onCreateCommon(mRunnable);
beginTest();
}
private static class TestResult {
TestResult(String label, float error) {
mLabel = label;
mTotalError = error;
mCount = 1;
}
public void addInto(float error) {
mTotalError += error;
mCount++;
}
public float getAverage() {
return mTotalError / mCount;
}
final String mLabel;
float mTotalError;
int mCount;
}
JSONObject mOutputJson = null;
JSONObject mInputJson = null;
final HashMap<String, TestResult> mModifierResults = new HashMap<String, TestResult>();
final HashMap<String, TestResult> mIndividualResults = new HashMap<String, TestResult>();
final HashMap<String, TestResult> mModifierDiffResults = new HashMap<String, TestResult>();
final HashMap<String, TestResult> mIndividualDiffResults = new HashMap<String, TestResult>();
private void beginTest() {
mFinalCallbacks.add(new FinalCallback() {
@Override
void report(String name, float value) {
Log.d(LOG_TAG, name + " " + value);
};
});
File inputFile = new File(Environment.getExternalStorageDirectory(),
"CanvasCompareInput.json");
if (inputFile.exists() && inputFile.canRead() && inputFile.length() > 0) {
try {
FileInputStream inputStream = new FileInputStream(inputFile);
Log.d(LOG_TAG, "Parsing input file...");
StringBuffer content = new StringBuffer((int)inputFile.length());
byte[] buffer = new byte[1024];
while (inputStream.read(buffer) != -1) {
content.append(new String(buffer));
}
mInputJson = new JSONObject(content.toString());
inputStream.close();
Log.d(LOG_TAG, "Parsed input file with " + mInputJson.length() + " entries");
} catch (JSONException e) {
Log.e(LOG_TAG, "error parsing input json", e);
} catch (IOException e) {
Log.e(LOG_TAG, "error reading input json from sd", e);
}
}
mOutputJson = new JSONObject();
}
private static void logTestResultHash(String label, HashMap<String, TestResult> map) {
Log.d(LOG_TAG, "---------------");
Log.d(LOG_TAG, label + ":");
Log.d(LOG_TAG, "---------------");
TreeSet<TestResult> set = new TreeSet<TestResult>(new Comparator<TestResult>() {
@Override
public int compare(TestResult lhs, TestResult rhs) {
if (lhs == rhs) return 0; // don't need to worry about complex equality
int cmp = Float.compare(lhs.getAverage(), rhs.getAverage());
if (cmp != 0) {
return cmp;
}
return lhs.mLabel.compareTo(rhs.mLabel);
}
});
for (TestResult t : map.values()) {
set.add(t);
}
for (TestResult t : set.descendingSet()) {
if (Math.abs(t.getAverage()) > ERROR_DISPLAY_THRESHOLD) {
Log.d(LOG_TAG, String.format("%2.4f : %s", t.getAverage(), t.mLabel));
}
}
Log.d(LOG_TAG, "");
}
private void finishTest() {
for (FinalCallback c : mFinalCallbacks) {
c.report("averageError", (mTotalError / mTotalTests));
for (int i = 1; i < ERROR_CUTOFFS.length; i++) {
c.report(String.format("tests with error over %1.3f", ERROR_CUTOFFS[i]),
mErrorRates[i]);
}
if (mInputJson != null) {
c.report("tests regressed", mTestsRegressed);
c.report("tests improved", mTestsImproved);
}
c.complete();
}
try {
if (mOutputJson != null) {
String outputString = mOutputJson.toString(4);
File outputFile = new File(Environment.getExternalStorageDirectory(),
"CanvasCompareOutput.json");
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputString.getBytes());
outputStream.close();
Log.d(LOG_TAG, "Saved output file with " + mOutputJson.length() + " entries");
}
} catch (JSONException e) {
Log.e(LOG_TAG, "error during JSON stringify", e);
} catch (IOException e) {
Log.e(LOG_TAG, "error storing JSON output on sd", e);
}
logTestResultHash("Modifier change vs previous", mModifierDiffResults);
logTestResultHash("Invidual test change vs previous", mIndividualDiffResults);
logTestResultHash("Modifier average test results", mModifierResults);
logTestResultHash("Individual test results", mIndividualResults);
Toast.makeText(getApplicationContext(), "done!", Toast.LENGTH_SHORT).show();
finish();
}
/**
* Inserts the error value into all TestResult objects, associated with each of its modifiers
*/
private static void addForAllModifiers(String fullName, float error, String[] modifierNames,
HashMap<String, TestResult> modifierResults) {
for (String modifierName : modifierNames) {
TestResult r = modifierResults.get(fullName);
if (r == null) {
modifierResults.put(modifierName, new TestResult(modifierName, error));
} else {
r.addInto(error);
}
}
}
private void handleError(final String[] modifierNames, final float error) {
String fullName = "";
for (String s : modifierNames) {
fullName = fullName.concat("." + s);
}
fullName = fullName.substring(1);
float deltaError = 0;
if (mInputJson != null) {
try {
deltaError = error - (float)mInputJson.getDouble(fullName);
} catch (JSONException e) {
Log.w(LOG_TAG, "Warning: unable to read from input json", e);
}
if (deltaError > ERROR_CHANGE_THRESHOLD) mTestsRegressed++;
if (deltaError < -ERROR_CHANGE_THRESHOLD) mTestsImproved++;
mIndividualDiffResults.put(fullName, new TestResult(fullName, deltaError));
addForAllModifiers(fullName, deltaError, modifierNames, mModifierDiffResults);
}
mIndividualResults.put(fullName, new TestResult(fullName, error));
addForAllModifiers(fullName, error, modifierNames, mModifierResults);
try {
if (mOutputJson != null) {
mOutputJson.put(fullName, error);
}
} catch (JSONException e) {
Log.e(LOG_TAG, "exception during JSON recording", e);
mOutputJson = null;
}
for (int i = 0; i < ERROR_CUTOFFS.length; i++) {
if (error <= ERROR_CUTOFFS[i]) break;
mErrorRates[i]++;
}
mTotalError += error;
mTotalTests++;
}
@Override
protected boolean forceRecreateBitmaps() {
// disable, unless needed for drawing into imageviews
return DRAW_BITMAPS;
}
// FOR TESTING
public void setFinalCallback(FinalCallback c) {
mFinalCallbacks.add(c);
}
}

View File

@@ -1,122 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.android.test.hwuicompare.R;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.Trace;
import android.util.Log;
import android.view.View;
abstract public class CompareActivity extends Activity {
private static final String LOG_TAG = "CompareActivity";
protected MainView mHardwareView = null;
protected Bitmap mSoftwareBitmap;
protected Bitmap mHardwareBitmap;
protected ErrorCalculator mErrorCalculator;
protected Handler mHandler;
Runnable mDrawCallback = null;
protected boolean mRedrewFlag = true;
protected void onCreateCommon(final Runnable postDrawCallback) {
mDrawCallback = new Runnable() {
@Override
public void run() {
mRedrewFlag = true;
mHandler.post(postDrawCallback);
};
};
getWindow().setBackgroundDrawable(new ColorDrawable(0xffefefef));
ResourceModifiers.init(getResources());
mHardwareView = findViewById(R.id.hardware_view);
mHardwareView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mHardwareView.setBackgroundColor(Color.WHITE);
mHardwareView.addDrawCallback(mDrawCallback);
int width = getResources().getDimensionPixelSize(R.dimen.layer_width);
int height = getResources().getDimensionPixelSize(R.dimen.layer_height);
mSoftwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mHardwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mErrorCalculator = new ErrorCalculator(getApplicationContext(), getResources());
mHandler = new Handler();
}
protected abstract boolean forceRecreateBitmaps();
protected void loadBitmaps() {
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "loadBitmaps");
if (forceRecreateBitmaps()) {
int width = mSoftwareBitmap.getWidth();
int height = mSoftwareBitmap.getHeight();
mSoftwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mHardwareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "softwareDraw");
mHardwareView.draw(new Canvas(mSoftwareBitmap));
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
try {
Method getHardwareLayer = View.class.getDeclaredMethod("getHardwareLayer");
if (!getHardwareLayer.isAccessible())
getHardwareLayer.setAccessible(true);
Object hardwareLayer = getHardwareLayer.invoke(mHardwareView);
if (hardwareLayer == null) {
Log.d(LOG_TAG, "failure to access hardware layer");
return;
}
Method copyInto = hardwareLayer.getClass()
.getDeclaredMethod("copyInto", Bitmap.class);
if (!copyInto.isAccessible())
copyInto.setAccessible(true);
Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, "copyInto");
boolean success = (Boolean) copyInto.invoke(hardwareLayer, mHardwareBitmap);
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
if (!success) {
Log.d(LOG_TAG, "failure to copy hardware layer into bitmap");
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
}

View File

@@ -1,503 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import static java.util.Map.entry;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.Log;
import java.util.Map;
import java.util.Map.Entry;
public abstract class DisplayModifier {
// automated tests ignore any combination of operations that don't together return TOTAL_MASK
protected final static int TOTAL_MASK = 0x1F;
// if we're filling, ensure we're not also sweeping over stroke parameters
protected final static int SWEEP_STROKE_WIDTH_BIT = 0x1 << 0;
protected final static int SWEEP_STROKE_CAP_BIT = 0x1 << 1;
protected final static int SWEEP_STROKE_JOIN_BIT = 0x1 << 2;
protected final static int SWEEP_SHADER_BIT = 0x1 << 3; // only allow non-simple shaders to use rectangle drawing
protected final static int SWEEP_TRANSFORM_BIT = 0x1 << 4; // only sweep over specified transforms
abstract public void modifyDrawing(Paint paint, Canvas canvas);
protected int mask() { return 0x0; };
private static final RectF gRect = new RectF(0, 0, 200, 175);
private static final float[] gPts = new float[] {
0, 100, 100, 0, 100, 200, 200, 100
};
private static final int NUM_PARALLEL_LINES = 24;
private static final float[] gTriPts = new float[] {
75, 0, 130, 130, 130, 130, 0, 130, 0, 130, 75, 0
};
private static final float[] gLinePts = new float[NUM_PARALLEL_LINES * 8 + gTriPts.length];
static {
int index;
for (index = 0; index < gTriPts.length; index++) {
gLinePts[index] = gTriPts[index];
}
float val = 0;
for (int i = 0; i < NUM_PARALLEL_LINES; i++) {
gLinePts[index + 0] = 150;
gLinePts[index + 1] = val;
gLinePts[index + 2] = 300;
gLinePts[index + 3] = val;
index += 4;
val += 8 + (2.0f/NUM_PARALLEL_LINES);
}
val = 0;
for (int i = 0; i < NUM_PARALLEL_LINES; i++) {
gLinePts[index + 0] = val;
gLinePts[index + 1] = 150;
gLinePts[index + 2] = val;
gLinePts[index + 3] = 300;
index += 4;
val += 8 + (2.0f/NUM_PARALLEL_LINES);
}
};
@SuppressWarnings("serial")
private static final Map<String, Map<String, DisplayModifier>> gMaps = Map.of(
"aa", Map.of(
"true", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setAntiAlias(true);
}
},
"false", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setAntiAlias(false);
}
}),
"style", Map.of(
"fill", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStyle(Paint.Style.FILL);
}
},
"stroke", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected int mask() { return SWEEP_STROKE_WIDTH_BIT; }
},
"fillAndStroke", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStyle(Paint.Style.FILL_AND_STROKE);
}
@Override
protected int mask() { return SWEEP_STROKE_WIDTH_BIT; }
}),
"strokeWidth", Map.of(
"hair", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeWidth(0);
}
@Override
protected int mask() { return SWEEP_STROKE_WIDTH_BIT; }
},
"0.3", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeWidth(0.3f);
}
},
"1", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeWidth(1);
}
},
"5", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeWidth(5);
}
},
"30", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeWidth(30);
}
}),
"strokeCap", Map.of(
"butt", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeCap(Paint.Cap.BUTT);
}
@Override
protected int mask() { return SWEEP_STROKE_CAP_BIT; }
},
"round", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeCap(Paint.Cap.ROUND);
}
},
"square", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeCap(Paint.Cap.SQUARE);
}
}),
"strokeJoin", Map.of(
"bevel", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeJoin(Paint.Join.BEVEL);
}
@Override
protected int mask() { return SWEEP_STROKE_JOIN_BIT; }
},
"round", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeJoin(Paint.Join.ROUND);
}
},
"miter", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setStrokeJoin(Paint.Join.MITER);
}
}),
// TODO: add miter0, miter1 etc to test miter distances
"transform", Map.of(
"noTransform", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {}
@Override
protected int mask() { return SWEEP_TRANSFORM_BIT; };
},
"rotate5", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.rotate(5);
}
},
"rotate45", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.rotate(45);
}
},
"rotate90", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.rotate(90);
canvas.translate(0, -200);
}
},
"scale2x2", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.scale(2, 2);
}
@Override
protected int mask() { return SWEEP_TRANSFORM_BIT; };
},
"rot20scl1x4", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.rotate(20);
canvas.scale(1, 4);
}
@Override
protected int mask() { return SWEEP_TRANSFORM_BIT; };
}),
"shader", Map.ofEntries(
entry("noShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {}
@Override
protected int mask() { return SWEEP_SHADER_BIT; };
}),
entry("repeatShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mRepeatShader);
}
@Override
protected int mask() { return SWEEP_SHADER_BIT; };
}),
entry("translatedShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mTranslatedShader);
}
}),
entry("scaledShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mScaledShader);
}
}),
entry("horGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mHorGradient);
}
}),
entry("diagGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mDiagGradient);
}
@Override
protected int mask() { return SWEEP_SHADER_BIT; };
}),
entry("vertGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mVertGradient);
}
}),
entry("radGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mRadGradient);
}
}),
entry("sweepGradient", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mSweepGradient);
}
}),
entry("composeShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mComposeShader);
}
}),
entry("bad composeShader", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mBadComposeShader);
}
}),
entry("bad composeShader 2", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader);
}
})),
"drawing", Map.ofEntries(
entry("roundRect", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawRoundRect(gRect, 20, 20, paint);
}
}),
entry("rect", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawRect(gRect, paint);
}
@Override
protected int mask() { return SWEEP_SHADER_BIT | SWEEP_STROKE_CAP_BIT; };
}),
entry("circle", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawCircle(100, 100, 75, paint);
}
}),
entry("oval", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawOval(gRect, paint);
}
}),
entry("lines", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawLines(gLinePts, paint);
}
@Override
protected int mask() { return SWEEP_STROKE_CAP_BIT; };
}),
entry("plusPoints", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawPoints(gPts, paint);
}
}),
entry("text", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setTextSize(36);
canvas.drawText("TEXTTEST", 0, 50, paint);
}
}),
entry("shadowtext", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
paint.setTextSize(36);
paint.setShadowLayer(3.0f, 0.0f, 3.0f, 0xffff00ff);
canvas.drawText("TEXTTEST", 0, 50, paint);
}
}),
entry("bitmapMesh", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawBitmapMesh(ResourceModifiers.instance().mBitmap, 3, 3,
ResourceModifiers.instance().mBitmapVertices, 0, null, 0, null);
}
}),
entry("arc", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawArc(gRect, 260, 285, false, paint);
}
@Override
protected int mask() { return SWEEP_STROKE_CAP_BIT; };
}),
entry("arcFromCenter", new DisplayModifier() {
@Override
public void modifyDrawing(Paint paint, Canvas canvas) {
canvas.drawArc(gRect, 260, 285, true, paint);
}
@Override
protected int mask() { return SWEEP_STROKE_JOIN_BIT; };
})));
// WARNING: DON'T PUT MORE MAPS BELOW THIS
private static Map<String, DisplayModifier> getMapAtIndex(int index) {
for (Map<String, DisplayModifier> map : gMaps.values()) {
if (index == 0) {
return map;
}
index--;
}
return null;
}
// indices instead of iterators for easier bidirectional traversal
private static final int mIndices[] = new int[gMaps.size()];
private static final String[] mLastAppliedModifications = new String[gMaps.size()];
private static boolean stepInternal(boolean forward) {
int modifierMapIndex = gMaps.size() - 1;
while (modifierMapIndex >= 0) {
Map<String, DisplayModifier> map = getMapAtIndex(modifierMapIndex);
mIndices[modifierMapIndex] += (forward ? 1 : -1);
if (mIndices[modifierMapIndex] >= 0 && mIndices[modifierMapIndex] < map.size()) {
break;
}
mIndices[modifierMapIndex] = (forward ? 0 : map.size() - 1);
modifierMapIndex--;
}
return modifierMapIndex < 0; // true if resetting
}
public static boolean step() {
boolean ret = false;
do {
ret |= stepInternal(true);
} while (!checkModificationStateMask());
return ret;
}
public static boolean stepBack() {
boolean ret = false;
do {
ret |= stepInternal(false);
} while (!checkModificationStateMask());
return ret;
}
private static boolean checkModificationStateMask() {
int operatorMask = 0x0;
int mapIndex = 0;
for (Map<String, DisplayModifier> map : gMaps.values()) {
int displayModifierIndex = mIndices[mapIndex];
for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) {
if (displayModifierIndex == 0) {
mLastAppliedModifications[mapIndex] = modifierEntry.getKey();
operatorMask |= modifierEntry.getValue().mask();
break;
}
displayModifierIndex--;
}
mapIndex++;
}
return operatorMask == TOTAL_MASK;
}
public static void apply(Paint paint, Canvas canvas) {
int mapIndex = 0;
for (Map<String, DisplayModifier> map : gMaps.values()) {
int displayModifierIndex = mIndices[mapIndex];
for (Entry<String, DisplayModifier> modifierEntry : map.entrySet()) {
if (displayModifierIndex == 0) {
mLastAppliedModifications[mapIndex] = modifierEntry.getKey();
modifierEntry.getValue().modifyDrawing(paint, canvas);
break;
}
displayModifierIndex--;
}
mapIndex++;
}
}
public static String[] getLastAppliedModifications() {
return mLastAppliedModifications.clone();
}
public static String[][] getStrings() {
String[][] keys = new String[gMaps.size()][];
int i = 0;
for (Map<String, DisplayModifier> map : gMaps.values()) {
keys[i] = new String[map.size()];
int j = 0;
for (String key : map.keySet()) {
keys[i][j++] = key;
}
i++;
}
return keys;
}
public static void setIndex(int mapIndex, int newIndexValue) {
mIndices[mapIndex] = newIndexValue;
}
public static int[] getIndices() {
return mIndices;
}
}

View File

@@ -1,187 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.util.Log;
public class ErrorCalculator {
private static final String LOG_TAG = "ErrorCalculator";
private static final int REGION_SIZE = 8;
private static final boolean LOG_TIMING = false;
private static final boolean LOG_CALC = false;
private RenderScript mRS;
private Allocation mIdealPixelsAllocation;
private Allocation mGivenPixelsAllocation;
private Allocation mOutputPixelsAllocation;
private Allocation mInputRowsAllocation;
private Allocation mOutputRegionsAllocation;
private ScriptC_errorCalculator mScript;
private int[] mOutputRowRegions;
public ErrorCalculator(Context c, Resources resources) {
int width = resources.getDimensionPixelSize(R.dimen.layer_width);
int height = resources.getDimensionPixelSize(R.dimen.layer_height);
mOutputRowRegions = new int[height / REGION_SIZE];
mRS = RenderScript.create(c);
int[] rowIndices = new int[height / REGION_SIZE];
for (int i = 0; i < rowIndices.length; i++)
rowIndices[i] = i * REGION_SIZE;
mScript = new ScriptC_errorCalculator(mRS);
mScript.set_HEIGHT(height);
mScript.set_WIDTH(width);
mScript.set_REGION_SIZE(REGION_SIZE);
mInputRowsAllocation = Allocation.createSized(mRS, Element.I32(mRS), rowIndices.length,
Allocation.USAGE_SCRIPT);
mInputRowsAllocation.copyFrom(rowIndices);
mOutputRegionsAllocation = Allocation.createSized(mRS, Element.I32(mRS),
mOutputRowRegions.length, Allocation.USAGE_SCRIPT);
}
private static long startMillis, middleMillis;
public float calcErrorRS(Bitmap ideal, Bitmap given) {
if (LOG_TIMING) {
startMillis = System.currentTimeMillis();
}
mIdealPixelsAllocation = Allocation.createFromBitmap(mRS, ideal,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
mScript.set_ideal(mIdealPixelsAllocation);
mScript.set_given(mGivenPixelsAllocation);
mScript.forEach_countInterestingRegions(mInputRowsAllocation, mOutputRegionsAllocation);
mOutputRegionsAllocation.copyTo(mOutputRowRegions);
int regionCount = 0;
for (int region : mOutputRowRegions) {
regionCount += region;
}
int interestingPixels = Math.max(1, regionCount) * REGION_SIZE * REGION_SIZE;
if (LOG_TIMING) {
long startMillis2 = System.currentTimeMillis();
}
mScript.forEach_accumulateError(mInputRowsAllocation, mOutputRegionsAllocation);
mOutputRegionsAllocation.copyTo(mOutputRowRegions);
float totalError = 0;
for (int row : mOutputRowRegions) {
totalError += row;
}
totalError /= 1024.0f;
if (LOG_TIMING) {
long finalMillis = System.currentTimeMillis();
Log.d(LOG_TAG, "rs: first part took " + (middleMillis - startMillis) + "ms");
Log.d(LOG_TAG, "rs: last part took " + (finalMillis - middleMillis) + "ms");
}
if (LOG_CALC) {
Log.d(LOG_TAG, "rs: error " + totalError + ", pixels " + interestingPixels);
}
return totalError / interestingPixels;
}
public void calcErrorHeatmapRS(Bitmap ideal, Bitmap given, Bitmap output) {
mIdealPixelsAllocation = Allocation.createFromBitmap(mRS, ideal,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
mScript.set_ideal(mIdealPixelsAllocation);
mScript.set_given(mGivenPixelsAllocation);
mOutputPixelsAllocation = Allocation.createFromBitmap(mRS, output,
Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
mScript.forEach_displayDifference(mOutputPixelsAllocation, mOutputPixelsAllocation);
mOutputPixelsAllocation.copyTo(output);
}
public static float calcError(Bitmap ideal, Bitmap given) {
if (LOG_TIMING) {
startMillis = System.currentTimeMillis();
}
int interestingRegions = 0;
for (int x = 0; x < ideal.getWidth(); x += REGION_SIZE) {
for (int y = 0; y < ideal.getWidth(); y += REGION_SIZE) {
if (inspectRegion(ideal, x, y)) {
interestingRegions++;
}
}
}
int interestingPixels = Math.max(1, interestingRegions) * REGION_SIZE * REGION_SIZE;
if (LOG_TIMING) {
long startMillis2 = System.currentTimeMillis();
}
float totalError = 0;
for (int x = 0; x < ideal.getWidth(); x++) {
for (int y = 0; y < ideal.getHeight(); y++) {
int idealColor = ideal.getPixel(x, y);
int givenColor = given.getPixel(x, y);
if (idealColor == givenColor)
continue;
totalError += Math.abs(Color.red(idealColor) - Color.red(givenColor));
totalError += Math.abs(Color.green(idealColor) - Color.green(givenColor));
totalError += Math.abs(Color.blue(idealColor) - Color.blue(givenColor));
totalError += Math.abs(Color.alpha(idealColor) - Color.alpha(givenColor));
}
}
totalError /= 1024.0f;
if (LOG_TIMING) {
long finalMillis = System.currentTimeMillis();
Log.d(LOG_TAG, "dvk: first part took " + (middleMillis - startMillis) + "ms");
Log.d(LOG_TAG, "dvk: last part took " + (finalMillis - middleMillis) + "ms");
}
if (LOG_CALC) {
Log.d(LOG_TAG, "dvk: error " + totalError + ", pixels " + interestingPixels);
}
return totalError / interestingPixels;
}
private static boolean inspectRegion(Bitmap ideal, int x, int y) {
int regionColor = ideal.getPixel(x, y);
for (int i = 0; i < REGION_SIZE; i++) {
for (int j = 0; j < REGION_SIZE; j++) {
if (ideal.getPixel(x + i, y + j) != regionColor)
return true;
}
}
return false;
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class MainView extends View {
Paint mPaint = new Paint();
public MainView(Context context) {
super(context);
}
public MainView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MainView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.reset();
DisplayModifier.apply(mPaint, canvas);
if (mDrawCallback != null) {
mDrawCallback.run();
}
}
private Runnable mDrawCallback;
public void addDrawCallback(Runnable drawCallback) {
mDrawCallback = drawCallback;
}
}

View File

@@ -1,212 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import com.android.test.hwuicompare.R;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
public class ManualActivity extends CompareActivity {
private static final String LOG_TAG = "ManualActivity";
private ImageView mCompareImageView;
private Bitmap mCompareBitmap;
private TextView mErrorTextView;
private MainView mSoftwareView;
private static final int COMPARE_VIEW_UNINITIALIZED = -1;
private static final int COMPARE_VIEW_HARDWARE = 0;
private static final int COMPARE_VIEW_SOFTWARE = 1;
private static final int COMPARE_VIEW_HEATMAP = 2; // TODO: add more like this? any ideas?
private int mCompareImageViewState = COMPARE_VIEW_UNINITIALIZED;
private int mLastCompareImageViewState = COMPARE_VIEW_UNINITIALIZED;
Runnable mRunnable = new Runnable() {
@Override
public void run() {
Log.d(LOG_TAG, "mRunnable running, mRedrewFlag = " + mRedrewFlag);
if (mRedrewFlag) {
loadBitmaps();
// recalculate error
float error = mErrorCalculator.calcErrorRS(mSoftwareBitmap, mHardwareBitmap);
String modname = "";
for (String s : DisplayModifier.getLastAppliedModifications()) {
modname = modname.concat(s + ".");
}
Log.d(LOG_TAG, "error for " + modname + " is " + error);
mErrorTextView.setText(String.format("%.4f", error));
}
if (mCompareImageViewState != mLastCompareImageViewState || mRedrewFlag) {
switch (mCompareImageViewState) {
case COMPARE_VIEW_UNINITIALIZED:
// set to hardware
case COMPARE_VIEW_HARDWARE:
mCompareImageView.setImageBitmap(mHardwareBitmap);
break;
case COMPARE_VIEW_SOFTWARE:
mCompareImageView.setImageBitmap(mSoftwareBitmap);
break;
case COMPARE_VIEW_HEATMAP:
mErrorCalculator.calcErrorHeatmapRS(mSoftwareBitmap, mHardwareBitmap,
mCompareBitmap);
mCompareImageView.setImageBitmap(mCompareBitmap);
break;
}
mCompareImageView.getDrawable().setFilterBitmap(false);
mCompareImageView.invalidate();
}
mLastCompareImageViewState = mCompareImageViewState;
mRedrewFlag = false;
mHandler.removeCallbacks(mRunnable);
}
};
private void redrawViews() {
mHardwareView.invalidate();
mSoftwareView.invalidate();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.manual_layout);
onCreateCommon(mRunnable);
mSoftwareView = (MainView) findViewById(R.id.software_view);
mSoftwareView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mSoftwareView.setBackgroundColor(Color.WHITE);
mSoftwareView.addDrawCallback(mDrawCallback);
mCompareImageView = (ImageView) findViewById(R.id.compare_image_view);
int width = getResources().getDimensionPixelSize(R.dimen.layer_width);
int height = getResources().getDimensionPixelSize(R.dimen.layer_height);
mCompareBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mErrorTextView = (TextView) findViewById(R.id.current_error);
((ImageButton) findViewById(R.id.next)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
DisplayModifier.step();
updateSpinners();
redrawViews();
}
});
((ImageButton) findViewById(R.id.previous)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
DisplayModifier.stepBack();
updateSpinners();
redrawViews();
}
});
((Button) findViewById(R.id.show_hardware_version))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCompareImageViewState = COMPARE_VIEW_HARDWARE;
mHandler.post(mRunnable);
}
});
((Button) findViewById(R.id.show_software_version))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCompareImageViewState = COMPARE_VIEW_SOFTWARE;
mHandler.post(mRunnable);
}
});
((Button) findViewById(R.id.show_error_heatmap)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCompareImageViewState = COMPARE_VIEW_HEATMAP;
mHandler.post(mRunnable);
}
});
buildSpinnerLayout();
}
private class DisplayModifierSpinner extends Spinner {
private final int mIndex;
public DisplayModifierSpinner(int index) {
super(ManualActivity.this);
mIndex = index;
setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItem,
int position, long id) {
DisplayModifier.setIndex(mIndex, position);
redrawViews();
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
}
});
}
}
private Spinner[] mSpinners;
private void buildSpinnerLayout() {
LinearLayout layout = (LinearLayout) findViewById(R.id.spinner_layout);
String[][] mapsStrings = DisplayModifier.getStrings();
mSpinners = new Spinner[mapsStrings.length];
int index = 0;
for (String[] spinnerValues : mapsStrings) {
mSpinners[index] = new DisplayModifierSpinner(index);
mSpinners[index].setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_dropdown_item, spinnerValues));
layout.addView(mSpinners[index]);
index++;
}
Log.d(LOG_TAG, "created " + index + " spinners");
}
private void updateSpinners() {
int[] indices = DisplayModifier.getIndices();
for (int i = 0; i < mSpinners.length; i++) {
mSpinners[i].setSelection(indices[i]);
}
}
@Override
protected boolean forceRecreateBitmaps() {
// continually recreate bitmaps to avoid modifying bitmaps currently being drawn
return true;
}
}

View File

@@ -1,136 +0,0 @@
/*
* Copyright (C) 2012 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.test.hwuicompare;
import com.android.test.hwuicompare.R;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.SweepGradient;
import android.graphics.Matrix;
import android.graphics.Shader;
public class ResourceModifiers {
public final BitmapShader mRepeatShader;
public final BitmapShader mTranslatedShader;
public final BitmapShader mScaledShader;
private final int mTexWidth;
private final int mTexHeight;
private final float mDrawWidth;
private final float mDrawHeight;
public final LinearGradient mHorGradient;
public final LinearGradient mDiagGradient;
public final LinearGradient mVertGradient;
public final RadialGradient mRadGradient;
public final SweepGradient mSweepGradient;
public final ComposeShader mComposeShader;
public final ComposeShader mBadComposeShader;
public final ComposeShader mAnotherBadComposeShader;
public final Bitmap mBitmap;
private final Matrix mMtx1;
private final Matrix mMtx2;
private final Matrix mMtx3;
public final float[] mBitmapVertices;
public final int[] mBitmapColors;
private static ResourceModifiers sInstance = null;
public static ResourceModifiers instance() { return sInstance; }
public static void init(Resources resources) {
sInstance = new ResourceModifiers(resources);
}
public ResourceModifiers(Resources resources) {
mBitmap = BitmapFactory.decodeResource(resources, R.drawable.sunset1);
mTexWidth = mBitmap.getWidth();
mTexHeight = mBitmap.getHeight();
mDrawWidth = resources.getDimensionPixelSize(R.dimen.layer_width);
mDrawHeight = resources.getDimensionPixelSize(R.dimen.layer_height);
mRepeatShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
mTranslatedShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT,
Shader.TileMode.REPEAT);
mMtx1 = new Matrix();
mMtx1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
mMtx1.postRotate(45, 0, 0);
mTranslatedShader.setLocalMatrix(mMtx1);
mScaledShader = new BitmapShader(mBitmap, Shader.TileMode.MIRROR,
Shader.TileMode.MIRROR);
mMtx2 = new Matrix();
mMtx2.setScale(0.5f, 0.5f);
mScaledShader.setLocalMatrix(mMtx2);
mHorGradient = new LinearGradient(0.0f, 0.0f, 1.0f, 0.0f,
Color.RED, Color.GREEN, Shader.TileMode.CLAMP);
mMtx3 = new Matrix();
mMtx3.setScale(mDrawHeight, 1.0f);
mMtx3.postRotate(-90.0f);
mMtx3.postTranslate(0.0f, mDrawHeight);
mHorGradient.setLocalMatrix(mMtx3);
mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 2.0f, mDrawHeight / 2.0f,
Color.BLUE, Color.RED, Shader.TileMode.CLAMP);
mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
mSweepGradient = new SweepGradient(mDrawWidth / 2.0f, mDrawHeight / 2.0f,
Color.YELLOW, Color.MAGENTA);
mComposeShader = new ComposeShader(mRepeatShader, mHorGradient,
PorterDuff.Mode.MULTIPLY);
final float width = mBitmap.getWidth() / 8.0f;
final float height = mBitmap.getHeight() / 8.0f;
mBitmapVertices = new float[] {
0.0f, 0.0f, width, 0.0f, width * 2, 0.0f, width * 3, 0.0f,
0.0f, height, width, height, width * 2, height, width * 4, height,
0.0f, height * 2, width, height * 2, width * 2, height * 2, width * 3, height * 2,
0.0f, height * 4, width, height * 4, width * 2, height * 4, width * 4, height * 4,
};
mBitmapColors = new int[] {
0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff0000,
0xff0000ff, 0xffff0000, 0xff00ff00, 0xff00ff00,
0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00,
0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ff0000,
};
// Use a repeating gradient with many colors to test the non simple case.
mRadGradient = new RadialGradient(mDrawWidth / 4.0f, mDrawHeight / 4.0f, 4.0f,
mBitmapColors, null, Shader.TileMode.REPEAT);
mBadComposeShader = new ComposeShader(mRadGradient, mComposeShader,
PorterDuff.Mode.MULTIPLY);
mAnotherBadComposeShader = new ComposeShader(mRadGradient, mVertGradient,
PorterDuff.Mode.MULTIPLY);
}
}

View File

@@ -1,46 +0,0 @@
package com.android.test.hwuicompare;
import com.android.test.hwuicompare.AutomaticActivity.FinalCallback;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
public class Test extends ActivityInstrumentationTestCase2<AutomaticActivity> {
AutomaticActivity mActivity;
private Bundle mBundle;
public Test() {
super(AutomaticActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mBundle = new Bundle();
mActivity = getActivity();
mActivity.setFinalCallback(new FinalCallback() {
@Override
void report(String key, float value) {
mBundle.putFloat(key, value);
}
@Override
void complete() {
synchronized(mBundle) {
mBundle.notify();
}
}
});
}
public void testCanvas() {
synchronized(mBundle) {
try {
mBundle.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
getInstrumentation().sendStatus(0, mBundle);
}
}

View File

@@ -1,61 +0,0 @@
#pragma version(1)
#pragma rs java_package_name(com.android.test.hwuicompare)
int REGION_SIZE;
int WIDTH;
int HEIGHT;
rs_allocation ideal;
rs_allocation given;
void countInterestingRegions(const int32_t *v_in, int32_t *v_out) {
int y = v_in[0];
v_out[0] = 0;
for (int x = 0; x < HEIGHT; x += REGION_SIZE) {
bool interestingRegion = false;
uchar4 regionColor = rsGetElementAt_uchar4(ideal, x, y);
for (int i = 0; i < REGION_SIZE && !interestingRegion; i++) {
for (int j = 0; j < REGION_SIZE && !interestingRegion; j++) {
uchar4 testVal = rsGetElementAt_uchar4(ideal, x + j, y + i);
interestingRegion |= (testVal.r != regionColor.r);
interestingRegion |= (testVal.g != regionColor.g);
interestingRegion |= (testVal.b != regionColor.b);
interestingRegion |= (testVal.a != regionColor.a);
}
}
if (interestingRegion) {
v_out[0]++;
}
}
}
void accumulateError(const int32_t *v_in, int32_t *v_out) {
int startY = v_in[0];
int error = 0;
for (int y = startY; y < startY + REGION_SIZE; y++) {
for (int x = 0; x < HEIGHT; x++) {
uchar4 idealPixel = rsGetElementAt_uchar4(ideal, x, y);
uchar4 givenPixel = rsGetElementAt_uchar4(given, x, y);
error += abs(idealPixel.x - givenPixel.x);
error += abs(idealPixel.y - givenPixel.y);
error += abs(idealPixel.z - givenPixel.z);
error += abs(idealPixel.w - givenPixel.w);
}
}
v_out[0] = error;
}
void displayDifference(const uchar4 *v_in, uchar4 *v_out, uint32_t x, uint32_t y) {
float4 idealPixel = rsGetElementAt_float4(ideal, x, y);
float4 givenPixel = rsGetElementAt_float4(given, x, y);
float4 diff = idealPixel - givenPixel;
float totalDiff = diff.x + diff.y + diff.z + diff.w;
if (totalDiff < 0) {
v_out[0] = rsPackColorTo8888(0, 0, clamp(-totalDiff/2.f, 0.f, 1.f));
} else {
v_out[0] = rsPackColorTo8888(clamp(totalDiff/2.f, 0.f, 1.f), 0, 0);
}
}