diff options
Diffstat (limited to 'tests')
51 files changed, 3736 insertions, 235 deletions
diff --git a/tests/BrowserTestPlugin/jni/PluginObject.h b/tests/BrowserTestPlugin/jni/PluginObject.h index a058d4a..037367e 100644 --- a/tests/BrowserTestPlugin/jni/PluginObject.h +++ b/tests/BrowserTestPlugin/jni/PluginObject.h @@ -65,7 +65,7 @@ class SubPlugin { public: SubPlugin(NPP inst) : m_inst(inst) {} virtual ~SubPlugin() {} - virtual int16 handleEvent(const ANPEvent* evt) = 0; + virtual int16_t handleEvent(const ANPEvent* evt) = 0; NPP inst() const { return m_inst; } diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp index 2eff394..91f1b3d 100644 --- a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp +++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp @@ -138,7 +138,7 @@ void EventPlugin::printToDiv(const char* text, int length) { browser->memfree(beginMem); } -int16 EventPlugin::handleEvent(const ANPEvent* evt) { +int16_t EventPlugin::handleEvent(const ANPEvent* evt) { switch (evt->eventType) { case kDraw_ANPEventType: { diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h index 88b7c9d..043be85 100644 --- a/tests/BrowserTestPlugin/jni/event/EventPlugin.h +++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h @@ -32,7 +32,7 @@ class EventPlugin : public SubPlugin { public: EventPlugin(NPP inst); virtual ~EventPlugin(); - virtual int16 handleEvent(const ANPEvent* evt); + virtual int16_t handleEvent(const ANPEvent* evt); private: void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip); diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp index 402a7e2..511180c 100644 --- a/tests/BrowserTestPlugin/jni/main.cpp +++ b/tests/BrowserTestPlugin/jni/main.cpp @@ -34,19 +34,19 @@ NPNetscapeFuncs* browser; #define EXPORT __attribute__((visibility("default"))) -NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved); NPError NPP_Destroy(NPP instance, NPSavedData** save); NPError NPP_SetWindow(NPP instance, NPWindow* window); NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, - NPBool seekable, uint16* stype); + NPBool seekable, uint16_t* stype); NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); -int32 NPP_WriteReady(NPP instance, NPStream* stream); -int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, +int32_t NPP_WriteReady(NPP instance, NPStream* stream); +int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer); void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); void NPP_Print(NPP instance, NPPrint* platformPrint); -int16 NPP_HandleEvent(NPP instance, void* event); +int16_t NPP_HandleEvent(NPP instance, void* event); void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, void* notifyData); NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); @@ -129,7 +129,7 @@ const char *NP_GetMIMEDescription(void) return "application/x-browsertestplugin:btp:Android Browser Test Plugin"; } -NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved) { @@ -188,7 +188,7 @@ NPError NPP_SetWindow(NPP instance, NPWindow* window) return NPERR_NO_ERROR; } -NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) { *stype = NP_ASFILEONLY; return NPERR_NO_ERROR; @@ -199,12 +199,12 @@ NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) return NPERR_NO_ERROR; } -int32 NPP_WriteReady(NPP instance, NPStream* stream) +int32_t NPP_WriteReady(NPP instance, NPStream* stream) { return 0; } -int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer) +int32_t NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer) { return 0; } @@ -217,7 +217,7 @@ void NPP_Print(NPP instance, NPPrint* platformPrint) { } -int16 NPP_HandleEvent(NPP instance, void* event) +int16_t NPP_HandleEvent(NPP instance, void* event) { PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event); diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk index 012e5eb..5abfc88 100644 --- a/tests/CoreTests/android/Android.mk +++ b/tests/CoreTests/android/Android.mk @@ -6,7 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ $(call all-subdir-java-files) -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle LOCAL_PACKAGE_NAME := CoreTests diff --git a/tests/CoreTests/android/core/CryptoTest.java b/tests/CoreTests/android/core/CryptoTest.java deleted file mode 100644 index e6e50ec..0000000 --- a/tests/CoreTests/android/core/CryptoTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.core; - -import junit.framework.Assert; -import junit.framework.TestCase; - -import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.digests.MD4Digest; -import org.bouncycastle.crypto.digests.MD5Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.MediumTest; - -/** - * Implements unit tests for our JNI wrapper around OpenSSL. We use the - * existing Bouncy Castle implementation as our test oracle. - */ -public class CryptoTest extends TestCase { - - /** - * Processes the two given message digests for the same data and checks - * the results. Requirement is that the results must be equal, the digest - * implementations must have the same properties, and the new implementation - * must be faster than the old one. - * - * @param oldDigest The old digest implementation, provided by Bouncy Castle - * @param newDigest The new digest implementation, provided by OpenSSL - */ - public void doTestMessageDigest(Digest oldDigest, Digest newDigest) { - final int ITERATIONS = 10; - - byte[] data = new byte[1024]; - - byte[] oldHash = new byte[oldDigest.getDigestSize()]; - byte[] newHash = new byte[newDigest.getDigestSize()]; - - Assert.assertEquals("Hash names must be equal", oldDigest.getAlgorithmName(), newDigest.getAlgorithmName()); - Assert.assertEquals("Hash sizes must be equal", oldHash.length, newHash.length); - Assert.assertEquals("Hash block sizes must be equal", ((ExtendedDigest)oldDigest).getByteLength(), ((ExtendedDigest)newDigest).getByteLength()); - for (int i = 0; i < data.length; i++) { - data[i] = (byte)i; - } - - long oldTime = 0; - long newTime = 0; - - for (int j = 0; j < ITERATIONS; j++) { - long t0 = System.currentTimeMillis(); - for (int i = 0; i < 4; i++) { - oldDigest.update(data, 0, data.length); - } - int oldLength = oldDigest.doFinal(oldHash, 0); - long t1 = System.currentTimeMillis(); - - oldTime = oldTime + (t1 - t0); - - long t2 = System.currentTimeMillis(); - for (int i = 0; i < 4; i++) { - newDigest.update(data, 0, data.length); - } - int newLength = newDigest.doFinal(newHash, 0); - long t3 = System.currentTimeMillis(); - - newTime = newTime + (t3 - t2); - - Assert.assertEquals("Hash sizes must be equal", oldLength, newLength); - - for (int i = 0; i < oldLength; i++) { - Assert.assertEquals("Hashes[" + i + "] must be equal", oldHash[i], newHash[i]); - } - } - - android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms"); - android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms"); - - // Assert.assertTrue("New hash should be faster", newTime < oldTime); - } - - /** - * Tests the MD4 implementation. - */ - @MediumTest - public void testMD4() { - Digest oldDigest = new MD4Digest(); - Digest newDigest = OpenSSLMessageDigest.getInstance("MD4"); - doTestMessageDigest(oldDigest, newDigest); - } - - /** - * Tests the MD5 implementation. - */ - @MediumTest - public void testMD5() { - Digest oldDigest = new MD5Digest(); - Digest newDigest = OpenSSLMessageDigest.getInstance("MD5"); - doTestMessageDigest(oldDigest, newDigest); - } - - /** - * Tests the SHA-1 implementation. - */ - @MediumTest - public void testSHA1() { - Digest oldDigest = new SHA1Digest(); - Digest newDigest = OpenSSLMessageDigest.getInstance("SHA-1"); - doTestMessageDigest(oldDigest, newDigest); - } - -} diff --git a/tests/DumpRenderTree/assets/run_layout_tests.py b/tests/DumpRenderTree/assets/run_layout_tests.py index b6e7bf3..ceac5d2 100755 --- a/tests/DumpRenderTree/assets/run_layout_tests.py +++ b/tests/DumpRenderTree/assets/run_layout_tests.py @@ -176,7 +176,7 @@ def main(options, args): # Count crashed tests. crashed_tests = [] - timeout_ms = '30000' + timeout_ms = '15000' if options.time_out_ms: timeout_ms = options.time_out_ms diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java index 5780c43..a5870f8 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java @@ -74,6 +74,8 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42; private static final int SET_GEOLOCATION_PERMISSION = 43; private static final int OVERRIDE_PREFERENCE = 44; + private static final int LAYOUT_DUMP_CHILD_FRAMES_TEXT = 45; + private static final int SET_XSS_AUDITOR_ENABLED = 46; CallbackProxy(EventSender eventSender, LayoutTestController layoutTestController) { @@ -178,6 +180,10 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon mLayoutTestController.dumpAsText(); break; + case LAYOUT_DUMP_CHILD_FRAMES_TEXT: + mLayoutTestController.dumpChildFramesAsText(); + break; + case LAYOUT_DUMP_HISTORY: mLayoutTestController.dumpBackForwardList(); break; @@ -273,6 +279,10 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon boolean value = msg.getData().getBoolean("value"); mLayoutTestController.overridePreference(key, value); break; + + case SET_XSS_AUDITOR_ENABLED: + mLayoutTestController.setXSSAuditorEnabled(msg.arg1 == 1); + break; } } @@ -380,6 +390,10 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon obtainMessage(LAYOUT_DUMP_TEXT).sendToTarget(); } + public void dumpChildFramesAsText() { + obtainMessage(LAYOUT_DUMP_CHILD_FRAMES_TEXT).sendToTarget(); + } + public void dumpBackForwardList() { obtainMessage(LAYOUT_DUMP_HISTORY).sendToTarget(); } @@ -498,4 +512,8 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon message.getData().putBoolean("value", value); message.sendToTarget(); } + + public void setXSSAuditorEnabled(boolean flag) { + obtainMessage(SET_XSS_AUDITOR_ENABLED, flag ? 1 : 0, 0).sendToTarget(); + } } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java index 77fd3ed..8bdf77c 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java @@ -73,30 +73,40 @@ public class FileFilter { static final String[] ignoreTestList = { "editing/selection/move-left-right.html", // Causes DumpRenderTree to hang + "fast/js/excessive-comma-usage.html", // Tests huge initializer list, causes OOM. "fast/js/regexp-charclass-crash.html", // RegExp is too large, causing OOM "fast/regex/test1.html", // Causes DumpRenderTree to hang with V8 "fast/regex/slow.html" // Causes DumpRenderTree to hang with V8 }; static void fillIgnoreResultList() { - // This first block of tests are for HTML5 features, for which Android + // This first block of tests are for features for which Android // should pass all tests. They are skipped only temporarily. // TODO: Fix these failing tests and remove them from this list. + ignoreResultList.add("fast/events/touch/basic-multi-touch-events.html"); // Requires multi-touch + ignoreResultList.add("fast/events/touch/touch-target.html"); // Requires multi-touch ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky + ignoreResultList.add("http/tests/appcache/fallback.html"); // http://b/issue?id=2713004 ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky ignoreResultList.add("storage/database-lock-after-reload.html"); // Succeeds but DumpRenderTree does not read result correctly ignoreResultList.add("storage/hash-change-with-xhr.html"); // Succeeds but DumpRenderTree does not read result correctly - - // Will always fail - ignoreResultList.add("dom/svg/level3/xpath"); // XPath not supported + ignoreResultList.add("storage/open-database-creation-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld() + ignoreResultList.add("storage/statement-error-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld() + ignoreResultList.add("storage/statement-success-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld() + ignoreResultList.add("storage/transaction-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld() + ignoreResultList.add("storage/transaction-error-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld() + ignoreResultList.add("storage/transaction-success-callback-isolated-world.html"); // Requires layoutTestController.evaluateScriptInIsolatedWorld() + + // Expected failures due to unsupported features. + ignoreResultList.add("fast/events/touch/touch-coords-in-zoom-and-scroll.html"); // Requires eventSender.zoomPageIn(),zoomPageOut() ignoreResultList.add("fast/workers"); // workers not supported - ignoreResultList.add("fast/xpath"); // XPath not supported ignoreResultList.add("http/tests/eventsource/workers"); // workers not supported ignoreResultList.add("http/tests/workers"); // workers not supported ignoreResultList.add("http/tests/xmlhttprequest/workers"); // workers not supported ignoreResultList.add("storage/domstorage/localstorage/private-browsing-affects-storage.html"); // private browsing not supported ignoreResultList.add("storage/domstorage/sessionstorage/private-browsing-affects-storage.html"); // private browsing not supported + ignoreResultList.add("storage/indexeddb"); // indexeddb not supported ignoreResultList.add("storage/private-browsing-readonly.html"); // private browsing not supported ignoreResultList.add("websocket/tests/workers"); // workers not supported @@ -104,12 +114,9 @@ public class FileFilter { ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707 ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin - ignoreResultList.add("fast/dom/Window/window-properties.html"); // xslt and xpath elements missing from property list ignoreResultList.add("fast/dom/Window/window-screen-properties.html"); // pixel depth ignoreResultList.add("fast/dom/Window/window-xy-properties.html"); // requires eventSender.mouseDown(),mouseUp() ignoreResultList.add("fast/dom/attribute-namespaces-get-set.html"); // http://b/733229 - ignoreResultList.add("fast/dom/gc-9.html"); // requires xpath support - ignoreResultList.add("fast/dom/global-constructors.html"); // requires xslt and xpath support ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html"); // dynamic plugins not supported ignoreResultList.add("fast/dom/tabindex-clamp.html"); // there is extra spacing in the file due to multiple input boxes fitting on one line on Apple, ours are wrapped. Space at line ends are stripped. ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html"); // requires eventSender.mouseDown(),mouseUp() @@ -172,8 +179,6 @@ public class FileFilter { ignoreResultList.add("fast/replaced/image-map.html"); // requires eventSender.mouseDown(),mouseUp() ignoreResultList.add("fast/text/plain-text-line-breaks.html"); // extra spacing because iFrames rendered next to each other on Apple ignoreResultList.add("profiler"); // profiler is not supported - ignoreResultList.add("svg"); // svg is not supported - } } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java index 322b0d2..4475e92 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java @@ -42,8 +42,13 @@ public class FsUtils { //no creation of instances } - public static void findLayoutTestsRecursively(BufferedOutputStream bos, + /** + * @return the number of tests in the list. + */ + public static int writeLayoutTestListRecursively(BufferedOutputStream bos, String dir, boolean ignoreResultsInDir) throws IOException { + + int testCount = 0; Log.v(LOGTAG, "Searching tests under " + dir); File d = new File(dir); @@ -61,7 +66,7 @@ public class FsUtils { // If this is not a test directory, we don't recurse into it. if (!FileFilter.isNonTestDir(s)) { Log.v(LOGTAG, "Recursing on " + s); - findLayoutTestsRecursively(bos, s, ignoreResultsInDir); + testCount += writeLayoutTestListRecursively(bos, s, ignoreResultsInDir); } continue; } @@ -72,7 +77,9 @@ public class FsUtils { continue; } - if ((s.toLowerCase().endsWith(".html") || s.toLowerCase().endsWith(".xml")) + if ((s.toLowerCase().endsWith(".html") + || s.toLowerCase().endsWith(".xml") + || s.toLowerCase().endsWith(".xhtml")) && !s.endsWith("TEMPLATE.html")) { Log.v(LOGTAG, "Recording " + s); bos.write(s.getBytes()); @@ -81,8 +88,10 @@ public class FsUtils { bos.write((" IGNORE_RESULT").getBytes()); } bos.write('\n'); + testCount++; } } + return testCount; } public static void updateTestStatus(String statusFile, String s) { diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java index 9236345..83460bd 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java @@ -19,6 +19,7 @@ package com.android.dumprendertree; public interface LayoutTestController { public void dumpAsText(); + public void dumpChildFramesAsText(); public void waitUntilDone(); public void notifyDone(); @@ -67,4 +68,7 @@ public interface LayoutTestController { public void setGeolocationPermission(boolean allow); public void overridePreference(String key, boolean value); + + // For XSSAuditor tests + public void setXSSAuditorEnabled(boolean flag); } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java index 042158a..3618c7b 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -18,12 +18,9 @@ package com.android.dumprendertree; import com.android.dumprendertree.TestShellActivity.DumpDataType; import com.android.dumprendertree.forwarder.AdbUtils; -import com.android.dumprendertree.forwarder.ForwardServer; import com.android.dumprendertree.forwarder.ForwardService; -import android.app.Instrumentation; import android.content.Intent; -import android.os.Bundle; import android.test.ActivityInstrumentationTestCase2; import android.util.Log; @@ -156,18 +153,11 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh private String mJsEngine; private String mTestPathPrefix; private boolean mFinished; + private int mTestCount; + private int mResumeIndex; public LayoutTestsAutoTest() { - super("com.android.dumprendertree", TestShellActivity.class); - } - - // This function writes the result of the layout test to - // Am status so that it can be picked up from a script. - private void passOrFailCallback(String file, boolean result) { - Instrumentation inst = getInstrumentation(); - Bundle bundle = new Bundle(); - bundle.putBoolean(file, result); - inst.sendStatus(0, bundle); + super(TestShellActivity.class); } private void getTestList() { @@ -188,6 +178,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } catch (Exception e) { Log.e(LOGTAG, "Error while reading test list : " + e.getMessage()); } + mTestCount = mTestList.size(); } private void resumeTestList() { @@ -198,6 +189,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh if (mTestList.elementAt(i).equals(line)) { mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size())); mTestListIgnoreResult = new Vector<Boolean>(mTestListIgnoreResult.subList(i+1, mTestListIgnoreResult.size())); + mResumeIndex = i + 1; break; } } @@ -230,14 +222,22 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh // The generic result is at <path>/<name>-expected.txt // First try the Android-specific result at // platform/android-<js-engine>/<path>/<name>-expected.txt + // then + // platform/android/<path>/<name>-expected.txt int pos = test.lastIndexOf('.'); if (pos == -1) return null; String genericExpectedResult = test.substring(0, pos) + "-expected.txt"; String androidExpectedResultsDir = "platform/android-" + mJsEngine + "/"; - String androidExpectedResult = - genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_ROOT + androidExpectedResultsDir); + String androidExpectedResult = genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT, + LAYOUT_TESTS_ROOT + androidExpectedResultsDir); File f = new File(androidExpectedResult); + if (f.exists()) + return androidExpectedResult; + androidExpectedResultsDir = "platform/android/"; + androidExpectedResult = genericExpectedResult.replaceFirst(LAYOUT_TESTS_ROOT, + LAYOUT_TESTS_ROOT + androidExpectedResultsDir); + f = new File(androidExpectedResult); return f.exists() ? androidExpectedResult : genericExpectedResult; } @@ -298,7 +298,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } } - private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult) { + private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout, boolean ignoreResult, int testNumber) { activity.setCallback(new TestShellCallback() { public void finished() { synchronized (LayoutTestsAutoTest.this) { @@ -334,6 +334,9 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test)); intent.putExtra(TestShellActivity.RESULT_FILE, resultFile); intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout); + intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, mTestCount); + intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, testNumber); + intent.putExtra(TestShellActivity.STOP_ON_REF_ERROR, true); activity.startActivity(intent); // Wait until done. @@ -373,8 +376,8 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh // Read settings mTestPathPrefix = (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getAbsolutePath(); mRebaselineResults = runner.mRebaseline; - // JSC is the default JavaScript engine. - mJsEngine = runner.mJsEngine == null ? "jsc" : runner.mJsEngine; + // V8 is the default JavaScript engine. + mJsEngine = runner.mJsEngine == null ? "v8" : runner.mJsEngine; int timeout = runner.mTimeoutInMillis; if (timeout <= 0) { @@ -391,7 +394,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh resumeTestList(); TestShellActivity activity = getActivity(); - activity.setDefaultDumpDataType(DumpDataType.DUMP_AS_TEXT); + activity.setDefaultDumpDataType(DumpDataType.EXT_REPR); // Run tests. int addr = -1; @@ -408,7 +411,9 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh boolean ignoreResult = mTestListIgnoreResult.elementAt(i); FsUtils.updateTestStatus(TEST_STATUS_FILE, s); // Run tests - runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult); + // i is 0 based, but test count is 1 based so add 1 to i here. + runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis, ignoreResult, + i + 1 + mResumeIndex); } FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE"); @@ -433,7 +438,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh try { File tests_list = new File(LAYOUT_TESTS_LIST_FILE); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false)); - FsUtils.findLayoutTestsRecursively(bos, getTestPath(), false); // Don't ignore results + FsUtils.writeLayoutTestListRecursively(bos, getTestPath(), false); // Don't ignore results bos.flush(); bos.close(); } catch (Exception e) { diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java index 82671eb..5ffe6b0 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java @@ -51,29 +51,38 @@ public class Menu extends FileList { intent.setClass(this, TestShellActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.putExtra(TestShellActivity.TEST_URL, "file://" + filename); + intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, 1); + intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 1); startActivity(intent); } @Override void processDirectory(String path, boolean selection) { - generateTestList(path); + int testCount = generateTestList(path); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setClass(this, TestShellActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.putExtra(TestShellActivity.UI_AUTO_TEST, LAYOUT_TESTS_LIST_FILE); + intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, testCount); + // TestShellActivity will process this intent once and increment the test index + // before running the first test, so pass 0 here to allow for that. + intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, 0); startActivity(intent); } - private void generateTestList(String path) { + private int generateTestList(String path) { + int testCount = 0; try { File tests_list = new File(LAYOUT_TESTS_LIST_FILE); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false)); - FsUtils.findLayoutTestsRecursively(bos, path, false); // Don't ignore results + testCount = FsUtils.writeLayoutTestListRecursively( + bos, path, false); // Don't ignore results bos.flush(); bos.close(); } catch (Exception e) { Log.e(LOGTAG, "Error when creating test list: " + e.getMessage()); } + return testCount; } } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 81d5b08..bf66fae 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -34,6 +34,8 @@ import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.ViewGroup; +import android.view.Window; +import android.webkit.ConsoleMessage; import android.webkit.GeolocationPermissions; import android.webkit.HttpAuthHandler; import android.webkit.JsPromptResult; @@ -98,6 +100,8 @@ public class TestShellActivity extends Activity implements LayoutTestController Log.v(LOGTAG, "message sent to WebView to dump text."); switch (mDumpDataType) { case DUMP_AS_TEXT: + callback.arg1 = mDumpTopFrameAsText ? 1 : 0; + callback.arg2 = mDumpChildFramesAsText ? 1 : 0; mWebView.documentAsText(callback); break; case EXT_REPR: @@ -116,6 +120,7 @@ public class TestShellActivity extends Activity implements LayoutTestController @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); + requestWindowFeature(Window.FEATURE_PROGRESS); LinearLayout contentView = new LinearLayout(this); contentView.setOrientation(LinearLayout.VERTICAL); @@ -158,6 +163,9 @@ public class TestShellActivity extends Activity implements LayoutTestController return; } + mTotalTestCount = intent.getIntExtra(TOTAL_TEST_COUNT, mTotalTestCount); + mCurrentTestNumber = intent.getIntExtra(CURRENT_TEST_NUMBER, mCurrentTestNumber); + mTestUrl = intent.getStringExtra(TEST_URL); if (mTestUrl == null) { mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST); @@ -171,6 +179,11 @@ public class TestShellActivity extends Activity implements LayoutTestController mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0); mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false); mSaveImagePath = intent.getStringExtra(SAVE_IMAGE); + mStopOnRefError = intent.getBooleanExtra(STOP_ON_REF_ERROR, false); + setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount); + float ratio = (float)mCurrentTestNumber / mTotalTestCount; + int progress = (int)(ratio * Window.PROGRESS_END); + getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress); Log.v(LOGTAG, " Loading " + mTestUrl); mWebView.loadUrl(mTestUrl); @@ -236,6 +249,7 @@ public class TestShellActivity extends Activity implements LayoutTestController Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url)); + intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, ++mCurrentTestNumber); intent.putExtra(TIMEOUT_IN_MILLIS, 10000); executeIntent(intent); } @@ -330,12 +344,22 @@ public class TestShellActivity extends Activity implements LayoutTestController // LayoutTestController Functions public void dumpAsText() { mDumpDataType = DumpDataType.DUMP_AS_TEXT; + mDumpTopFrameAsText = true; if (mWebView != null) { String url = mWebView.getUrl(); Log.v(LOGTAG, "dumpAsText called: "+url); } } + public void dumpChildFramesAsText() { + mDumpDataType = DumpDataType.DUMP_AS_TEXT; + mDumpChildFramesAsText = true; + if (mWebView != null) { + String url = mWebView.getUrl(); + Log.v(LOGTAG, "dumpChildFramesAsText called: "+url); + } + } + public void waitUntilDone() { mWaitUntilDone = true; String url = mWebView.getUrl(); @@ -347,7 +371,9 @@ public class TestShellActivity extends Activity implements LayoutTestController Log.v(LOGTAG, "notifyDone called: " + url); if (mWaitUntilDone) { mWaitUntilDone = false; - mChromeClient.onProgressChanged(mWebView, 101); + if (!mRequestedWebKitData && !mTimedOut && !finished()) { + requestWebKitData(); + } } } @@ -472,6 +498,10 @@ public class TestShellActivity extends Activity implements LayoutTestController } } + public void setXSSAuditorEnabled (boolean flag) { + mWebView.getSettings().setXSSAuditorEnabled(flag); + } + private final WebViewClient mViewClient = new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { @@ -489,11 +519,30 @@ public class TestShellActivity extends Activity implements LayoutTestController drawPageToFile(mSaveImagePath + "/" + name + ".png", mWebView); } } + // Calling finished() will check if we've met all the conditions for completing - // this test and move to the next one if we are ready. + // this test and move to the next one if we are ready. Otherwise we ask WebCore to + // dump the page. if (finished()) { return; } + + if (!mWaitUntilDone && !mRequestedWebKitData && !mTimedOut) { + requestWebKitData(); + } else { + if (mWaitUntilDone) { + Log.v(LOGTAG, "page finished loading but waiting for notifyDone to be called: " + url); + } + + if (mRequestedWebKitData) { + Log.v(LOGTAG, "page finished loading but webkit data has already been requested: " + url); + } + + if (mTimedOut) { + Log.v(LOGTAG, "page finished loading but already timed out: " + url); + } + } + super.onPageFinished(view, url); } @@ -535,44 +584,8 @@ public class TestShellActivity extends Activity implements LayoutTestController private final WebChromeClient mChromeClient = new WebChromeClient() { @Override - public void onProgressChanged(WebView view, int newProgress) { - - // notifyDone calls this with 101%. We only want to update this flag if this - // is the real call from WebCore. - if (newProgress == 100) { - mOneHundredPercentComplete = true; - } - - // With the flag updated, we can now proceed as normal whether the progress update came from - // WebCore or notifyDone. - if (newProgress >= 100) { - // finished() will check if we are ready to move to the next test and do so if we are. - if (finished()) { - return; - } - - if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) { - String url = mWebView.getUrl(); - Log.v(LOGTAG, "Finished: "+ url); - requestWebKitData(); - } else { - String url = mWebView.getUrl(); - if (mTimedOut) { - Log.v(LOGTAG, "Timed out before finishing: " + url); - } else if (mWaitUntilDone) { - Log.v(LOGTAG, "Waiting for notifyDone: " + url); - } else if (mRequestedWebKitData) { - Log.v(LOGTAG, "Requested webkit data ready: " + url); - } - } - } - } - - @Override public void onReceivedTitle(WebView view, String title) { - if (title.length() > 30) - title = "..."+title.substring(title.length()-30); - setTitle(title); + setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount + ": "+ title); if (mDumpTitleChanges) { mTitleChanges.append("TITLE CHANGED: "); mTitleChanges.append(title); @@ -675,15 +688,28 @@ public class TestShellActivity extends Activity implements LayoutTestController } @Override - public void onConsoleMessage(String message, int lineNumber, - String sourceID) { + public boolean onConsoleMessage(ConsoleMessage consoleMessage) { + String msg = "CONSOLE MESSAGE: line " + consoleMessage.lineNumber() + ": " + + consoleMessage.message() + "\n"; if (mConsoleMessages == null) { mConsoleMessages = new StringBuffer(); } - String consoleMessage = "CONSOLE MESSAGE: line " - + lineNumber +": "+ message +"\n"; - mConsoleMessages.append(consoleMessage); - Log.v(LOGTAG, "LOG: "+consoleMessage); + mConsoleMessages.append(msg); + Log.v(LOGTAG, "LOG: " + msg); + // the rationale here is that if there's an error of either type, and the test was + // waiting for "notifyDone" signal to finish, then there's no point in waiting + // anymore because the JS execution is already terminated at this point and a + // "notifyDone" will never come out so it's just wasting time till timeout kicks in + if ((msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:")) + && mWaitUntilDone && mStopOnRefError) { + Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError."); + mHandler.postDelayed(new Runnable() { + public void run() { + notifyDone(); + } + }, 500); + } + return true; } @Override @@ -729,6 +755,8 @@ public class TestShellActivity extends Activity implements LayoutTestController private void resetTestStatus() { mWaitUntilDone = false; mDumpDataType = mDefaultDumpDataType; + mDumpTopFrameAsText = false; + mDumpChildFramesAsText = false; mTimedOut = false; mDumpTitleChanges = false; mRequestedWebKitData = false; @@ -738,10 +766,10 @@ public class TestShellActivity extends Activity implements LayoutTestController mEventSender.clearTouchPoints(); mEventSender.clearTouchMetaState(); mPageFinished = false; - mOneHundredPercentComplete = false; mDumpWebKitData = false; mGetDrawtime = false; mSaveImagePath = null; + setDefaultWebSettings(mWebView); } private long[] getDrawWebViewTime(WebView view, int count) { @@ -778,7 +806,7 @@ public class TestShellActivity extends Activity implements LayoutTestController } private boolean canMoveToNextTest() { - return (mDumpWebKitData && mOneHundredPercentComplete && mPageFinished && !mWaitUntilDone) || mTimedOut; + return (mDumpWebKitData && mPageFinished && !mWaitUntilDone) || mTimedOut; } private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) { @@ -786,6 +814,19 @@ public class TestShellActivity extends Activity implements LayoutTestController return; } + setDefaultWebSettings(webview); + + webview.setWebChromeClient(mChromeClient); + webview.setWebViewClient(mViewClient); + // Setting a touch interval of -1 effectively disables the optimisation in WebView + // that stops repeated touch events flooding WebCore. The Event Sender only sends a + // single event rather than a stream of events (like what would generally happen in + // a real use of touch events in a WebView) and so if the WebView drops the event, + // the test will fail as the test expects one callback for every touch it synthesizes. + webview.setTouchInterval(-1); + } + + public void setDefaultWebSettings(WebView webview) { WebSettings settings = webview.getSettings(); settings.setAppCacheEnabled(true); settings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); @@ -798,15 +839,7 @@ public class TestShellActivity extends Activity implements LayoutTestController settings.setDatabasePath(getDir("databases",0).getAbsolutePath()); settings.setDomStorageEnabled(true); settings.setWorkersEnabled(false); - - webview.setWebChromeClient(mChromeClient); - webview.setWebViewClient(mViewClient); - // Setting a touch interval of -1 effectively disables the optimisation in WebView - // that stops repeated touch events flooding WebCore. The Event Sender only sends a - // single event rather than a stream of events (like what would generally happen in - // a real use of touch events in a WebView) and so if the WebView drops the event, - // the test will fail as the test expects one callback for every touch it synthesizes. - webview.setTouchInterval(-1); + settings.setXSSAuditorEnabled(false); } private WebView mWebView; @@ -823,6 +856,9 @@ public class TestShellActivity extends Activity implements LayoutTestController private String mSaveImagePath; private BufferedReader mTestListReader; private boolean mGetDrawtime; + private int mTotalTestCount; + private int mCurrentTestNumber; + private boolean mStopOnRefError; // States private boolean mTimedOut; @@ -832,6 +868,8 @@ public class TestShellActivity extends Activity implements LayoutTestController // Layout test controller variables. private DumpDataType mDumpDataType; private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR; + private boolean mDumpTopFrameAsText; + private boolean mDumpChildFramesAsText; private boolean mWaitUntilDone; private boolean mDumpTitleChanges; private StringBuffer mTitleChanges; @@ -845,7 +883,6 @@ public class TestShellActivity extends Activity implements LayoutTestController private boolean mPageFinished = false; private boolean mDumpWebKitData = false; - private boolean mOneHundredPercentComplete = false; static final String TIMEOUT_STR = "**Test timeout"; @@ -860,6 +897,9 @@ public class TestShellActivity extends Activity implements LayoutTestController static final String UI_AUTO_TEST = "UiAutoTest"; static final String GET_DRAW_TIME = "GetDrawTime"; static final String SAVE_IMAGE = "SaveImage"; + static final String TOTAL_TEST_COUNT = "TestCount"; + static final String CURRENT_TEST_NUMBER = "TestNumber"; + static final String STOP_ON_REF_ERROR = "StopOnReferenceError"; static final int DRAW_RUNS = 5; static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt"; diff --git a/tests/DumpRenderTree2/Android.mk b/tests/DumpRenderTree2/Android.mk new file mode 100644 index 0000000..2aa6799 --- /dev/null +++ b/tests/DumpRenderTree2/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := DumpRenderTree2 + +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/tests/DumpRenderTree2/AndroidManifest.xml b/tests/DumpRenderTree2/AndroidManifest.xml new file mode 100644 index 0000000..14df611 --- /dev/null +++ b/tests/DumpRenderTree2/AndroidManifest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2010 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.dumprendertree2"> + <application> + <activity android:name=".ui.DirListActivity" + android:label="Dump Render Tree 2" + android:configChanges="orientation"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name=".LayoutTestsRunner" + android:label="Layout tests' runner"> + </activity> + + <activity android:name=".LayoutTestsExecuter" + android:label="Layout tests' executer" + android:process=":executer"> + </activity> + + <service android:name="ManagerService"> + </service> + </application> + + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_SDCARD" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> +</manifest>
\ No newline at end of file diff --git a/tests/DumpRenderTree2/res/drawable/folder.png b/tests/DumpRenderTree2/res/drawable/folder.png Binary files differnew file mode 100644 index 0000000..5b3fcec --- /dev/null +++ b/tests/DumpRenderTree2/res/drawable/folder.png diff --git a/tests/DumpRenderTree2/res/drawable/runtest.png b/tests/DumpRenderTree2/res/drawable/runtest.png Binary files differnew file mode 100644 index 0000000..910c654 --- /dev/null +++ b/tests/DumpRenderTree2/res/drawable/runtest.png diff --git a/tests/DumpRenderTree2/res/layout/dirlist_row.xml b/tests/DumpRenderTree2/res/layout/dirlist_row.xml new file mode 100644 index 0000000..e5578a6 --- /dev/null +++ b/tests/DumpRenderTree2/res/layout/dirlist_row.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2010 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:orientation="horizontal" + android:gravity="center_vertical" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/icon" + android:layout_width="80px" + android:adjustViewBounds="true" + android:paddingLeft="15px" + android:paddingRight="15px" + android:paddingTop="15px" + android:paddingBottom="15px" + android:layout_height="wrap_content" + /> + + <TextView + android:id="@+id/label" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:minHeight="60px" + android:gravity="center_vertical" + android:textSize="14sp" + /> + +</LinearLayout>
\ No newline at end of file diff --git a/tests/DumpRenderTree2/res/values/strings.xml b/tests/DumpRenderTree2/res/values/strings.xml new file mode 100644 index 0000000..5fd1eb9 --- /dev/null +++ b/tests/DumpRenderTree2/res/values/strings.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2010 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="dialog_run_abort_dir_title_prefix">Directory:</string> + <string name="dialog_run_abort_dir_msg">This will run all the tests in this directory and all + the subdirectories. It may take a few hours!</string> + <string name="dialog_run_abort_dir_ok_button">Run tests!</string> + <string name="dialog_run_abort_dir_abort_button">Abort</string> + + <string name="dialog_progress_title">Loading items.</string> + <string name="dialog_progress_msg">Please wait...</string> + + <string name="runner_preloading_title">Preloading tests...</string> +</resources>
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java new file mode 100644 index 0000000..3c7dee2 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.os.Bundle; +import android.os.Message; +import android.webkit.WebView; + +/** + * A class that represent a result of the test. It is responsible for returning the result's + * raw data and generating its own diff in HTML format. + */ +public abstract class AbstractResult { + + public enum TestType { + TEXT, + PIXEL + } + + public enum ResultCode { + PASS("Passed"), + FAIL_RESULT_DIFFERS("Failed: different results"), + FAIL_NO_EXPECTED_RESULT("Failed: no expected result"), + FAIL_TIMED_OUT("Failed: timed out"), + FAIL_CRASHED("Failed: crashed"); + + private String mTitle; + + private ResultCode(String title) { + mTitle = title; + } + + @Override + public String toString() { + return mTitle; + } + } + + /** + * Makes the result object obtain the results of the test from the webview + * and store them in the format that suits itself bests. This method is asynchronous. + * The message passed as a parameter is a message that should be sent to its target + * when the result finishes obtaining the result. + * + * @param webview + * @param resultObtainedMsg + */ + public abstract void obtainActualResults(WebView webview, Message resultObtainedMsg); + + public abstract void setExpectedImageResult(byte[] expectedResult); + + public abstract void setExpectedTextResult(String expectedResult); + + /** + * Returns result's image data that can be written to the disk. It can be null + * if there is an error of some sort or for example the test times out. + * + * <p> Some tests will not provide data (like text tests) + * + * @return + * results image data + */ + public abstract byte[] getActualImageResult(); + + /** + * Returns result's text data. It can be null + * if there is an error of some sort or for example the test times out. + * + * @return + * results text data + */ + public abstract String getActualTextResult(); + + /** + * Returns the code of this result. + * + * @return + * the code of this result + */ + public abstract ResultCode getResultCode(); + + /** + * Return the type of the result data. + * + * @return + * the type of the result data. + */ + public abstract TestType getType(); + + /** + * Returns a piece of HTML code that presents a visual diff between a result and + * the expected result. + * + * @return + * a piece of HTML code with a visual diff between the result and the expected result + */ + public abstract String getDiffAsHtml(); + + public abstract Bundle getBundle(); +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java new file mode 100644 index 0000000..cf82d24 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FileFilter.java @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.util.Log; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A utility to filter out some files/directories from the views and tests that run. + */ +public class FileFilter { + private static final String LOG_TAG = "FileFilter"; + + private static final String TEST_EXPECTATIONS_TXT_PATH = + "platform/android/test_expectations.txt"; + + private static final String TOKEN_SKIP = "SKIP"; + private static final String TOKEN_IGNORE_RESULT = "IGNORE_RESULT"; + private static final String TOKEN_SLOW = "SLOW"; + + private final Set<String> mSkipList = new HashSet<String>(); + private final Set<String> mIgnoreResultList = new HashSet<String>(); + private final Set<String> mSlowList = new HashSet<String>(); + + private final String mRootDirPath; + + public FileFilter(String rootDirPath) { + /** It may or may not contain a trailing slash */ + this.mRootDirPath = rootDirPath; + + reloadConfiguration(); + } + + private static final String trimTrailingSlashIfPresent(String path) { + File file = new File(path); + return file.getPath(); + } + + public void reloadConfiguration() { + File txt_exp = new File(mRootDirPath, TEST_EXPECTATIONS_TXT_PATH); + + BufferedReader bufferedReader; + try { + bufferedReader = + new BufferedReader(new FileReader(txt_exp)); + + String line; + String entry; + String[] parts; + String path; + Set<String> tokens; + Boolean skipped; + while (true) { + line = bufferedReader.readLine(); + if (line == null) { + break; + } + + /** Remove the comment and trim */ + entry = line.split("//", 2)[0].trim(); + + /** Omit empty lines, advance to next line */ + if (entry.isEmpty()) { + continue; + } + + /** Split on whitespace into path part and the rest */ + parts = entry.split("\\s", 2); + + /** At this point parts.length >= 1 */ + if (parts.length == 1) { + Log.w(LOG_TAG + "::reloadConfiguration", + "There are no options specified for the test!"); + continue; + } + + path = trimTrailingSlashIfPresent(parts[0]); + + /** Split on whitespace */ + tokens = new HashSet<String>(Arrays.asList(parts[1].split("\\s", 0))); + + /** Chose the right collections to add to */ + skipped = false; + if (tokens.contains(TOKEN_SKIP)) { + mSkipList.add(path); + skipped = true; + } + + /** If test is on skip list we ignore any further options */ + if (skipped) { + continue; + } + + if (tokens.contains(TOKEN_IGNORE_RESULT)) { + mIgnoreResultList.add(path); + } + + if (tokens.contains(TOKEN_SLOW)) { + mSlowList.add(path); + } + } + } catch (FileNotFoundException e) { + Log.w(LOG_TAG + "::reloadConfiguration", "File not found: " + txt_exp.getPath()); + } catch (IOException e) { + Log.e(LOG_TAG + "::reloadConfiguration", "IOException: " + e.getMessage()); + } + } + + /** + * Checks if test is supposed to be skipped. + * + * <p> + * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html + * + * @param testPath + * - a relative path within LayoutTests folder + * @return if the test is supposed to be skipped + */ + public boolean isSkip(String testPath) { + for (String prefix : getPrefixes(testPath)) { + if (mSkipList.contains(prefix)) { + return true; + } + } + + return false; + } + + /** + * Checks if test result is supposed to be ignored. + * + * <p> + * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html + * + * @param testPath + * - a relative path within LayoutTests folder + * @return if the test result is supposed to be ignored + */ + public boolean isIgnoreRes(String testPath) { + for (String prefix : getPrefixes(testPath)) { + if (mIgnoreResultList.contains(prefix)) { + return true; + } + } + + return false; + } + + /** + * Checks if test is slow and should have timeout increased. + * + * <p> + * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html + * + * @param testPath + * - a relative path within LayoutTests folder + * @return if the test is slow and should have timeout increased. + */ + public boolean isSlow(String testPath) { + for (String prefix : getPrefixes(testPath)) { + if (mSlowList.contains(prefix)) { + return true; + } + } + + return false; + } + + /** + * Returns the list of all path prefixes of the given path. + * + * <p> + * e.g. this/is/a/path returns the list: this this/is this/is/a this/is/a/path + * + * @param path + * @return the list of all path prefixes of the given path. + */ + private static List<String> getPrefixes(String path) { + File file = new File(path); + List<String> prefixes = new ArrayList<String>(8); + + do { + prefixes.add(file.getPath()); + file = file.getParentFile(); + } while (file != null); + + return prefixes; + } + + /** + * Checks if the directory may contain tests or contains just helper files. + * + * @param dirName + * @return + * if the directory may contain tests + */ + public static boolean isTestDir(String dirName) { + return (!dirName.equals("script-tests") + && !dirName.equals("resources") && !dirName.startsWith(".")); + } + + /** + * Checks if the file is a test. + * Currently we run .html and .xhtml tests. + * + * @param testName + * @return + * if the file is a test + */ + public static boolean isTestFile(String testName) { + return testName.endsWith(".html") || testName.endsWith(".xhtml"); + } + + /** + * Return the path to the file relative to the tests root dir + * + * @param filePath + * @return + * the path relative to the tests root dir + */ + public String getRelativePath(String filePath) { + File rootDir = new File(mRootDirPath); + return filePath.replaceFirst(rootDir.getPath() + File.separator, ""); + } + + /** + * Return the path to the file relative to the tests root dir + * + * @param filePath + * @return + * the path relative to the tests root dir + */ + public String getRelativePath(File file) { + return getRelativePath(file.getAbsolutePath()); + } + + public File getAbsoluteFile(String relativePath) { + return new File(mRootDirPath, relativePath); + } + + public String getAboslutePath(String relativePath) { + return getAbsoluteFile(relativePath).getAbsolutePath(); + } + + /** + * If the path contains extension (e.g .foo at the end of the file) then it changes + * this (.foo) into newEnding (so it has to contain the dot if we want to preserve it). + * + * <p>If the path doesn't contain an extension, it adds the ending to the path. + * + * @param relativePath + * @param newEnding + * @return + * a new path, containing the newExtension + */ + public static String setPathEnding(String relativePath, String newEnding) { + int dotPos = relativePath.lastIndexOf('.'); + if (dotPos == -1) { + return relativePath + newEnding; + } + + return relativePath.substring(0, dotPos) + newEnding; + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java new file mode 100644 index 0000000..212c187 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + */ +public class FsUtils { + public static final String LOG_TAG = "FsUtils"; + + public static void writeDataToStorage(File file, byte[] bytes, boolean append) { + Log.d(LOG_TAG + "::writeDataToStorage", file.getAbsolutePath()); + try { + OutputStream outputStream = null; + try { + file.getParentFile().mkdirs(); + file.createNewFile(); + Log.d(LOG_TAG + "::writeDataToStorage", "File created."); + outputStream = new FileOutputStream(file, append); + outputStream.write(bytes); + } finally { + if (outputStream != null) { + outputStream.close(); + } + } + } catch (IOException e) { + Log.e(LOG_TAG + "::writeDataToStorage", e.getMessage()); + } + } + + public static byte[] readDataFromStorage(File file) { + if (!file.exists()) { + Log.d(LOG_TAG + "::readDataFromStorage", "File does not exist: " + + file.getAbsolutePath()); + return null; + } + + byte[] bytes = null; + try { + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + bytes = new byte[(int) file.length()]; + fis.read(bytes); + } finally { + if (fis != null) { + fis.close(); + } + } + } catch (IOException e) { + Log.e(LOG_TAG + "::readDataFromStorage", e.getMessage()); + } + + return bytes; + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java new file mode 100644 index 0000000..1312ef9 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.app.Activity; +import android.net.Uri; +import android.os.Handler; +import android.os.Message; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.webkit.WebStorage.QuotaUpdater; + +import java.io.File; + +/** + * A class that represents a single layout test. It is responsible for running the test, + * checking its result and creating an AbstractResult object. + */ +public class LayoutTest { + + private static final String LOG_TAG = "LayoutTest"; + + public static final int MSG_ACTUAL_RESULT_OBTAINED = 0; + + private String mRelativePath; + private String mTestsRootDirPath; + private String mUrl; + private boolean mOnTestFinishedCalled; + private Message mTestFinishedMsg; + private AbstractResult mResult; + + private WebView mWebView; + private Activity mActivity; + + private final Handler mResultHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { + mResult.setExpectedTextResult(LayoutTestsRunnerThread + .getExpectedTextResult(mRelativePath)); + mResult.setExpectedImageResult(LayoutTestsRunnerThread + .getExpectedImageResult(mRelativePath)); + mTestFinishedMsg.sendToTarget(); + } + } + }; + + private WebViewClient mWebViewClient = new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + /** Some tests fire up many page loads, we don't want to detect them */ + if (!url.equals(mUrl)) { + return; + } + + onTestFinished(); + } + }; + + private WebChromeClient mWebChromeClient = new WebChromeClient() { + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, + long currentQuota, long estimatedSize, long totalUsedQuota, + QuotaUpdater quotaUpdater) { + /** TODO: This should be recorded as part of the text result */ + quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024); + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, JsResult result) { + /** TODO: Alerts should be recorded as part of text result */ + result.confirm(); + return true; + } + + @Override + public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { + /** TODO: Alerts should be recorded as part of text result */ + result.confirm(); + return true; + } + + @Override + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, + JsPromptResult result) { + /** TODO: Alerts should be recorded as part of text result */ + result.confirm(); + return true; + } + + }; + + public LayoutTest(String relativePath, String testsRootDirPath, Message testFinishedMsg, + LayoutTestsRunner activity) { + mRelativePath = relativePath; + mTestsRootDirPath = testsRootDirPath; + mTestFinishedMsg = testFinishedMsg; + mActivity = activity; + } + + public LayoutTest(AbstractResult result, String relativePath) { + mResult = result; + mRelativePath = relativePath; + } + + public void run() { + mWebView = new WebView(mActivity); + mActivity.setContentView(mWebView); + + setupWebView(); + + /** TODO: Add timeout msg */ + mUrl = Uri.fromFile(new File(mTestsRootDirPath, mRelativePath)).toString(); + mWebView.loadUrl(mUrl); + } + + private void onTestFinished() { + if (mOnTestFinishedCalled) { + return; + } + + mOnTestFinishedCalled = true; + + /** + * If the result has not been set by the time the test finishes we create + * a default type of result. + */ + if (mResult == null) { + /** TODO: Default type should be RenderTreeResult. We don't support it now. */ + mResult = new TextResult(mRelativePath); + } + + /** TODO: Implement waitUntilDone */ + + mResult.obtainActualResults(mWebView, + mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); + } + + private void setupWebView() { + WebSettings webViewSettings = mWebView.getSettings(); + webViewSettings.setAppCacheEnabled(true); + webViewSettings.setAppCachePath(mActivity.getApplicationContext().getCacheDir().getPath()); + webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); + webViewSettings.setJavaScriptEnabled(true); + webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); + webViewSettings.setSupportMultipleWindows(true); + webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); + webViewSettings.setDatabaseEnabled(true); + webViewSettings.setDatabasePath(mActivity.getDir("databases", 0).getAbsolutePath()); + webViewSettings.setDomStorageEnabled(true); + webViewSettings.setWorkersEnabled(false); + webViewSettings.setXSSAuditorEnabled(false); + + mWebView.setWebViewClient(mWebViewClient); + mWebView.setWebChromeClient(mWebChromeClient); + } + + public AbstractResult getResult() { + return mResult; + } + + public String getRelativePath() { + return mRelativePath; + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java new file mode 100644 index 0000000..6fd3085 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.util.Log; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.webkit.WebStorage.QuotaUpdater; + +import java.io.File; +import java.util.List; + +/** + * This activity executes the test. It contains WebView and logic of LayoutTestController + * functions. It runs in a separate process and sends the results of running the test + * to ManagerService. The reason why is to handle crashing (test that crashes brings down + * whole process with it). + */ +public class LayoutTestsExecuter extends Activity { + + /** TODO: make it a setting */ + static final String TESTS_ROOT_DIR_PATH = + Environment.getExternalStorageDirectory() + + File.separator + "android" + + File.separator + "LayoutTests"; + + private static final String LOG_TAG = "LayoutTestExecuter"; + + public static final String EXTRA_TESTS_LIST = "TestsList"; + + private static final int MSG_ACTUAL_RESULT_OBTAINED = 0; + + private List<String> mTestsList; + private int mCurrentTestCount = 0; + + private WebView mCurrentWebView; + private String mCurrentTestRelativePath; + private String mCurrentTestUri; + + private boolean mOnTestFinishedCalled; + private AbstractResult mCurrentResult; + + /** COMMUNICATION WITH ManagerService */ + + private Messenger mManagerServiceMessenger; + + private ServiceConnection mServiceConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mManagerServiceMessenger = new Messenger(service); + runNextTest(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + /** TODO */ + } + }; + + private final Handler mResultHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { + reportResultToService(); + runNextTest(); + } + } + }; + + /** WEBVIEW CONFIGURATION */ + + private WebViewClient mWebViewClient = new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { + /** Some tests fire up many page loads, we don't want to detect them */ + if (!url.equals(mCurrentTestUri)) { + return; + } + + /** TODO: Implement waitUntilDone */ + onTestFinished(); + } + }; + + private WebChromeClient mWebChromeClient = new WebChromeClient() { + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, + long currentQuota, long estimatedSize, long totalUsedQuota, + QuotaUpdater quotaUpdater) { + /** TODO: This should be recorded as part of the text result */ + quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024); + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, JsResult result) { + /** TODO: Alerts should be recorded as part of text result */ + result.confirm(); + return true; + } + + @Override + public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { + /** TODO: Alerts should be recorded as part of text result */ + result.confirm(); + return true; + } + + @Override + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, + JsPromptResult result) { + /** TODO: Alerts should be recorded as part of text result */ + result.confirm(); + return true; + } + + }; + + /** IMPLEMENTATION */ + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST); + + bindService(new Intent(this, ManagerService.class), mServiceConnection, + Context.BIND_AUTO_CREATE); + } + + private void reset() { + mOnTestFinishedCalled = false; + mCurrentResult = null; + + mCurrentWebView = new WebView(this); + mCurrentWebView.setWebViewClient(mWebViewClient); + mCurrentWebView.setWebChromeClient(mWebChromeClient); + + WebSettings webViewSettings = mCurrentWebView.getSettings(); + webViewSettings.setAppCacheEnabled(true); + webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); + webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); + webViewSettings.setJavaScriptEnabled(true); + webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); + webViewSettings.setSupportMultipleWindows(true); + webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); + webViewSettings.setDatabaseEnabled(true); + webViewSettings.setDatabasePath(getDir("databases", 0).getAbsolutePath()); + webViewSettings.setDomStorageEnabled(true); + webViewSettings.setWorkersEnabled(false); + webViewSettings.setXSSAuditorEnabled(false); + + setContentView(mCurrentWebView); + } + + private void runNextTest() { + if (mTestsList.isEmpty()) { + onAllTestsFinished(); + return; + } + + mCurrentTestCount++; + mCurrentTestRelativePath = mTestsList.remove(0); + mCurrentTestUri = + Uri.fromFile(new File(TESTS_ROOT_DIR_PATH, mCurrentTestRelativePath)).toString(); + + reset(); + /** TODO: Implement timeout */ + mCurrentWebView.loadUrl(mCurrentTestUri); + } + + private void onTestFinished() { + if (mOnTestFinishedCalled) { + return; + } + + mOnTestFinishedCalled = true; + + /** + * If the result has not been set by the time the test finishes we create + * a default type of result. + */ + if (mCurrentResult == null) { + /** TODO: Default type should be RenderTreeResult. We don't support it now. */ + mCurrentResult = new TextResult(mCurrentTestRelativePath); + } + + mCurrentResult.obtainActualResults(mCurrentWebView, + mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); + } + + private void reportResultToService() { + try { + Message serviceMsg = + Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS); + Bundle bundle = mCurrentResult.getBundle(); + /** TODO: Add timeout info to bundle */ + serviceMsg.setData(bundle); + mManagerServiceMessenger.send(serviceMsg); + } catch (RemoteException e) { + Log.e(LOG_TAG + "::reportResultToService", e.getMessage()); + } + } + + private void onAllTestsFinished() { + Log.d(LOG_TAG + "::onAllTestsFisnihed", "Begin."); + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java new file mode 100644 index 0000000..4421aba --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunner.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.Window; + +/** + * An Activity that is responsible only for updating the UI features, like titles, progress bars, + * etc. + * + * <p>Also, the webview form the test must be running in this activity's thread if we want + * to be able to display it on the screen. + */ +public class LayoutTestsRunner extends Activity { + + public static final int MSG_UPDATE_PROGRESS = 1; + public static final int MSG_SHOW_PROGRESS_DIALOG = 2; + public static final int MSG_DISMISS_PROGRESS_DIALOG = 3; + + /** Constants for adding extras to an intent */ + public static final String EXTRA_TEST_PATH = "TestPath"; + + private static ProgressDialog sProgressDialog; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_PROGRESS: + int i = msg.arg1; + int size = msg.arg2; + getWindow().setFeatureInt(Window.FEATURE_PROGRESS, + i * Window.PROGRESS_END / size); + setTitle(i * 100 / size + "% (" + i + "/" + size + ")"); + break; + + case MSG_SHOW_PROGRESS_DIALOG: + sProgressDialog.show(); + break; + + case MSG_DISMISS_PROGRESS_DIALOG: + sProgressDialog.dismiss(); + break; + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + /** Prepare the progress dialog */ + sProgressDialog = new ProgressDialog(LayoutTestsRunner.this); + sProgressDialog.setCancelable(false); + sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); + sProgressDialog.setTitle(R.string.dialog_progress_title); + sProgressDialog.setMessage(getText(R.string.dialog_progress_msg)); + + requestWindowFeature(Window.FEATURE_PROGRESS); + + /** Execute the intent */ + Intent intent = getIntent(); + if (!intent.getAction().equals(Intent.ACTION_RUN)) { + return; + } + String path = intent.getStringExtra(EXTRA_TEST_PATH); + + new LayoutTestsRunnerThread(path, this).start(); + } + + public Handler getHandler() { + return mHandler; + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java new file mode 100644 index 0000000..ac814cb --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.content.Intent; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * A Thread that is responsible for finding and loading the tests, starting them and + * generating summaries. The actual running of the test is delegated to LayoutTestsRunner + * activity (a UI thread) because of a WebView object that need to be created in UI thread + * so it can be displayed on the screen. However, the logic for doing this remains in + * this class (in handler created in constructor). + */ +public class LayoutTestsRunnerThread extends Thread { + + private static final String LOG_TAG = "LayoutTestsRunnerThread"; + + /** Messages for handler on this thread */ + public static final int MSG_TEST_FINISHED = 0; + + /** Messages for our handler running on UI thread */ + public static final int MSG_RUN_TEST = 0; + + /** TODO: make it a setting */ + private static final String TESTS_ROOT_DIR_PATH = + Environment.getExternalStorageDirectory() + + File.separator + "android" + + File.separator + "LayoutTests"; + + /** TODO: make it a setting */ + private static final String RESULTS_ROOT_DIR_PATH = + Environment.getExternalStorageDirectory() + + File.separator + "android" + + File.separator + "LayoutTests-results"; + + /** TODO: Make it a setting */ + private static final String EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX = + "platform" + File.separator + + "android-v8" + File.separator; + + /** TODO: Make these settings */ + private static final String TEXT_RESULT_EXTENSION = "txt"; + private static final String IMAGE_RESULT_EXTENSION = "png"; + + /** A list containing relative paths of tests to run */ + private LinkedList<String> mTestsList = new LinkedList<String>(); + + private FileFilter mFileFilter; + private Summarizer mSummarizer; + + /** Our handler running on this thread. Created in run() method. */ + private Handler mHandler; + + /** Our handler running on UI thread. Created in constructor of this thread. */ + private Handler mHandlerOnUiThread; + + /** + * A relative path to the folder with the tests we want to run or particular test. + * Used up to and including preloadTests(). + */ + private String mRelativePath; + + private LayoutTestsRunner mActivity; + + private LayoutTest mCurrentTest; + private String mCurrentTestPath; + private int mCurrentTestCount = 0; + private int mTotalTestCount; + + /** + * The given path must be relative to the root dir. The given handler must be + * able to handle messages that update the display (UI thread). + * + * @param path + * @param uiDisplayHandler + */ + public LayoutTestsRunnerThread(String path, LayoutTestsRunner activity) { + mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH); + mRelativePath = path; + mActivity = activity; + + /** This creates a handler that runs on the thread that _created_ this thread */ + mHandlerOnUiThread = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_RUN_TEST: + ((LayoutTest) msg.obj).run(); + break; + } + } + }; + } + + @Override + public void run() { + Looper.prepare(); + + mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH); + + /** A handler obtained from UI thread to handle messages concerning updating the display */ + final Handler uiDisplayHandler = mActivity.getHandler(); + + /** Creates a new handler in _this_ thread */ + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_TEST_FINISHED: + onTestFinished(mCurrentTest); + uiDisplayHandler.obtainMessage(LayoutTestsRunner.MSG_UPDATE_PROGRESS, + mCurrentTestCount, mTotalTestCount).sendToTarget(); + runNextTest(); + break; + } + } + }; + + /** Check if the path is correct */ + File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath); + if (!file.exists()) { + Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath); + return; + } + + /** Populate the tests' list accordingly */ + if (file.isDirectory()) { + uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_SHOW_PROGRESS_DIALOG); + preloadTests(mRelativePath); + uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_DISMISS_PROGRESS_DIALOG); + } else { + mTestsList.addLast(mRelativePath); + mTotalTestCount = 1; + } + + /** + * Instead of running next test here, we send a tests' list to Executer activity. + * Rest of the code is never executed and will be gradually moved to the service. + */ + Intent intent = new Intent(); + intent.setClass(mActivity, LayoutTestsExecuter.class); + intent.setAction(Intent.ACTION_RUN); + intent.putStringArrayListExtra(LayoutTestsExecuter.EXTRA_TESTS_LIST, + new ArrayList<String>(mTestsList)); + mActivity.startActivity(intent); + + Looper.loop(); + } + + /** + * Loads all the tests from the given folders and all the subfolders + * into mTestsList. + * + * @param dirRelativePath + */ + private void preloadTests(String dirRelativePath) { + LinkedList<String> foldersList = new LinkedList<String>(); + foldersList.add(dirRelativePath); + + String relativePath; + String currentDirRelativePath; + String itemName; + File[] items; + while (!foldersList.isEmpty()) { + currentDirRelativePath = foldersList.removeFirst(); + items = new File(TESTS_ROOT_DIR_PATH, currentDirRelativePath).listFiles(); + for (File item : items) { + itemName = item.getName(); + relativePath = currentDirRelativePath + File.separator + itemName; + + if (item.isDirectory() && FileFilter.isTestDir(itemName)) { + foldersList.add(relativePath); + continue; + } + + if (FileFilter.isTestFile(itemName)) { + if (!mFileFilter.isSkip(relativePath)) { + mTestsList.addLast(relativePath); + } else { + mSummarizer.addSkippedTest(relativePath); + } + } + } + } + + mTotalTestCount = mTestsList.size(); + } + + private void runNextTest() { + if (mTestsList.isEmpty()) { + onFinishedTests(); + return; + } + + mCurrentTestCount++; + mCurrentTestPath = mTestsList.removeFirst(); + mCurrentTest = new LayoutTest(mCurrentTestPath, TESTS_ROOT_DIR_PATH, + mHandler.obtainMessage(MSG_TEST_FINISHED), mActivity); + + /** + * This will run the test on UI thread. The reason why we need to run the test + * on UI thread is because of the WebView. If we want to display the webview on + * the screen it needs to be in the UI thread. WebView should be created as + * part of the LayoutTest.run() method. + */ + mHandlerOnUiThread.obtainMessage(MSG_RUN_TEST, mCurrentTest).sendToTarget(); + } + + private void onTestFinished(LayoutTest test) { + String testPath = test.getRelativePath(); + + /** Obtain the result */ + AbstractResult result = test.getResult(); + if (result == null) { + Log.e(LOG_TAG + "::runTests", testPath + ": result NULL!!"); + return; + } + + dumpResultData(result, testPath); + + mSummarizer.appendTest(test); + } + + private void dumpResultData(AbstractResult result, String testPath) { + dumpActualTextResult(result, testPath); + dumpActualImageResult(result, testPath); + } + + private void dumpActualTextResult(AbstractResult result, String testPath) { + String actualTextResult = result.getActualTextResult(); + if (actualTextResult == null) { + return; + } + + String resultPath = FileFilter.setPathEnding(testPath, "-actual." + TEXT_RESULT_EXTENSION); + FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), + actualTextResult.getBytes(), false); + } + + private void dumpActualImageResult(AbstractResult result, String testPath) { + byte[] actualImageResult = result.getActualImageResult(); + if (actualImageResult == null) { + return; + } + + String resultPath = FileFilter.setPathEnding(testPath, "-actual." + IMAGE_RESULT_EXTENSION); + FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), + actualImageResult, false); + } + + private void onFinishedTests() { + Log.d(LOG_TAG + "::onFinishedTests", "Begin."); + Looper.myLooper().quit(); + mSummarizer.summarize(); + /** TODO: Present some kind of notification to the user that + * allows to chose next action, e.g: + * - go to html view of results + * - zip results + * - run more tests before zipping */ + } + + public static String getExpectedTextResult(String relativePath) { + return new String(getExpectedResult(relativePath, TEXT_RESULT_EXTENSION)); + } + + public static byte[] getExpectedImageResult(String relativePath) { + return getExpectedResult(relativePath, IMAGE_RESULT_EXTENSION); + } + + private static byte[] getExpectedResult(String relativePath, String extension) { + relativePath = FileFilter.setPathEnding(relativePath, "-expected." + extension); + + byte[] bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath)); + if (bytes == null) { + relativePath = EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX + relativePath; + bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath)); + } + + return bytes; + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java new file mode 100644 index 0000000..e452a38 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ManagerService.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.util.Log; + +/** + * A service that handles managing the results of tests, informing of crashes, generating + * summaries, etc. + */ +public class ManagerService extends Service { + + private static final String LOG_TAG = "ManagerService"; + + static final int MSG_PROCESS_ACTUAL_RESULTS = 0; + + private Handler mIncomingHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_PROCESS_ACTUAL_RESULTS: + Log.d(LOG_TAG + ".mIncomingHandler", msg.getData().getString("relativePath")); + break; + } + } + }; + + private Messenger mMessenger = new Messenger(mIncomingHandler); + + @Override + public void onCreate() { + super.onCreate(); + /** TODO: */ + } + + @Override + public IBinder onBind(Intent intent) { + return mMessenger.getBinder(); + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java new file mode 100644 index 0000000..4d15bb5 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/Summarizer.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.util.Log; + +import java.io.File; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +/** + * A class that collects information about tests that ran and can create HTML + * files with summaries and easy navigation. + */ +public class Summarizer { + + private static final String LOG_TAG = "Summarizer"; + + private static final String CSS = + "* {" + + " font-family: Verdana;" + + " border: 0;" + + " margin: 0;" + + " padding: 0;}" + + "body {" + + " margin: 10px;}" + + "a {" + + " font-size: 12px;" + + " color: black;}" + + "h1 {" + + " font-size: 33px;" + + " margin: 4px 0 4px 0;}" + + "h2 {" + + " font-size:22px;" + + " margin: 20px 0 3px 0;}" + + "h3 {" + + " font-size: 20px;" + + " margin-bottom: 6px;}" + + "table.visual_diff {" + + " border-bottom: 0px solid;" + + " border-collapse: collapse;" + + " width: 100%;" + + " margin-bottom: 3px;}" + + "table.visual_diff tr.headers td {" + + " border-bottom: 1px solid;" + + " border-top: 0;" + + " padding-bottom: 3px;}" + + "table.visual_diff tr.results td {" + + " border-top: 1px dashed;" + + " border-right: 1px solid;" + + " font-size: 15px;" + + " vertical-align: top;}" + + "table.visual_diff tr.results td.line_count {" + + " background-color:#aaa;" + + " min-width:20px;" + + " text-align: right;" + + " border-right: 1px solid;" + + " border-left: 1px solid;" + + " padding: 2px 1px 2px 0px;}" + + "table.visual_diff tr.results td.line {" + + " padding: 2px 0px 2px 4px;" + + " border-right: 1px solid;" + + " width: 49.8%;}" + + "table.visual_diff tr.footers td {" + + " border-top: 1px solid;" + + " border-bottom: 0;}" + + "table.visual_diff tr td.space {" + + " border: 0;" + + " width: 0.4%}" + + "div.space {" + + " margin-top:30px;}" + + "span.eql {" + + " background-color: #f3f3f3;}" + + "span.del {" + + " background-color: #ff8888; }" + + "span.ins {" + + " background-color: #88ff88; }" + + "span.fail {" + + " color: red;}" + + "span.pass {" + + " color: green;}" + + "span.time_out {" + + " color: orange;}"; + private static final String HTML_DIFF_BEGINNING = "<html><head><style type=\"text/css\">" + + CSS + "</style></head><body>"; + private static final String HTML_DIFF_ENDING = "</body></html>"; + + /** TODO: Make it a setting */ + private static final String HTML_DIFF_RELATIVE_PATH = "_diff.html"; + private static final String HTML_DIFF_INDEX_RELATIVE_PATH = "_diff-index.html"; + + /** A list containing relatives paths of tests that were skipped */ + private LinkedList<String> mSkippedTestsList = new LinkedList<String>(); + + /** Collection of tests grouped according to result. Sets are initialized lazily. */ + private Map<AbstractResult.ResultCode, Set<String>> mResults = + new EnumMap<AbstractResult.ResultCode, Set<String>>(AbstractResult.ResultCode.class); + + /** + * Collection of tests for which results are ignored grouped according to result. Sets are + * initialized lazily. + */ + private Map<AbstractResult.ResultCode, Set<String>> mResultsIgnored = + new EnumMap<AbstractResult.ResultCode, Set<String>>(AbstractResult.ResultCode.class); + + private FileFilter mFileFilter; + private String mResultsRootDirPath; + + public Summarizer(FileFilter fileFilter, String resultsRootDirPath) { + mFileFilter = fileFilter; + mResultsRootDirPath = resultsRootDirPath; + createHtmlDiff(); + } + + private void createHtmlDiff() { + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_RELATIVE_PATH), + HTML_DIFF_BEGINNING.getBytes(), false); + } + + private void appendHtmlDiff(String relativePath, String diff) { + StringBuilder html = new StringBuilder(); + html.append("<label id=\"" + relativePath + "\" />"); + html.append(diff); + html.append("<a href=\"" + HTML_DIFF_INDEX_RELATIVE_PATH + "\">Back to index</a>"); + html.append("<div class=\"space\"></div>"); + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_RELATIVE_PATH), + html.toString().getBytes(), true); + } + + private void finalizeHtmlDiff() { + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_RELATIVE_PATH), + HTML_DIFF_ENDING.getBytes(), true); + } + + /** TODO: Add settings method, like setIndexSkippedTests(), setIndexTimedOutTests(), etc */ + + public void addSkippedTest(String relativePath) { + mSkippedTestsList.addLast(relativePath); + } + + public void appendTest(LayoutTest test) { + String testPath = test.getRelativePath(); + + /** Obtain the result */ + AbstractResult result = test.getResult(); + if (result == null) { + Log.e(LOG_TAG + "::appendTest", testPath + ": result NULL!!"); + return; + } + + AbstractResult.ResultCode resultCode = result.getResultCode(); + + /** Add the test to correct collection according to its result code */ + if (mFileFilter.isIgnoreRes(testPath)) { + /** Lazy initialization */ + if (mResultsIgnored.get(resultCode) == null) { + mResultsIgnored.put(resultCode, new HashSet<String>()); + } + + mResultsIgnored.get(resultCode).add(testPath); + } else { + /** Lazy initialization */ + if (mResults.get(resultCode) == null) { + mResults.put(resultCode, new HashSet<String>()); + } + + mResults.get(resultCode).add(testPath); + } + + if (resultCode != AbstractResult.ResultCode.PASS) { + appendHtmlDiff(testPath, result.getDiffAsHtml()); + } + } + + public void summarize() { + finalizeHtmlDiff(); + createHtmlDiffIndex(); + } + + private void createHtmlDiffIndex() { + StringBuilder html = new StringBuilder(); + html.append(HTML_DIFF_BEGINNING); + Set<String> results; + html.append("<h1>NOT ignored</h1>"); + appendResultsMap(mResults, html); + html.append("<h1>Ignored</h1>"); + appendResultsMap(mResultsIgnored, html); + html.append(HTML_DIFF_ENDING); + FsUtils.writeDataToStorage(new File(mResultsRootDirPath, HTML_DIFF_INDEX_RELATIVE_PATH), + html.toString().getBytes(), false); + } + + private void appendResultsMap(Map<AbstractResult.ResultCode, Set<String>> resultsMap, + StringBuilder html) { + Set<String> results; + for (AbstractResult.ResultCode resultCode : AbstractResult.ResultCode.values()) { + results = resultsMap.get(resultCode); + if (results != null) { + html.append("<h2>"); + html.append(resultCode.toString()); + html.append("</h2"); + for (String relativePath : results) { + html.append("<a href=\""); + html.append(HTML_DIFF_RELATIVE_PATH); + html.append("#"); + html.append(relativePath); + html.append("\">"); + html.append(relativePath); + html.append("</a><br />"); + } + } + } + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java new file mode 100644 index 0000000..7bab4ae --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TextResult.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2010 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.dumprendertree2; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.webkit.WebView; + +/** + * A result object for which the expected output is text. It does not have an image + * expected result. + * + * <p>Created if layoutTestController.dumpAsText() was called. + */ +public class TextResult extends AbstractResult { + + private static final int MSG_DOCUMENT_AS_TEXT = 0; + + private String mExpectedResult; + private String mActualResult; + private String mRelativePath; + private ResultCode mResultCode; + private Message mResultObtainedMsg; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_DOCUMENT_AS_TEXT) { + mActualResult = (String) msg.obj; + mResultObtainedMsg.sendToTarget(); + } + } + }; + + public TextResult(String relativePath) { + mRelativePath = relativePath; + } + + /** + * Used to recreate the Result when received by the service. + * + * @param bundle + * bundle with data used to recreate the result + */ + public TextResult(Bundle bundle) { + mExpectedResult = bundle.getString("expectedTextualResult"); + mActualResult = bundle.getString("actualTextualResult"); + mRelativePath = bundle.getString("relativePath"); + mResultCode = ResultCode.valueOf(bundle.getString("resultCode")); + } + + @Override + public ResultCode getResultCode() { + if (mResultCode != null) { + return mResultCode; + } + + if (mExpectedResult == null) { + mResultCode = AbstractResult.ResultCode.FAIL_NO_EXPECTED_RESULT; + } else if (!mExpectedResult.equals(mActualResult)) { + mResultCode = AbstractResult.ResultCode.FAIL_RESULT_DIFFERS; + } else { + mResultCode = AbstractResult.ResultCode.PASS; + } + + return mResultCode; + } + + @Override + public byte[] getActualImageResult() { + return null; + } + + @Override + public String getActualTextResult() { + return mActualResult; + } + + @Override + public void setExpectedImageResult(byte[] expectedResult) { + /** This method is not applicable to this type of result */ + } + + @Override + public void setExpectedTextResult(String expectedResult) { + mExpectedResult = expectedResult; + } + + @Override + public String getDiffAsHtml() { + /** TODO: just a stub + * Probably needs rethinking anyway - just one table would be much better + * This will require some changes in Summarizer in CSS as well */ + StringBuilder html = new StringBuilder(); + html.append("<h3>"); + html.append(mRelativePath); + html.append("</h3>"); + html.append("<table class=\"visual_diff\">"); + + html.append("<tr class=\"headers\">"); + html.append("<td colspan=\"2\">Expected result:</td>"); + html.append("<td class=\"space\"></td>"); + html.append("<td colspan=\"2\">Actual result:</td>"); + html.append("</tr>"); + + html.append("<tr class=\"results\">"); + html.append("<td class=\"line_count\">1:</td>"); + html.append("<td class=\"line\">"); + if (mExpectedResult == null) { + html.append("NULL"); + } else { + html.append(mExpectedResult.replace("\n", "<br />")); + } + html.append("</td>"); + html.append("<td class=\"space\"></td>"); + html.append("<td class=\"line_count\">1:</td>"); + html.append("<td class=\"line\">"); + if (mActualResult == null) { + html.append("NULL"); + } else { + html.append(mActualResult.replace("\n", "<br />")); + } + html.append("</td>"); + html.append("</tr>"); + + html.append("<tr class=\"footers\">"); + html.append("<td colspan=\"2\"></td>"); + html.append("<td class=\"space\"></td>"); + html.append("<td colspan=\"2\"></td>"); + html.append("</tr>"); + + html.append("</table>"); + + return html.toString(); + } + + @Override + public TestType getType() { + return TestType.TEXT; + } + + @Override + public void obtainActualResults(WebView webview, Message resultObtainedMsg) { + mResultObtainedMsg = resultObtainedMsg; + Message msg = mHandler.obtainMessage(MSG_DOCUMENT_AS_TEXT); + + /** TODO: mDumpTopFrameAsText and mDumpChildFramesAsText */ + msg.arg1 = 1; + msg.arg2 = 0; + webview.documentAsText(msg); + } + + @Override + public Bundle getBundle() { + Bundle bundle = new Bundle(); + bundle.putString("expectedTextualResult", mExpectedResult); + bundle.putString("actualTextualResult", mActualResult); + bundle.putString("relativePath", mRelativePath); + if (mResultCode != null) { + bundle.putString("resultCode", mResultCode.name()); + } + bundle.putString("type", getType().name()); + return bundle; + } +}
\ No newline at end of file diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java new file mode 100644 index 0000000..790d1d3 --- /dev/null +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/ui/DirListActivity.java @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2010 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.dumprendertree2.ui; + +import com.android.dumprendertree2.FileFilter; +import com.android.dumprendertree2.LayoutTestsRunner; +import com.android.dumprendertree2.R; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * An Activity that allows navigating through tests folders and choosing folders or tests to run. + */ +public class DirListActivity extends ListActivity { + + private static final String LOG_TAG = "DirListActivity"; + private static final String ROOT_DIR_PATH = + Environment.getExternalStorageDirectory() + + File.separator + "android" + + File.separator + "LayoutTests"; + + /** TODO: This is just a guess - think of a better way to achieve it */ + private static final int MEAN_TITLE_CHAR_SIZE = 13; + + private static final int PROGRESS_DIALOG_DELAY_MS = 200; + + /** Code for the dialog, used in showDialog and onCreateDialog */ + private static final int DIALOG_RUN_ABORT_DIR = 0; + + /** Messages codes */ + private static final int MSG_LOADED_ITEMS = 0; + private static final int MSG_SHOW_PROGRESS_DIALOG = 1; + + /** Initialized lazily before first sProgressDialog.show() */ + private static ProgressDialog sProgressDialog; + + private ListView mListView; + + /** This is a relative path! */ + private String mCurrentDirPath; + + /** + * TODO: This should not be a constant, but rather be configurable from somewhere. + */ + private String mRootDirPath = ROOT_DIR_PATH; + + private FileFilter mFileFilter; + + /** + * A thread responsible for loading the contents of the directory from sd card + * and sending them via Message to main thread that then loads them into + * ListView + */ + private class LoadListItemsThread extends Thread { + private Handler mHandler; + private String mRelativePath; + + public LoadListItemsThread(String relativePath, Handler handler) { + mRelativePath = relativePath; + mHandler = handler; + } + + @Override + public void run() { + Message msg = mHandler.obtainMessage(MSG_LOADED_ITEMS); + msg.obj = getDirList(mRelativePath); + mHandler.sendMessage(msg); + } + } + + /** + * Very simple object to use inside ListView as an item. + */ + private static class ListItem implements Comparable<ListItem> { + private String mRelativePath; + private String mName; + private boolean mIsDirectory; + + public ListItem(String relativePath, boolean isDirectory) { + mRelativePath = relativePath; + mName = new File(relativePath).getName(); + mIsDirectory = isDirectory; + } + + public boolean isDirectory() { + return mIsDirectory; + } + + public String getRelativePath() { + return mRelativePath; + } + + public String getName() { + return mName; + } + + @Override + public int compareTo(ListItem another) { + return mRelativePath.compareTo(another.getRelativePath()); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ListItem)) { + return false; + } + + return mRelativePath.equals(((ListItem) o).getRelativePath()); + } + + @Override + public int hashCode() { + return mRelativePath.hashCode(); + } + + } + + /** + * A custom adapter that sets the proper icon and label in the list view. + */ + private static class DirListAdapter extends ArrayAdapter<ListItem> { + private Activity mContext; + private ListItem[] mItems; + + public DirListAdapter(Activity context, ListItem[] items) { + super(context, R.layout.dirlist_row, items); + + mContext = context; + mItems = items; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + LayoutInflater inflater = mContext.getLayoutInflater(); + View row = inflater.inflate(R.layout.dirlist_row, null); + + TextView label = (TextView) row.findViewById(R.id.label); + label.setText(mItems[position].getName()); + + ImageView icon = (ImageView) row.findViewById(R.id.icon); + if (mItems[position].isDirectory()) { + icon.setImageResource(R.drawable.folder); + } else { + icon.setImageResource(R.drawable.runtest); + } + + return row; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mFileFilter = new FileFilter(ROOT_DIR_PATH); + mListView = getListView(); + + mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + ListItem item = (ListItem) parent.getItemAtPosition(position); + + if (item.isDirectory()) { + showDir(item.getRelativePath()); + } else { + /** Run the test */ + Intent intent = new Intent(); + intent.setClass(DirListActivity.this, LayoutTestsRunner.class); + intent.setAction(Intent.ACTION_RUN); + intent.putExtra(LayoutTestsRunner.EXTRA_TEST_PATH, item.getRelativePath()); + startActivity(intent); + } + } + }); + + mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { + ListItem item = (ListItem) parent.getItemAtPosition(position); + + if (item.isDirectory()) { + Bundle arguments = new Bundle(1); + arguments.putString("name", item.getName()); + arguments.putString("relativePath", item.getRelativePath()); + showDialog(DIALOG_RUN_ABORT_DIR, arguments); + } else { + /** TODO: Maybe show some info about a test? */ + } + + return true; + } + }); + + /** All the paths are relative to test root dir where possible */ + showDir(""); + } + + @Override + /** + * Moves to the parent directory if one exists. Does not allow to move above + * the test 'root' directory. + */ + public void onBackPressed() { + File currentDirParent = new File(mCurrentDirPath).getParentFile(); + if (currentDirParent != null) { + showDir(currentDirParent.getPath()); + } else { + showDir(""); + } + } + + /** + * Prevents the activity from recreating on change of orientation. The title needs to + * be recalculated. + */ + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + setTitle(shortenTitle(mCurrentDirPath)); + } + + @Override + protected Dialog onCreateDialog(int id, final Bundle args) { + Dialog dialog = null; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + switch (id) { + case DIALOG_RUN_ABORT_DIR: + builder.setTitle(getText(R.string.dialog_run_abort_dir_title_prefix) + " " + + args.getString("name")); + builder.setMessage(R.string.dialog_run_abort_dir_msg); + builder.setCancelable(true); + + builder.setPositiveButton(R.string.dialog_run_abort_dir_ok_button, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + removeDialog(DIALOG_RUN_ABORT_DIR); + /** Run the tests */ + Intent intent = new Intent(); + intent.setClass(DirListActivity.this, LayoutTestsRunner.class); + intent.setAction(Intent.ACTION_RUN); + intent.putExtra(LayoutTestsRunner.EXTRA_TEST_PATH, + args.getString("relativePath")); + startActivity(intent); + } + }); + + builder.setNegativeButton(R.string.dialog_run_abort_dir_abort_button, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + removeDialog(DIALOG_RUN_ABORT_DIR); + } + }); + + dialog = builder.create(); + dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + removeDialog(DIALOG_RUN_ABORT_DIR); + } + }); + break; + } + + return dialog; + } + + /** + * Loads the contents of dir into the list view. + * + * @param dirPath + * directory to load into list view + */ + private void showDir(String dirPath) { + mCurrentDirPath = dirPath; + + /** Show progress dialog with a delay */ + final Handler delayedDialogHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_SHOW_PROGRESS_DIALOG) { + if (sProgressDialog == null) { + sProgressDialog = new ProgressDialog(DirListActivity.this); + sProgressDialog.setCancelable(false); + sProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); + sProgressDialog.setTitle(R.string.dialog_progress_title); + sProgressDialog.setMessage(getText(R.string.dialog_progress_msg)); + } + sProgressDialog.show(); + } + } + }; + Message msgShowDialog = delayedDialogHandler.obtainMessage(MSG_SHOW_PROGRESS_DIALOG); + delayedDialogHandler.sendMessageDelayed(msgShowDialog, PROGRESS_DIALOG_DELAY_MS); + + /** Delegate loading contents from SD card to a new thread */ + new LoadListItemsThread(mCurrentDirPath, new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_LOADED_ITEMS) { + setListAdapter(new DirListAdapter(DirListActivity.this, + (ListItem[])msg.obj)); + delayedDialogHandler.removeMessages(MSG_SHOW_PROGRESS_DIALOG); + setTitle(shortenTitle(mCurrentDirPath)); + if (sProgressDialog != null) { + sProgressDialog.dismiss(); + } + } + } + }).start(); + } + + /** + * TODO: find a neat way to determine number of characters that fit in the title + * bar. + * */ + private String shortenTitle(String title) { + if (title.equals("")) { + return "Tests' root dir:"; + } + int charCount = mListView.getWidth() / MEAN_TITLE_CHAR_SIZE; + + if (title.length() > charCount) { + return "..." + title.substring(title.length() - charCount); + } else { + return title; + } + } + + /** + * Return the array with contents of the given directory. + * First it contains the subfolders, then the files. Both sorted + * alphabetically. + * + * The dirPath is relative. + */ + private ListItem[] getDirList(String dirPath) { + File dir = new File(mRootDirPath, dirPath); + + List<ListItem> subDirs = new ArrayList<ListItem>(); + List<ListItem> subFiles = new ArrayList<ListItem>(); + + for (File item : dir.listFiles()) { + if (item.isDirectory() && FileFilter.isTestDir(item.getName())) { + subDirs.add(new ListItem(mFileFilter.getRelativePath(item), true)); + } else if (FileFilter.isTestFile(item.getName())) { + subFiles.add(new ListItem(mFileFilter.getRelativePath(item), false)); + } + } + + Collections.sort(subDirs); + Collections.sort(subFiles); + + /** Concatenate the two lists */ + subDirs.addAll(subFiles); + + return subDirs.toArray(new ListItem[subDirs.size()]); + } +}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/Android.mk b/tests/HwAccelerationTest/Android.mk new file mode 100644 index 0000000..d4743f9 --- /dev/null +++ b/tests/HwAccelerationTest/Android.mk @@ -0,0 +1,26 @@ +# +# Copyright (C) 2010 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := HwAccelerationTest + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml new file mode 100644 index 0000000..80480db --- /dev/null +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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.google.android.test.hwui"> + + <application + android:label="HwUi" + android:hardwareAccelerated="true"> + + <activity + android:name="AlphaLayersActivity" + android:label="_αLayers"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="LayersActivity" + android:label="_Layers" + android:theme="@android:style/Theme.Translucent.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="XfermodeActivity" + android:label="_Xfermodes" + android:theme="@android:style/Theme.Translucent.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="BitmapsActivity" + android:label="_Bitmaps" + android:theme="@android:style/Theme.Translucent.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="BitmapsRectActivity" + android:label="_BitmapsRect" + android:theme="@android:style/Theme.Translucent.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="NinePatchesActivity" + android:label="_9patch"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="QuickRejectActivity" + android:label="_QuickReject"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="RotationActivity" + android:label="_Rotation"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="ShadersActivity" + android:label="_Shaders"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="TextActivity" + android:label="_Text" + android:theme="@android:style/Theme.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity + android:name="ListActivity" + android:label="_List"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> +</manifest> diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/icon.png b/tests/HwAccelerationTest/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..60fbdf5 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable-hdpi/icon.png diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg b/tests/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg Binary files differnew file mode 100644 index 0000000..92851f3 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable-hdpi/sunset1.jpg diff --git a/tests/HwAccelerationTest/res/drawable-hdpi/sunset2.png b/tests/HwAccelerationTest/res/drawable-hdpi/sunset2.png Binary files differnew file mode 100644 index 0000000..3258ee7 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable-hdpi/sunset2.png diff --git a/tests/HwAccelerationTest/res/drawable/icon.png b/tests/HwAccelerationTest/res/drawable/icon.png Binary files differnew file mode 100644 index 0000000..cb40a19 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable/icon.png diff --git a/tests/HwAccelerationTest/res/drawable/sunset1.jpg b/tests/HwAccelerationTest/res/drawable/sunset1.jpg Binary files differnew file mode 100644 index 0000000..92851f3 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable/sunset1.jpg diff --git a/tests/HwAccelerationTest/res/drawable/sunset2.png b/tests/HwAccelerationTest/res/drawable/sunset2.png Binary files differnew file mode 100644 index 0000000..3258ee7 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable/sunset2.png diff --git a/tests/HwAccelerationTest/res/layout/list_activity.xml b/tests/HwAccelerationTest/res/layout/list_activity.xml new file mode 100644 index 0000000..f548f53 --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/list_activity.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ListView + android:id="@+id/list" + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1.0" /> + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <Button + android:layout_width="0dip" + android:layout_weight="1.0" + android:layout_height="wrap_content" + android:layout_marginLeft="10dip" + android:layout_marginRight="3dip" + + android:text="Add" /> + + <Button + android:layout_width="0dip" + android:layout_weight="1.0" + android:layout_height="wrap_content" + android:layout_marginLeft="3dip" + android:layout_marginRight="10dip" + + android:text="Remove" /> + + </LinearLayout> + +</LinearLayout> diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/AlphaLayersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/AlphaLayersActivity.java new file mode 100644 index 0000000..0217a05 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/AlphaLayersActivity.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.FrameLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class AlphaLayersActivity extends Activity { + private static final String LOG_TAG = "HwUi"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + DirtyBitmapView container = new DirtyBitmapView(this); + + ColorView color = new ColorView(this); + container.addView(color, new DirtyBitmapView.LayoutParams( + dipToPx(this, 100), dipToPx(this, 100), Gravity.CENTER)); + + AlphaAnimation a = new AlphaAnimation(1.0f, 0.0f); + a.setDuration(2000); + a.setRepeatCount(Animation.INFINITE); + a.setRepeatMode(Animation.REVERSE); + color.startAnimation(a); + + setContentView(container); + } + + @SuppressWarnings({"UnusedDeclaration"}) + static int dipToPx(Context c, int dip) { + return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f); + } + + static class ColorView extends View { + ColorView(Context c) { + super(c); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRGB(0, 255, 0); + } + } + + static class DirtyBitmapView extends FrameLayout { + private final Paint mPaint; + + DirtyBitmapView(Context c) { + super(c); + mPaint = new Paint(); + } + + @Override + public void dispatchDraw(Canvas canvas) { + canvas.drawRGB(255, 255, 255); + + mPaint.setColor(0xffff0000); + canvas.drawRect(200.0f, 0.0f, 220.0f, 20.0f, mPaint); + + canvas.save(); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); + Log.d(LOG_TAG, "rejected = " + canvas.quickReject(100.0f, 100.0f, 110.0f, 110.0f, + Canvas.EdgeType.BW)); + Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f, + Canvas.EdgeType.BW)); + canvas.restore(); + + canvas.save(); + canvas.scale(2.0f, 2.0f); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); + Log.d(LOG_TAG, "rejected = " + canvas.quickReject(50.0f, 50.0f, 60.0f, 60.0f, + Canvas.EdgeType.BW)); + Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f, + Canvas.EdgeType.BW)); + canvas.restore(); + + canvas.save(); + canvas.translate(20.0f, 20.0f); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); + Log.d(LOG_TAG, "rejected = " + canvas.quickReject(80.0f, 80.0f, 90.0f, 90.0f, + Canvas.EdgeType.BW)); + Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f, + Canvas.EdgeType.BW)); + canvas.restore(); + + canvas.save(); + canvas.scale(2.0f, 2.0f); + canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); + + mPaint.setColor(0xff00ff00); + canvas.drawRect(0.0f, 0.0f, 20.0f, 20.0f, mPaint); + + mPaint.setColor(0xff0000ff); + canvas.drawRect(20.0f, 0.0f, 40.0f, 20.0f, mPaint); + + canvas.restore(); + + final int restoreTo = canvas.save(); + canvas.saveLayerAlpha(0.0f, 100.0f, getWidth(), 150.0f, 127, + Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + mPaint.setColor(0xff0000ff); + canvas.drawRect(0.0f, 100.0f, 40.0f, 150.0f, mPaint); + mPaint.setColor(0xff00ffff); + canvas.drawRect(40.0f, 100.0f, 140.0f, 150.0f, mPaint); + mPaint.setColor(0xffff00ff); + canvas.drawRect(140.0f, 100.0f, 240.0f, 150.0f, mPaint); + canvas.restoreToCount(restoreTo); + + super.dispatchDraw(canvas); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java new file mode 100644 index 0000000..cfa8d3c --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsActivity.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.ScaleAnimation; +import android.widget.FrameLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class BitmapsActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final BitmapsView view = new BitmapsView(this); + final FrameLayout layout = new FrameLayout(this); + layout.addView(view, new FrameLayout.LayoutParams(480, 800, Gravity.CENTER)); + setContentView(layout); + + ScaleAnimation a = new ScaleAnimation(1.0f, 2.0f, 1.0f, 2.0f, + ScaleAnimation.RELATIVE_TO_SELF, 0.5f, + ScaleAnimation.RELATIVE_TO_SELF,0.5f); + a.setDuration(2000); + a.setRepeatCount(Animation.INFINITE); + a.setRepeatMode(Animation.REVERSE); + view.startAnimation(a); + } + + static class BitmapsView extends View { + private Paint mBitmapPaint; + private final Bitmap mBitmap1; + private final Bitmap mBitmap2; + private final PorterDuffXfermode mDstIn; + + BitmapsView(Context c) { + super(c); + + mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2); + + mBitmapPaint = new Paint(); + mDstIn = new PorterDuffXfermode(PorterDuff.Mode.DST_IN); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.translate(120.0f, 50.0f); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint); + + canvas.translate(0.0f, mBitmap1.getHeight()); + canvas.translate(0.0f, 25.0f); + canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, null); + + mBitmapPaint.setAlpha(127); + canvas.translate(0.0f, mBitmap2.getHeight()); + canvas.translate(0.0f, 25.0f); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint); + + mBitmapPaint.setAlpha(255); + canvas.translate(0.0f, mBitmap1.getHeight()); + canvas.translate(0.0f, 25.0f); + mBitmapPaint.setColor(0xffff0000); + canvas.drawRect(0.0f, 0.0f, mBitmap2.getWidth(), mBitmap2.getHeight(), mBitmapPaint); + mBitmapPaint.setXfermode(mDstIn); + canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBitmapPaint); + + mBitmapPaint.reset(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsRectActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsRectActivity.java new file mode 100644 index 0000000..f8726c2 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/BitmapsRectActivity.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class BitmapsRectActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final BitmapsView view = new BitmapsView(this); + setContentView(view); + } + + static class BitmapsView extends View { + private Paint mBitmapPaint; + private final Bitmap mBitmap1; + private final Bitmap mBitmap2; + private final Rect mSrcRect; + private final RectF mDstRect; + private final RectF mDstRect2; + + BitmapsView(Context c) { + super(c); + + mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2); + + mBitmapPaint = new Paint(); + mBitmapPaint.setFilterBitmap(true); + + final float fourth = mBitmap1.getWidth() / 4.0f; + final float half = mBitmap1.getHeight() / 2.0f; + mSrcRect = new Rect((int) fourth, (int) (half - half / 2.0f), + (int) (fourth + fourth), (int) (half + half / 2.0f)); + mDstRect = new RectF(fourth, half - half / 2.0f, fourth + fourth, half + half / 2.0f); + mDstRect2 = new RectF(fourth, half - half / 2.0f, + (fourth + fourth) * 3.0f, (half + half / 2.0f) * 3.0f); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.translate(120.0f, 50.0f); + canvas.drawBitmap(mBitmap1, mSrcRect, mDstRect, mBitmapPaint); + + canvas.translate(0.0f, mBitmap1.getHeight()); + canvas.translate(-100.0f, 25.0f); + canvas.drawBitmap(mBitmap1, mSrcRect, mDstRect2, mBitmapPaint); + } + } +}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java new file mode 100644 index 0000000..437cd1c --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/LayersActivity.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class LayersActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(new LayersView(this)); + } + + static class LayersView extends View { + private Paint mLayerPaint; + private final Paint mRectPaint; + + LayersView(Context c) { + super(c); + + mLayerPaint = new Paint(); + mRectPaint = new Paint(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.translate(140.0f, 100.0f); + + //canvas.drawRGB(255, 255, 255); + + int count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xffff0000); + canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint); + + canvas.restoreToCount(count); + + canvas.translate(0.0f, 125.0f); + + count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xff00ff00); + mRectPaint.setAlpha(50); + canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint); + + canvas.restoreToCount(count); + + canvas.translate(25.0f, 125.0f); + + mRectPaint.setColor(0xff0000ff); + mRectPaint.setAlpha(255); + canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint); + + mLayerPaint.setAlpha(127); + mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); + count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xffff0000); + canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint); + + canvas.restoreToCount(count); + + canvas.translate(0.0f, 125.0f); + + mRectPaint.setColor(0xff0000ff); + mRectPaint.setAlpha(255); + canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint); + + mLayerPaint.setColor(0xffff0000); + mLayerPaint.setAlpha(127); + mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); + count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint, + Canvas.ALL_SAVE_FLAG); + + mRectPaint.setColor(0xffff0000); + canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint); + + canvas.restoreToCount(count); + + mLayerPaint = new Paint(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java new file mode 100644 index 0000000..c638958 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.TextView; + +@SuppressWarnings({"UnusedDeclaration"}) +public class ListActivity extends Activity { + private static final String[] DATA_LIST = { + "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", + "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", + "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", + "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", + "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", + "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", + "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria", + "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde", + "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", + "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", + "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", + "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic", + "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", + "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland", + "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia", + "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar", + "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", + "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary", + "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", + "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos", + "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", + "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", + "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova", + "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", + "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", + "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas", + "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", + "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar", + "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena", + "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", + "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal", + "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", + "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea", + "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden", + "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas", + "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", + "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda", + "Ukraine", "United Arab Emirates", "United Kingdom", + "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", + "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara", + "Yemen", "Yugoslavia", "Zambia", "Zimbabwe" + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.list_activity); + + ListAdapter adapter = new SimpleListAdapter(this); + + ListView list = (ListView) findViewById(R.id.list); + list.setAdapter(adapter); + } + + private static class SimpleListAdapter extends ArrayAdapter<String> { + public SimpleListAdapter(Context context) { + super(context, android.R.layout.simple_list_item_1, DATA_LIST); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView v = (TextView) super.getView(position, convertView, parent); + final Resources r = getContext().getResources(); + final DisplayMetrics metrics = r.getDisplayMetrics(); + v.setCompoundDrawablePadding((int) (6 * metrics.density + 0.5f)); + v.setCompoundDrawablesWithIntrinsicBounds(r.getDrawable(R.drawable.icon), + null, null, null); + return v; + } + } +}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java new file mode 100644 index 0000000..3268fbf --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/NinePatchesActivity.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.os.Bundle; +import android.view.Gravity; +import android.widget.Button; +import android.widget.FrameLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class NinePatchesActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + FrameLayout layout = new FrameLayout(this); + Button b = new Button(this); + b.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, + FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); + b.setText("9 patches"); + layout.addView(b); + layout.setBackgroundColor(0xffffffff); + + setContentView(layout); + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java new file mode 100644 index 0000000..fd7a1e6 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/QuickRejectActivity.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class QuickRejectActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final QuickRejectView view = new QuickRejectView(this); + setContentView(view); + } + + static class QuickRejectView extends View { + private Paint mBitmapPaint; + private final Bitmap mBitmap1; + + QuickRejectView(Context c) { + super(c); + + mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + + mBitmapPaint = new Paint(); + mBitmapPaint.setFilterBitmap(true); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.save(); + canvas.clipRect(0.0f, 0.0f, 40.0f, 40.0f); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBitmapPaint); + canvas.drawBitmap(mBitmap1, -mBitmap1.getWidth(), 0.0f, mBitmapPaint); + canvas.drawBitmap(mBitmap1, 50.0f, 0.0f, mBitmapPaint); + canvas.restore(); + } + } +}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java new file mode 100644 index 0000000..e629cb8 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class RotationActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + DrawingView container = new DrawingView(this); + + setContentView(container); + } + + @SuppressWarnings({"UnusedDeclaration"}) + static int dipToPx(Context c, int dip) { + return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f); + } + + static class DrawingView extends View { + private final Paint mPaint; + + DrawingView(Context c) { + super(c); + mPaint = new Paint(); + mPaint.setAntiAlias(true); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.translate(dipToPx(getContext(), 400), dipToPx(getContext(), 200)); + canvas.rotate(45.0f); + canvas.drawRGB(255, 255, 255); + mPaint.setColor(0xffff0000); + canvas.drawRect(-80.0f, -80.0f, 80.0f, 80.0f, mPaint); + canvas.drawRect(0.0f, 0.0f, 220.0f, 220.0f, mPaint); + canvas.restore(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java new file mode 100644 index 0000000..1912245 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ShadersActivity.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Shader; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class ShadersActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(new ShadersView(this)); + } + + static class ShadersView extends View { + private BitmapShader mRepeatShader; + private BitmapShader mTranslatedShader; + private BitmapShader mScaledShader; + private int mTexWidth; + private int mTexHeight; + private Paint mPaint; + private float mDrawWidth; + private float mDrawHeight; + private LinearGradient mHorGradient; + private LinearGradient mDiagGradient; + private LinearGradient mVertGradient; + + ShadersView(Context c) { + super(c); + + Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + mTexWidth = texture.getWidth(); + mTexHeight = texture.getHeight(); + mDrawWidth = mTexWidth * 2.2f; + mDrawHeight = mTexHeight * 1.2f; + + mRepeatShader = new BitmapShader(texture, Shader.TileMode.REPEAT, + Shader.TileMode.REPEAT); + + mTranslatedShader = new BitmapShader(texture, Shader.TileMode.REPEAT, + Shader.TileMode.REPEAT); + Matrix m1 = new Matrix(); + m1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f); + mTranslatedShader.setLocalMatrix(m1); + + mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR, + Shader.TileMode.MIRROR); + Matrix m2 = new Matrix(); + m2.setScale(0.5f, 0.5f); + mScaledShader.setLocalMatrix(m2); + + mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f, + Color.RED, Color.GREEN, Shader.TileMode.REPEAT); + + mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 1.5f, mDrawHeight, + Color.BLUE, Color.MAGENTA, Shader.TileMode.CLAMP); + + mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f, + Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR); + + mPaint = new Paint(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + //canvas.drawRGB(255, 255, 255); + + // Bitmap shaders + canvas.save(); + canvas.translate(40.0f, 40.0f); + + mPaint.setShader(mRepeatShader); + canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); + + canvas.translate(0.0f, 40.0f + mDrawHeight); + mPaint.setShader(mTranslatedShader); + canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); + + canvas.translate(0.0f, 40.0f + mDrawHeight); + mPaint.setShader(mScaledShader); + canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); + + canvas.restore(); + + // Gradients + canvas.save(); + canvas.translate(40.0f + mDrawWidth + 40.0f, 40.0f); + + mPaint.setShader(mHorGradient); + canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); + + canvas.translate(0.0f, 40.0f + mDrawHeight); + mPaint.setShader(mDiagGradient); + canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); + + canvas.translate(0.0f, 40.0f + mDrawHeight); + mPaint.setShader(mVertGradient); + canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint); + + canvas.restore(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java new file mode 100644 index 0000000..3b5cf43 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/TextActivity.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class TextActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(new CustomTextView(this)); + } + + static class CustomTextView extends View { + private final Paint mMediumPaint; + private final Paint mLargePaint; + + CustomTextView(Context c) { + super(c); + + mMediumPaint = new Paint(); + mMediumPaint.setAntiAlias(true); + mMediumPaint.setColor(0xffff0000); + mLargePaint = new Paint(); + mLargePaint.setAntiAlias(true); + mLargePaint.setTextSize(36.0f); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRGB(255, 255, 255); + + canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint); + mMediumPaint.setTextAlign(Paint.Align.CENTER); + canvas.drawText("Hello OpenGL renderer!", 100, 40, mMediumPaint); + mMediumPaint.setTextAlign(Paint.Align.RIGHT); + canvas.drawText("Hello OpenGL renderer!", 100, 60, mMediumPaint); + mMediumPaint.setTextAlign(Paint.Align.LEFT); + canvas.drawText("Hello OpenGL renderer!", 100, 100, mMediumPaint); + canvas.drawText("Hello OpenGL renderer!", 100, 200, mLargePaint); + + canvas.save(); + canvas.clipRect(150.0f, 220.0f, 450.0f, 320.0f); + canvas.drawText("Hello OpenGL renderer!", 100, 300, mLargePaint); + canvas.restore(); + } + } +}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java new file mode 100644 index 0000000..8c81f02 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/XfermodeActivity.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2010 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.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.os.Bundle; +import android.view.View; + +import static android.graphics.PorterDuff.Mode; + +@SuppressWarnings({"UnusedDeclaration"}) +public class XfermodeActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(new XfermodesView(this)); + } + + static class XfermodesView extends View { + private final Paint mBluePaint; + private final Paint mRedPaint; + + XfermodesView(Context c) { + super(c); + + mBluePaint = new Paint(); + mBluePaint.setColor(0xff0000ff); + + mRedPaint = new Paint(); + mRedPaint.setColor(0x7fff0000); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + //canvas.drawRGB(255, 255, 255); + + canvas.translate(100.0f, 100.0f); + + // SRC modes + canvas.save(); + + drawRects(canvas, Mode.SRC_OVER); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.SRC_IN); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.SRC_OUT); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.SRC_ATOP); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.SRC); + + canvas.restore(); + + canvas.translate(100.0f, 0.0f); + + // DST modes + canvas.save(); + + drawRects(canvas, Mode.DST_OVER); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.DST_IN); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.DST_OUT); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.DST_ATOP); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.DST); + + canvas.restore(); + + canvas.translate(100.0f, 0.0f); + + // Other modes + canvas.save(); + + drawRects(canvas, Mode.CLEAR); + canvas.translate(0.0f, 100.0f); + + drawRects(canvas, Mode.XOR); + + canvas.translate(0.0f, 100.0f); + + mBluePaint.setAlpha(127); + canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint); + + canvas.translate(0.0f, 100.0f); + + mBluePaint.setAlpha(10); + mBluePaint.setColor(0x7f0000ff); + canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint); + + mBluePaint.setColor(0xff0000ff); + mBluePaint.setAlpha(255); + + canvas.restore(); + } + + private void drawRects(Canvas canvas, PorterDuff.Mode mode) { + canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint); + + canvas.save(); + canvas.translate(25.0f, 25.0f); + mRedPaint.setXfermode(new PorterDuffXfermode(mode)); + canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mRedPaint); + canvas.restore(); + } + } +} |