diff options
Diffstat (limited to 'tests')
83 files changed, 6465 insertions, 2924 deletions
diff --git a/tests/ActivityTests/res/anim/slow_enter.xml b/tests/ActivityTests/res/anim/slow_enter.xml new file mode 100644 index 0000000..0309643 --- /dev/null +++ b/tests/ActivityTests/res/anim/slow_enter.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" > + <scale android:fromXScale="0.9" android:toXScale="1.5" + android:fromYScale="0.9" android:toYScale="1.5" + android:pivotX="50%" android:pivotY="50%" + android:interpolator="@interpolator/slow_enter" + android:duration="40000" /> + <alpha android:fromAlpha="0.0" android:toAlpha="1.0" + android:interpolator="@android:interpolator/decelerate_cubic" + android:duration="1000" /> +</set> diff --git a/tests/ActivityTests/res/anim/slow_exit.xml b/tests/ActivityTests/res/anim/slow_exit.xml new file mode 100644 index 0000000..6cd3114 --- /dev/null +++ b/tests/ActivityTests/res/anim/slow_exit.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:shareInterpolator="false" > + <scale android:fromXScale="1.0" android:toXScale="0.9" + android:fromYScale="1.0" android:toYScale="0.9" + android:pivotX="50%" android:pivotY="50%" + android:interpolator="@android:interpolator/decelerate_quint" + android:duration="300" /> + <alpha android:fromAlpha="1.0" android:toAlpha="0.0" + android:interpolator="@android:interpolator/decelerate_cubic" + android:duration="300"/> +</set> diff --git a/tests/ActivityTests/res/interpolator/slow_enter.xml b/tests/ActivityTests/res/interpolator/slow_enter.xml new file mode 100644 index 0000000..ddab1aa --- /dev/null +++ b/tests/ActivityTests/res/interpolator/slow_enter.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2011, 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. +*/ +--> + +<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:cycles="10" /> diff --git a/tests/TileBenchmark/tests/AndroidManifest.xml b/tests/ActivityTests/res/values/themes.xml index 703b152..67f5938 100644 --- a/tests/TileBenchmark/tests/AndroidManifest.xml +++ b/tests/ActivityTests/res/values/themes.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2008 The Android Open Source Project +<!-- Copyright (C) 2011 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. @@ -14,14 +14,12 @@ limitations under the License. --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.test.tilebenchmark.tests"> - - <application> - <uses-library android:name="android.test.runner" /> - </application> - - <instrumentation android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.test.tilebenchmark" - android:label="Tests for WebView Tiles."/> -</manifest> +<resources> + <style name="SlowDialog" parent="@android:style/Theme.Holo.Dialog"> + <item name="android:windowAnimationStyle">@style/SlowDialog</item> + </style> + <style name="SlowDialog"> + <item name="android:windowEnterAnimation">@anim/slow_enter</item> + <item name="android:windowExitAnimation">@anim/slow_exit</item> + </style> +</resources> diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index 583c13c..ae42e29 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -22,6 +22,7 @@ import java.util.List; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityThread; +import android.app.AlertDialog; import android.app.Application; import android.content.ActivityNotFoundException; import android.os.Bundle; @@ -35,6 +36,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.ScrollView; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -101,6 +104,20 @@ public class ActivityTestMain extends Activity { } @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add("Animate!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + AlertDialog.Builder builder = new AlertDialog.Builder(ActivityTestMain.this, + R.style.SlowDialog); + builder.setTitle("This is a title"); + builder.show(); + return true; + } + }); + return true; + } + + @Override protected void onStart() { super.onStart(); buildUi(); diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml index f503658..7d4d4db 100644 --- a/tests/BiDiTests/res/layout/basic.xml +++ b/tests/BiDiTests/res/layout/basic.xml @@ -19,6 +19,10 @@ android:layout_width="fill_parent" android:layout_height="fill_parent"> + <ScrollView + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -131,4 +135,6 @@ </LinearLayout> + </ScrollView> + </FrameLayout> diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml index b1f5e50..233cd0d 100644 --- a/tests/BiDiTests/res/values/strings.xml +++ b/tests/BiDiTests/res/values/strings.xml @@ -24,11 +24,11 @@ <string name="button_before_text">Start</string> <string name="button_requestlayout_text">Request Layout</string> <string name="button_alert_dialog_text">AlertDialog</string> - <string name="textview_text">This is a text for a TextView</string> - <string name="textview_ltr_text">This is a text for a LTR TextView</string> - <string name="textview_rtl_text">This is a text for a RTL TextView</string> - <string name="textview_default_text">This is a text for a default TextView</string> - <string name="textview_password_default_text">This is a text for a password TextView</string> + <string name="textview_text">TextView</string> + <string name="textview_ltr_text">LTR TextView</string> + <string name="textview_rtl_text">RTL TextView</string> + <string name="textview_default_text">Default TextView</string> + <string name="textview_password_default_text">Password TextView</string> <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string> <string name="normal_text">Normal String</string> <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string> @@ -50,5 +50,6 @@ <string name="rtl">"والحق أن تترك ونص"</string> <string name="composing">"\u0644\u0627"</string> <string name="url">www.amazon.co.uk/gp/aw/h.html/275-8912818-8203452</string> + <string name="pointer_location" msgid="6084434787496938001">"ตำแหน่งของตัวชี้"</string> </resources> diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java index 0126dea..0b1974a 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java @@ -51,6 +51,7 @@ public class BiDiTestView extends View { private String MIXED_TEXT_1; private String HEBREW_TEXT; private String RTL_TEXT; + private String THAI_TEXT; private int currentTextSize; @@ -82,6 +83,7 @@ public class BiDiTestView extends View { MIXED_TEXT_1 = context.getString(R.string.mixed_text_1); HEBREW_TEXT = context.getString(R.string.hebrew_text); RTL_TEXT = context.getString(R.string.rtl); + THAI_TEXT = context.getString(R.string.pointer_location); } public void setCurrentTextSize(int size) { @@ -134,6 +136,10 @@ public class BiDiTestView extends View { // Test Hebrew deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize, false, false, Paint.DIRECTION_RTL, currentTextSize); + + // Test Thai + deltaX = testString(canvas, THAI_TEXT, ORIGIN, ORIGIN + 16 * currentTextSize, + false, false, Paint.DIRECTION_LTR, currentTextSize); } private int testString(Canvas canvas, String text, int x, int y, diff --git a/tests/CoreTests/android/core/CharArrayWriterTest.java b/tests/CoreTests/android/core/CharArrayWriterTest.java deleted file mode 100644 index 0aae1e4..0000000 --- a/tests/CoreTests/android/core/CharArrayWriterTest.java +++ /dev/null @@ -1,48 +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.TestCase; - -import java.io.CharArrayWriter; -import android.test.suitebuilder.annotation.SmallTest; - -/** - * Basic tests for CharArrayWriter. - */ -public class CharArrayWriterTest extends TestCase { - - @SmallTest - public void testCharArrayWriter() throws Exception { - String str = "AbCdEfGhIjKlMnOpQrStUvWxYz"; - CharArrayWriter a = new CharArrayWriter(); - CharArrayWriter b = new CharArrayWriter(); - - a.write(str, 0, 26); - a.write('X'); - a.writeTo(b); - - assertEquals(27, a.size()); - assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString()); - - b.write("alphabravodelta", 5, 5); - b.append('X'); - assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", b.toString()); - b.append("omega"); - assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", b.toString()); - } -} diff --git a/tests/CoreTests/android/core/ClassLoaderTest.java b/tests/CoreTests/android/core/ClassLoaderTest.java deleted file mode 100644 index 5e7f5a4..0000000 --- a/tests/CoreTests/android/core/ClassLoaderTest.java +++ /dev/null @@ -1,243 +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.TestCase; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import android.test.suitebuilder.annotation.Suppress; - -/** - * Test for basic ClassLoader functionality. - */ -@Suppress -public class ClassLoaderTest extends TestCase { - /* - package my.pkg; - public class CLTest { - public CLTest() {} - - public String test() { return "This is test 1"; } - } - */ - static private byte[] test1class = { - (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31, - (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00, - (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08, - (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00, - (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10, - (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c, - (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74, - (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03, - (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01, - (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f, - (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00, - (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e, - (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d, - (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54, - (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65, - (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, - (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29, - (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76, - (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61, - (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53, - (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e, - (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00, - (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75, - (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46, - (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01, - (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c, - (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, - (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76, - (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05, - (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00, - (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69, - (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, - (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73, - (byte) 0x74, (byte) 0x20, (byte) 0x31, (byte) 0x01, - (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79, - (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67, - (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, - (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61, - (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c, - (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f, - (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, - (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21, - (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, - (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01, - (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00, - (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12, - (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c - }; - - /* - package my.pkg; - public class CLTest { - public CLTest() {} - - public String test() { return "This is test 2"; } - } - */ - static private byte[] test2class = { - (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31, - (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00, - (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08, - (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00, - (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10, - (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c, - (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74, - (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03, - (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01, - (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f, - (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00, - (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e, - (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d, - (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54, - (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65, - (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, - (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29, - (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76, - (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61, - (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53, - (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e, - (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00, - (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75, - (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46, - (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01, - (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c, - (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, - (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76, - (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05, - (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00, - (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69, - (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73, - (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73, - (byte) 0x74, (byte) 0x20, (byte) 0x32, (byte) 0x01, - (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79, - (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67, - (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54, - (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01, - (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61, - (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c, - (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f, - (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65, - (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21, - (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05, - (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01, - (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, - (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00, - (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00, - (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, - (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12, - (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08, - (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06, - (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, - (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00, - (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c - }; - - /* - * Custom class loader. - */ - private class MyLoader extends ClassLoader { - public MyLoader(byte[] data) { - super(); - mData = data; - } - - protected Class<?> findClass(String name) throws ClassNotFoundException { - assertEquals("my.pkg.CLTest", name); - return defineClass(name, mData, 0, mData.length); - } - - byte[] mData; - } - - - /* - * Simple test: manually load two class files that have the same class - * name but different contents. - */ - public void testClassLoader() throws Exception { - Class test1, test2; - MyLoader loader1 = new MyLoader(test1class); - MyLoader loader2 = new MyLoader(test2class); - - test1 = loader1.loadClass("my.pkg.CLTest"); - test2 = loader2.loadClass("my.pkg.CLTest"); - - methodTest(test1, "This is test 1"); - methodTest(test2, "This is test 2"); - } - - /* - * Invoke the test() method and verify that the string returned - * matches what we expect. - */ - private static void methodTest(Class clazz, String expect) - throws NoSuchMethodException, InstantiationException, - IllegalAccessException, InvocationTargetException { - Method meth = clazz.getMethod("test", (Class[]) null); - Object obj = clazz.newInstance(); - Object result = meth.invoke(obj, (Object[]) null); - - assertEquals(result, expect); - } -} - diff --git a/tests/CoreTests/android/core/ClassTest.java b/tests/CoreTests/android/core/ClassTest.java deleted file mode 100644 index cc1b4ca..0000000 --- a/tests/CoreTests/android/core/ClassTest.java +++ /dev/null @@ -1,337 +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 android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.widget.Button; -import junit.framework.TestCase; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.Set; - - -class ClassWithPrivateConstructor { - private ClassWithPrivateConstructor() { - } -} - -public class ClassTest extends TestCase { - - @SmallTest - public void testClass() throws Exception { - // Now, never mind the fact that most of this stuff has to work - // for the test harness to get this far.... - - //System.out.println("Class.forName()"); - Class helloClass = Class.forName(ClassTest.class.getName()); - - //System.out.println("Class.newInstance()"); - Object instance = helloClass.newInstance(); - assertNotNull(instance); - - //System.out.println("Class.forName() nonexisting class"); - try { - Class.forName("this.class.DoesNotExist"); - fail("unexpected success"); - } catch (ClassNotFoundException ex) { - // expected - } - - //System.out.println("Class.newInstance() private constructor"); - try { - Class.forName("android.core.ClassWithPrivateConstructor").newInstance(); - fail("unexpected success"); - } catch (IllegalAccessException ex) { - // this is expected - } - - //System.out.println("Class.getDeclaredMethod()"); - - Method method = helloClass.getDeclaredMethod("method", (Class[]) null); - - method.invoke(new ClassTest(), (Object[]) null); - - //System.out.println("Class.getDeclaredMethod() w/ args"); - - method = helloClass.getDeclaredMethod("methodWithArgs", Object.class); - - Object invokeArgs[] = new Object[1]; - invokeArgs[0] = "Hello"; - Object ret = method.invoke(new ClassTest(), invokeArgs); - assertEquals(ret, invokeArgs[0]); - - //System.out.println("Class.getDeclaredMethod() -- private"); - - method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null); - - method.invoke(new ClassTest(), (Object[]) null); - //fail("unexpected success"); - // TODO: I think this actually *should* succeed, because the - // call to the private method is being made from the same class. - // This needs to be replaced with a private call to a different - // class. - - //System.out.println("Class.getSuperclass"); - Class objectClass = Class.forName("java.lang.Object"); - assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass); - - //System.out.println("Class.isAssignableFrom"); - assertTrue(objectClass.isAssignableFrom(helloClass)); - assertFalse(helloClass.isAssignableFrom(objectClass)); - - //System.out.println("Class.getConstructor"); - - Constructor constructor = helloClass.getConstructor((Class[]) null); - assertNotNull(constructor); - - //System.out.println("Class.getModifiers"); - - assertTrue(Modifier.isPublic(helloClass.getModifiers())); - //System.out.println("Modifiers: " + Modifier.toString(helloClass.getModifiers())); - - //System.out.println("Class.getMethod"); - - helloClass.getMethod("method", (Class[]) null); - - try { - Class[] argTypes = new Class[1]; - argTypes[0] = helloClass; - helloClass.getMethod("method", argTypes); - fail("unexpected success"); - } catch (NoSuchMethodException ex) { - // exception expected - } - - // Test for public tracker issue 14 - SimpleClass obj = new SimpleClass(); - Field field = obj.getClass().getDeclaredField("str"); - field.set(obj, null); - } - - public class SimpleClass { - public String str; - } - - public Object methodWithArgs(Object o) { - return o; - } - - boolean methodInvoked; - - public void method() { - methodInvoked = true; - } - - boolean privateMethodInvoked; - - public void privateMethod() { - privateMethodInvoked = true; - } - - // Regression for 1018067: Class.getMethods() returns the same method over - // and over again from all base classes - @MediumTest - public void testClassGetMethodsNoDupes() { - Method[] methods = Button.class.getMethods(); - Set<String> set = new HashSet<String>(); - - for (int i = 0; i < methods.length; i++) { - String signature = methods[i].toString(); - - int par = signature.indexOf('('); - int dot = signature.lastIndexOf('.', par); - - signature = signature.substring(dot + 1); - - assertFalse("Duplicate " + signature, set.contains(signature)); - set.add(signature); - } - } - - interface MyInterface { - void foo(); - } - - interface MyOtherInterface extends MyInterface { - void bar(); - } - - abstract class MyClass implements MyOtherInterface { - public void gabba() { - } - - public void hey() { - } - } - - // Check if we also reflect methods from interfaces - @SmallTest - public void testGetMethodsInterfaces() { - Method[] methods = MyInterface.class.getMethods(); - assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); - - methods = MyOtherInterface.class.getMethods(); - assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); - assertTrue("Interface method must be there", hasMethod(methods, ".bar(")); - - methods = MyClass.class.getMethods(); - assertTrue("Interface method must be there", hasMethod(methods, ".foo(")); - assertTrue("Interface method must be there", hasMethod(methods, ".bar(")); - - assertTrue("Declared method must be there", hasMethod(methods, ".gabba(")); - assertTrue("Declared method must be there", hasMethod(methods, ".hey(")); - - assertTrue("Inherited method must be there", hasMethod(methods, ".toString(")); - } - - private boolean hasMethod(Method[] methods, String signature) { - for (int i = 0; i < methods.length; i++) { - if (methods[i].toString().contains(signature)) { - return true; - } - } - - return false; - } - - // Test for Class.getPackage(); - @SmallTest - public void testClassGetPackage() { - assertNotNull("Package must be non-null", getClass().getPackage()); - assertEquals("Package must have expected name", "android.core", getClass().getPackage().getName()); - assertEquals("Package must have expected title", "Unknown", getClass().getPackage().getSpecificationTitle()); - - Package p = java.lang.Object.class.getPackage(); - assertNotNull("Package must be non-null", p); - assertEquals("Package must have expected name", "java.lang", p.getName()); - assertSame("Package object must be same for each call", p, java.lang.Object.class.getPackage()); - } - - // Regression test for #1123708: Problem with getCanonicalName(), - // getSimpleName(), and getPackage(). - // - // A couple of interesting cases need to be checked: Top-level classes, - // member classes, local classes, and anonymous classes. Also, boundary - // cases with '$' in the class names are checked, since the '$' is used - // as the separator between outer and inner class, so this might lead - // to problems (it did in the previous implementation). - // - // Caution: Adding local or anonymous classes elsewhere in this - // file might affect the test. - private class MemberClass { - // This space intentionally left blank. - } - - private class Mi$o$oup { - // This space intentionally left blank. - } - - @SmallTest - public void testVariousClassNames() { - Class<?> clazz = this.getClass(); - String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + "."); - - // Simple, top-level class - - assertEquals("Top-level class name must be correct", pkg + "ClassTest", clazz.getName()); - assertEquals("Top-level class simple name must be correct", "ClassTest", clazz.getSimpleName()); - assertEquals("Top-level class canonical name must be correct", pkg + "ClassTest", clazz.getCanonicalName()); - - clazz = MemberClass.class; - - assertEquals("Member class name must be correct", pkg + "ClassTest$MemberClass", clazz.getName()); - assertEquals("Member class simple name must be correct", "MemberClass", clazz.getSimpleName()); - assertEquals("Member class canonical name must be correct", pkg + "ClassTest.MemberClass", clazz.getCanonicalName()); - - class LocalClass { - // This space intentionally left blank. - } - - clazz = LocalClass.class; - - assertEquals("Local class name must be correct", pkg + "ClassTest$1LocalClass", clazz.getName()); - assertEquals("Local class simple name must be correct", "LocalClass", clazz.getSimpleName()); - assertNull("Local class canonical name must be null", clazz.getCanonicalName()); - - clazz = new Object() { }.getClass(); - - assertEquals("Anonymous class name must be correct", pkg + "ClassTest$1", clazz.getName()); - assertEquals("Anonymous class simple name must be empty", "", clazz.getSimpleName()); - assertNull("Anonymous class canonical name must be null", clazz.getCanonicalName()); - - // Weird special cases with dollar in name. - - clazz = Mou$$aka.class; - - assertEquals("Top-level class name must be correct", pkg + "Mou$$aka", clazz.getName()); - assertEquals("Top-level class simple name must be correct", "Mou$$aka", clazz.getSimpleName()); - assertEquals("Top-level class canonical name must be correct", pkg + "Mou$$aka", clazz.getCanonicalName()); - - clazz = Mi$o$oup.class; - - assertEquals("Member class name must be correct", pkg + "ClassTest$Mi$o$oup", clazz.getName()); - assertEquals("Member class simple name must be correct", "Mi$o$oup", clazz.getSimpleName()); - assertEquals("Member class canonical name must be correct", pkg + "ClassTest.Mi$o$oup", clazz.getCanonicalName()); - - class Ma$hedPotatoe$ { - // This space intentionally left blank. - } - - clazz = Ma$hedPotatoe$.class; - - assertEquals("Member class name must be correct", pkg + "ClassTest$1Ma$hedPotatoe$", clazz.getName()); - assertEquals("Member class simple name must be correct", "Ma$hedPotatoe$", clazz.getSimpleName()); - assertNull("Member class canonical name must be null", clazz.getCanonicalName()); - } - - @SmallTest - public void testLocalMemberClass() { - Class<?> clazz = this.getClass(); - - assertFalse("Class must not be member", clazz.isMemberClass()); - assertFalse("Class must not be local", clazz.isLocalClass()); - - clazz = MemberClass.class; - - assertTrue("Class must be member", clazz.isMemberClass()); - assertFalse("Class must not be local", clazz.isLocalClass()); - - class OtherLocalClass { - // This space intentionally left blank. - } - - clazz = OtherLocalClass.class; - - assertFalse("Class must not be member", clazz.isMemberClass()); - assertTrue("Class must be local", clazz.isLocalClass()); - - clazz = new Object() { }.getClass(); - - assertFalse("Class must not be member", clazz.isMemberClass()); - assertFalse("Class must not be local", clazz.isLocalClass()); - } - -} - -class Mou$$aka { - // This space intentionally left blank. -} diff --git a/tests/CoreTests/android/core/MiscRegressionTest.java b/tests/CoreTests/android/core/MiscRegressionTest.java index 7734397..32995b5 100644 --- a/tests/CoreTests/android/core/MiscRegressionTest.java +++ b/tests/CoreTests/android/core/MiscRegressionTest.java @@ -16,56 +16,12 @@ package android.core; -import junit.framework.Assert; -import junit.framework.TestCase; - -import java.io.File; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.security.KeyStore; -import java.security.cert.Certificate; -import java.util.Arrays; -import java.util.ConcurrentModificationException; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Random; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.logging.Logger; -import java.util.zip.Deflater; -import java.util.zip.Inflater; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.LargeTest; +import java.util.logging.Logger; +import junit.framework.TestCase; public class MiscRegressionTest extends TestCase { - // Regression test for #857840: want JKS key store - @SmallTest - public void testDefaultKeystore() { - String type = KeyStore.getDefaultType(); - Assert.assertEquals("Default keystore type must be Bouncy Castle", "BKS", type); - - try { - KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); - Assert.assertNotNull("Keystore must not be null", store); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - - try { - KeyStore store = KeyStore.getInstance("BKS"); - Assert.assertNotNull("Keystore must not be null", store); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - // Regression test for #951285: Suitable LogHandler should be chosen // depending on the environment. @MediumTest @@ -78,408 +34,4 @@ public class MiscRegressionTest extends TestCase { Logger.global.finer("This has logging Level.FINER, should become VERBOSE"); Logger.global.finest("This has logging Level.FINEST, should become VERBOSE"); } - - // Regression test for Issue 5697: - // getContextClassLoader returns a non-application classloader - // http://code.google.com/p/android/issues/detail?id=5697 - // - @MediumTest - public void testJavaContextClassLoader() throws Exception { - Assert.assertNotNull("Must hava a Java context ClassLoader", - Thread.currentThread().getContextClassLoader()); - } - - // Regression test for #1045939: Different output for Method.toString() - @SmallTest - public void testMethodToString() { - try { - Method m1 = Object.class.getMethod("notify", new Class[] { }); - Method m2 = Object.class.getMethod("toString", new Class[] { }); - Method m3 = Object.class.getMethod("wait", new Class[] { long.class, int.class }); - Method m4 = Object.class.getMethod("equals", new Class[] { Object.class }); - Method m5 = String.class.getMethod("valueOf", new Class[] { char[].class }); - Method m6 = Runtime.class.getMethod("exec", new Class[] { String[].class }); - - assertEquals("Method.toString() must match expectations", - "public final native void java.lang.Object.notify()", - m1.toString()); - - assertEquals("Method.toString() must match expectations", - "public java.lang.String java.lang.Object.toString()", - m2.toString()); - - assertEquals("Method.toString() must match expectations", - "public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException", - m3.toString()); - - assertEquals("Method.toString() must match expectations", - "public boolean java.lang.Object.equals(java.lang.Object)", - m4.toString()); - - assertEquals("Method.toString() must match expectations", - "public static java.lang.String java.lang.String.valueOf(char[])", - m5.toString()); - - assertEquals("Method.toString() must match expectations", - "public java.lang.Process java.lang.Runtime.exec(java.lang.String[]) throws java.io.IOException", - m6.toString()); - - } catch (Exception ex) { - throw new RuntimeException(ex); - } - - } - - // Regression test for #1062200: Enum fails to deserialize. Actual problem - // was that Class.isEnum() erroneously returned true for indirect - // descendants of Enum. - enum TrafficLights { - RED, - YELLOW {}, - GREEN { - @SuppressWarnings("unused") - int i; - @SuppressWarnings("unused") - void foobar() {} - }; - } - - @SmallTest - public void testClassIsEnum() { - Class<?> trafficClass = TrafficLights.class; - - Class<?> redClass = TrafficLights.RED.getClass(); - Class<?> yellowClass = TrafficLights.YELLOW.getClass(); - Class<?> greenClass = TrafficLights.GREEN.getClass(); - - Assert.assertSame("Classes must be equal", trafficClass, redClass); - Assert.assertNotSame("Classes must be different", trafficClass, yellowClass); - Assert.assertNotSame("Classes must be different", trafficClass, greenClass); - Assert.assertNotSame("Classes must be different", yellowClass, greenClass); - - Assert.assertTrue("Must be an enum", trafficClass.isEnum()); - Assert.assertTrue("Must be an enum", redClass.isEnum()); - Assert.assertFalse("Must not be an enum", yellowClass.isEnum()); - Assert.assertFalse("Must not be an enum", greenClass.isEnum()); - - Assert.assertNotNull("Must have enum constants", trafficClass.getEnumConstants()); - Assert.assertNull("Must not have enum constants", yellowClass.getEnumConstants()); - Assert.assertNull("Must not have enum constants", greenClass.getEnumConstants()); - } - - // Regression test for #1046174: JarEntry.getCertificates() is really slow. - public void checkJarCertificates(File file) { - try { - JarFile jarFile = new JarFile(file); - JarEntry je = jarFile.getJarEntry("AndroidManifest.xml"); - byte[] readBuffer = new byte[1024]; - - long t0 = System.currentTimeMillis(); - - // We must read the stream for the JarEntry to retrieve - // its certificates. - InputStream is = jarFile.getInputStream(je); - while (is.read(readBuffer, 0, readBuffer.length) != -1) { - // not using - } - is.close(); - Certificate[] certs = je != null ? je.getCertificates() : null; - - long t1 = System.currentTimeMillis(); - android.util.Log.d("TestHarness", "loadCertificates() took " + (t1 - t0) + " ms"); - if (certs == null) { - android.util.Log.d("TestHarness", "We have no certificates"); - } else { - android.util.Log.d("TestHarness", "We have " + certs.length + " certificates"); - } - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - @LargeTest - public void testJarCertificates() { - File[] files = new File("/system/app").listFiles(); - for (int i = 0; i < files.length; i++) { - checkJarCertificates(files[i]); - } - } - - // Regression test for #1120750: Reflection for static long fields is broken - private static final long MY_LONG = 5073258162644648461L; - - @SmallTest - public void testLongFieldReflection() { - try { - Field field = getClass().getDeclaredField("MY_LONG"); - assertEquals(5073258162644648461L, field.getLong(null)); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - // Regression test for Harmony LinkedHashMap bug. Copied from core, just - // to make sure it doesn't get lost. - @SmallTest - public void testLinkedHashMap() { - // we want to test the LinkedHashMap in access ordering mode. - LinkedHashMap map = new LinkedHashMap<String, String>(10, 0.75f, true); - - map.put("key1", "value1"); - map.put("key2", "value2"); - map.put("key3", "value3"); - - Iterator iterator = map.keySet().iterator(); - String id = (String) iterator.next(); - map.get(id); - try { - iterator.next(); - // A LinkedHashMap is supposed to throw this Exception when a - // iterator.next() Operation takes place after a get - // Operation. This is because the get Operation is considered - // a structural modification if the LinkedHashMap is in - // access order mode. - fail("expected ConcurrentModificationException was not thrown."); - } catch(ConcurrentModificationException e) { - // expected - } - - LinkedHashMap mapClone = (LinkedHashMap) map.clone(); - - iterator = map.keySet().iterator(); - id = (String) iterator.next(); - mapClone.get(id); - try { - iterator.next(); - } catch(ConcurrentModificationException e) { - fail("expected ConcurrentModificationException was not thrown."); - } - } - - // Regression test for #1212257: Boot-time package scan is slow. Not - // expected to fail. Please see log if you are interested in the results. - @LargeTest - public void testZipStressManifest() { - android.util.Log.d("MiscRegressionTest", "ZIP stress test started"); - - long time0 = System.currentTimeMillis(); - - try { - File[] files = new File("/system/app").listFiles(); - - byte[] buffer = new byte[512]; - - if (files != null) { - for (int i = 0; i < files.length; i++) { - android.util.Log.d("MiscRegressionTest", - "ZIP stress test processing " + files[i] + "..."); - - ZipFile zip = new ZipFile(files[i]); - - ZipEntry entry = zip.getEntry("AndroidManifest.xml"); - InputStream stream = zip.getInputStream(entry); - - int j = stream.read(buffer); - while (j != -1) { - j = stream.read(buffer); - } - - stream.close(); - } - } - } catch (Exception ex) { - throw new RuntimeException(ex); - } - - long time1 = System.currentTimeMillis(); - - android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " + - "time was " + (time1- time0) + "ms"); - } - - @LargeTest - public void testZipStressAllFiles() { - android.util.Log.d("MiscRegressionTest", "ZIP stress test started"); - - long time0 = System.currentTimeMillis(); - - try { - File[] files = new File("/system/app").listFiles(); - - byte[] buffer = new byte[512]; - - if (files != null) { - for (int i = 0; i < files.length; i++) { - android.util.Log.d("MiscRegressionTest", - "ZIP stress test processing " + files[i] + "..."); - - ZipFile zip = new ZipFile(files[i]); - - Enumeration<? extends ZipEntry> entries = zip.entries(); - while (entries.hasMoreElements()) { - InputStream stream = zip.getInputStream(entries.nextElement()); - - int j = stream.read(buffer); - while (j != -1) { - j = stream.read(buffer); - } - - stream.close(); - } - } - } - } catch (Exception ex) { - throw new RuntimeException(ex); - } - - long time1 = System.currentTimeMillis(); - - android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " + - "time was " + (time1- time0) + "ms"); - } - - @SmallTest - public void testOsEncodingProperty() { - long time0 = System.currentTimeMillis(); - String[] files = new File("/system/app").list(); - long time1 = System.currentTimeMillis(); - android.util.Log.d("MiscRegressionTest", "File.list() test finished, " + - "time was " + (time1- time0) + "ms"); - } - - // ------------------------------------------------------------------------- - // Regression test for #1185084: Native memory allocated by - // java.util.zip.Deflater in system_server. The fix reduced some internal - // ZLIB buffers in size, so this test is trying to execute a lot of - // deflating to ensure that things are still working properly. - private void assertEquals(byte[] a, byte[] b) { - assertEquals("Arrays must have same length", a.length, b.length); - - for (int i = 0; i < a.length; i++) { - assertEquals("Array elements #" + i + " must be equal", a[i], b[i]); - } - } - - @LargeTest - public void testZipDeflateInflateStress() { - - final int DATA_SIZE = 16384; - - Random random = new Random(42); // Seed makes test reproducible - - try { - // Outer loop selects "mode" of test. - for (int j = 1; j <=2 ; j++) { - - byte[] input = new byte[DATA_SIZE]; - - if (j == 1) { - // Totally random content - random.nextBytes(input); - } else { - // Random contents with longer repetitions - int pos = 0; - while (pos < input.length) { - byte what = (byte)random.nextInt(256); - int howMany = random.nextInt(32); - if (pos + howMany >= input.length) { - howMany = input.length - pos; - } - Arrays.fill(input, pos, pos + howMany, what); - pos += howMany; - } - } - - // Inner loop tries all 9 compression levels. - for (int i = 1; i <= 9; i++) { - android.util.Log.d("MiscRegressionTest", "ZipDeflateInflateStress test (" + j + "," + i + ")..."); - - byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure... - - Deflater deflater = new Deflater(i); - deflater.setInput(input); - deflater.finish(); - - deflater.deflate(zipped); - - byte[] output = new byte[DATA_SIZE]; - - Inflater inflater = new Inflater(); - inflater.setInput(zipped); - inflater.finished(); - - inflater.inflate(output); - - assertEquals(input, output); - } - } - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - // ------------------------------------------------------------------------- - // Regression test for #1252043: Thread.getStackTrace() is broken - class MyThread extends Thread { - public MyThread(String name) { - super(name); - } - - @Override - public void run() { - doSomething(); - } - - public void doSomething() { - for (int i = 0; i < 20;) { - try { - Thread.sleep(100); - } catch (InterruptedException ex) { - } - } - } - } - - class MyOtherThread extends Thread { - public int visibleTraces; - - public MyOtherThread(ThreadGroup group, String name) { - super(group, name); - } - - @Override - public void run() { - visibleTraces = Thread.getAllStackTraces().size(); - } - } - - @LargeTest - public void testThreadGetStackTrace() { - MyThread t1 = new MyThread("t1"); - t1.start(); - - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - } - - StackTraceElement[] traces = t1.getStackTrace(); - StackTraceElement trace = traces[traces.length - 2]; - - // Expect to find MyThread.doSomething in the trace - assertTrue("Must find MyThread.doSomething in trace", - trace.getClassName().endsWith("$MyThread") && - trace.getMethodName().equals("doSomething")); - - ThreadGroup g1 = new ThreadGroup("1"); - MyOtherThread t2 = new MyOtherThread(g1, "t2"); - t2.start(); - try { - t2.join(); - } catch (InterruptedException ex) { - } - - // Expect to see the traces of all threads (not just t2) - assertTrue("Must have traces for all threads", t2.visibleTraces > 1); - } } diff --git a/tests/CoreTests/android/core/RegexTest.java b/tests/CoreTests/android/core/RegexTest.java deleted file mode 100644 index 743afc1..0000000 --- a/tests/CoreTests/android/core/RegexTest.java +++ /dev/null @@ -1,287 +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 android.test.suitebuilder.annotation.SmallTest; - -import junit.framework.TestCase; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Tests basic functionality of Pattern and Matcher classes. - */ -public class RegexTest extends TestCase { - - @SmallTest - public void testMatches() throws Exception { - /* Tests class Matcher */ - - Pattern p = Pattern.compile("bcd"); - Matcher m = p.matcher("bcd"); - assertTrue("Should match.", m.matches()); - - /* Pattern in the middle */ - p = Pattern.compile("bcd"); - m = p.matcher("abcdefg"); - assertFalse("Should not match.", m.matches()); - - /* Pattern at the head */ - m = p.matcher("bcdefg"); - assertFalse("Should not match.", m.matches()); - - /* Pattern at the tail */ - m = p.matcher("abcd"); - assertFalse("Should not match.", m.matches()); - - /* Make sure matches() doesn't change after calls to find() */ - p = Pattern.compile(".*"); - m = p.matcher("abc"); - assertTrue(m.matches()); - assertTrue(m.find()); - assertTrue(m.matches()); - - p = Pattern.compile("."); - m = p.matcher("abc"); - assertFalse(m.matches()); - assertTrue(m.find()); - assertFalse(m.matches()); - - /* Make sure matches() agrees after a reset() */ - m.reset("z"); - assertTrue(m.matches()); - - m.reset("xyz"); - assertFalse(m.matches()); - - /* Tests class Pattern */ - - assertFalse("Erroneously matched partial string. " + - "See http://b/issue?id=754601", Pattern.matches("er", "xer")); - assertFalse("Erroneously matched partial string. " + - "See http://b/issue?id=754601", Pattern.matches("xe", "xer")); - assertTrue("Generic regex should match.", - Pattern.matches(".*", "bcd")); - assertTrue("Grouped regex should match.", - Pattern.matches("(b(c(d)))", "bcd")); - assertTrue("Grouped regex should match.", - Pattern.matches("(b)(c)(d)", "bcd")); - } - - @SmallTest - public void testGroupCount() throws Exception { - Pattern p = Pattern.compile( - "\\b(?:\\+?1)?" - + "(?:[ -\\.])?" - + "\\(?(\\d{3})?\\)?" - + "(?:[ -\\.\\/])?" - + "(\\d{3})" - + "(?:[ -\\.])?" - + "(\\d{4})\\b" - ); - - Matcher m = p.matcher("1 (919) 555-1212"); - - assertEquals("groupCount is incorrect, see http://b/issue?id=759412", - 3, m.groupCount()); - } - - @SmallTest - public void testGroups() throws Exception { - Pattern p = Pattern.compile("(b)([c|d])(z*)"); - Matcher m = p.matcher("abcdefg"); - - /* Must call find() first, otherwise group*() are undefined. */ - assertTrue(m.find()); - - assertEquals(3, m.groupCount()); - - assertEquals("bc", m.group(0)); - assertEquals("b", m.group(1)); - assertEquals("c", m.group(2)); - assertEquals("", m.group(3)); - } - - @SmallTest - public void testFind() throws Exception { - Pattern p = Pattern.compile("."); - Matcher m = p.matcher("abc"); - - assertTrue(m.find()); - assertEquals("a", m.group(0)); - - assertTrue(m.find()); - assertEquals("b", m.group(0)); - - assertTrue(m.find()); - assertEquals("c", m.group(0)); - - assertFalse(m.find()); - } - - @SmallTest - public void testReplaceAll() throws Exception { - // Begins with non-matching text, ends with matching text - Pattern p = Pattern.compile("a*b"); - Matcher m = p.matcher("fooaabfooaabfooabfoob"); - - String r = m.replaceAll("-"); - assertEquals("foo-foo-foo-foo-", r); - - // Begins with matching text, ends with non-matching text - p = Pattern.compile("a*b"); - m = p.matcher("aabfooaabfooabfoobfoo"); - - r = m.replaceAll("-"); - assertEquals("-foo-foo-foo-foo", r); - } - - @SmallTest - public void testReplaceFirst() throws Exception { - // Begins with non-matching text, ends with matching text - Pattern p = Pattern.compile("a*b"); - Matcher m = p.matcher("fooaabfooaabfooabfoob"); - - String r = m.replaceFirst("-"); - assertEquals("foo-fooaabfooabfoob", r); - - // Begins with matching text, ends with non-matching text - p = Pattern.compile("a*b"); - m = p.matcher("aabfooaabfooabfoobfoo"); - - r = m.replaceFirst("-"); - assertEquals("-fooaabfooabfoobfoo", r); - } - - @SmallTest - public void testSplit() throws Exception { - Pattern p = Pattern.compile(":"); - String[] strings; - - strings = p.split("boo:and:foo"); - assertEquals(3, strings.length); - assertEquals("boo", strings[0]); - assertEquals("and", strings[1]); - assertEquals("foo", strings[2]); - - strings = p.split("boo:and:foo", 2); - assertEquals(2, strings.length); - assertEquals("boo", strings[0]); - assertEquals("and:foo", strings[1]); - - strings = p.split("boo:and:foo", 5); - assertEquals(3, strings.length); - assertEquals("boo", strings[0]); - assertEquals("and", strings[1]); - assertEquals("foo", strings[2]); - - strings = p.split("boo:and:foo", -2); - assertEquals(3, strings.length); - assertEquals("boo", strings[0]); - assertEquals("and", strings[1]); - assertEquals("foo", strings[2]); - - p = Pattern.compile("o"); - - strings = p.split("boo:and:foo"); - assertEquals(3, strings.length); - assertEquals("b", strings[0]); - assertEquals("", strings[1]); - assertEquals(":and:f", strings[2]); - - strings = p.split("boo:and:foo", 5); - assertEquals(5, strings.length); - assertEquals("b", strings[0]); - assertEquals("", strings[1]); - assertEquals(":and:f", strings[2]); - assertEquals("", strings[3]); - assertEquals("", strings[4]); - - strings = p.split("boo:and:foo", -2); - assertEquals(5, strings.length); - assertEquals("b", strings[0]); - assertEquals("", strings[1]); - assertEquals(":and:f", strings[2]); - assertEquals("", strings[3]); - assertEquals("", strings[4]); - - strings = p.split("boo:and:foo", 0); - assertEquals(3, strings.length); - assertEquals("b", strings[0]); - assertEquals("", strings[1]); - assertEquals(":and:f", strings[2]); - } - - // ------------------------------------------------------------------- - // Regression test for #1172774: Bug in Regex.java - // Regression test for #1216887: Regular expression match is very slow - public static final Pattern TOP_LEVEL_DOMAIN_PATTERN = Pattern.compile( - "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])" - + "|(biz|b[abdefghijmnorstvwyz])" - + "|(cat|com|coop|c[acdfghiklmnoruvxyz])" - + "|d[ejkmoz]" - + "|(edu|e[cegrstu])" - + "|f[ijkmor]" - + "|(gov|g[abdefghilmnpqrstuwy])" - + "|h[kmnrtu]" - + "|(info|int|i[delmnoqrst])" - + "|(jobs|j[emop])" - + "|k[eghimnrwyz]" - + "|l[abcikrstuvy]" - + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])" - + "|(name|net|n[acefgilopruz])" - + "|(org|om)" - + "|(pro|p[aefghklmnrstwy])" - + "|qa" - + "|r[eouw]" - + "|s[abcdeghijklmnortuvyz]" - + "|(tel|travel|t[cdfghjklmnoprtvwz])" - + "|u[agkmsyz]" - + "|v[aceginu]" - + "|w[fs]" - + "|y[etu]" - + "|z[amw])"); - - public static final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile( - "[\\+a-zA-Z0-9\\.\\_\\%\\-]+\\@" - + "((" - + "[a-zA-Z0-9]\\.|" - + "([a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9]\\.)+)" - + TOP_LEVEL_DOMAIN_PATTERN - + ")"); - - @SmallTest - public void testMonsterRegexCorrectness() { - assertTrue(EMAIL_ADDRESS_PATTERN.matcher("a+b@gmail.com").matches()); - } - - @SmallTest - public void testMonsterRegexPerformance() { - android.util.Log.e("RegexTest", "RegEx performance test started."); - long t0 = System.currentTimeMillis(); - Matcher m = EMAIL_ADDRESS_PATTERN.matcher("donot repeate@RC8jjjjjjjjjjjjjjj"); - assertFalse(m.find()); - long t1 = System.currentTimeMillis(); - android.util.Log.e("RegexTest", "RegEx performance test finished, " + - "took " + (t1 - t0) + " ms."); - } - - // - // ------------------------------------------------------------------- - -} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java index 5e2a9fd..b7d2c26 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java @@ -141,7 +141,7 @@ public class FsUtils { } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX) && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX) && !path.startsWith(HTTP_WML_TESTS_PREFIX)) { - url = "http://127.0.0.1:18000/" + path.substring(HTTP_TESTS_PREFIX.length()); + url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length()); } else { url = "file://" + path; } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java index 7a277d7..25dd04fd 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java @@ -26,7 +26,7 @@ import android.util.Log; public class ForwardService { - private ForwardServer fs18000, fs8080, fs8443; + private ForwardServer fs8000, fs8080, fs8443; private static ForwardService inst; @@ -40,7 +40,7 @@ public class ForwardService { private ForwardService() { int addr = getForwardHostAddr(); if (addr != -1) { - fs18000 = new ForwardServer(18000, addr, 8000); + fs8000 = new ForwardServer(8000, addr, 8000); fs8080 = new ForwardServer(8080, addr, 8080); fs8443 = new ForwardServer(8443, addr, 8443); } @@ -55,8 +55,8 @@ public class ForwardService { public void startForwardService() { try { - if (fs18000 != null) - fs18000.start(); + if (fs8000 != null) + fs8000.start(); if (fs8080 != null) fs8080.start(); if (fs8443 != null) @@ -68,9 +68,9 @@ public class ForwardService { } public void stopForwardService() { - if (fs18000 != null) { - fs18000.stop(); - fs18000 = null; + if (fs8000 != null) { + fs8000.stop(); + fs8000 = null; } if (fs8080 != null) { fs8080.stop(); diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 929b103..643cb8d 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -30,6 +30,17 @@ android:label="HwUi" android:hardwareAccelerated="true"> + <meta-data android:name="android.graphics.renderThread" android:value="true" /> + + <activity + android:name="PaintDrawFilterActivity" + android:label="_DrawFilter"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name="DisplayListLayersActivity" android:label="__DisplayListLayers"> @@ -38,6 +49,15 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <activity + android:name="MatrixActivity" + android:label="_Matrix"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> <activity android:name="TextFadeActivity" @@ -466,6 +486,16 @@ </activity> <activity + android:name="PosTextActivity" + android:label="_PosText" + 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> diff --git a/tests/HwAccelerationTest/res/values/strings.xml b/tests/HwAccelerationTest/res/values/strings.xml new file mode 100644 index 0000000..69e58aa --- /dev/null +++ b/tests/HwAccelerationTest/res/values/strings.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="complex_string">"ตำแหน่งของตัวชี้"</string> +</resources> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java new file mode 100644 index 0000000..1906b9d --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MatrixActivity.java @@ -0,0 +1,56 @@ +/* + * 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.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.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class MatrixActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(new MatrixView(this)); + } + + static class MatrixView extends View { + MatrixView(Context c) { + super(c); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRGB(255, 255, 255); + + Log.d("Matrix", "m1=" + canvas.getMatrix()); + + canvas.save(); + canvas.translate(10.0f, 10.0f); + Log.d("Matrix", "m2=" + canvas.getMatrix()); + canvas.translate(20.0f, 20.0f); + Log.d("Matrix", "m3=" + canvas.getMatrix()); + canvas.restore(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java new file mode 100644 index 0000000..8523272 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java @@ -0,0 +1,64 @@ +/* + * 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.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PaintFlagsDrawFilter; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class PaintDrawFilterActivity 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 PaintFlagsDrawFilter mDrawFilter; + + CustomTextView(Context c) { + super(c); + + mMediumPaint = new Paint(); + mMediumPaint.setAntiAlias(true); + mMediumPaint.setColor(0xff000000); + mMediumPaint.setFakeBoldText(true); + mMediumPaint.setTextSize(24.0f); + + mDrawFilter = new PaintFlagsDrawFilter( + Paint.FAKE_BOLD_TEXT_FLAG, Paint.UNDERLINE_TEXT_FLAG); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRGB(255, 255, 255); + + canvas.setDrawFilter(null); + canvas.drawText("Hello OpenGL renderer!", 100, 120, mMediumPaint); + canvas.setDrawFilter(mDrawFilter); + canvas.drawText("Hello OpenGL renderer!", 100, 220, mMediumPaint); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java new file mode 100644 index 0000000..1c868d2 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PosTextActivity.java @@ -0,0 +1,79 @@ +/* + * 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.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 PosTextActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(new CustomTextView(this)); + } + + static class CustomTextView extends View { + private final Paint mLargePaint; + private final String mText; + private final float[] mPos; + + CustomTextView(Context c) { + super(c); + + mText = c.getResources().getString(R.string.complex_string); + mPos = new float[mText.length() * 2]; + for (int i = 0; i < mPos.length; i += 2) { + mPos[i] = i * 30.0f; + mPos[i + 1] = i * 10.0f; + } + + 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.save(); + + canvas.drawLine(100.0f, 0.0f, 100.0f, getHeight(), mLargePaint); + + canvas.translate(100.0f, 100.0f); + mLargePaint.setTextAlign(Paint.Align.LEFT); + canvas.drawPosText(mText, mPos, mLargePaint); + + canvas.translate(0.0f, 50.0f); + mLargePaint.setTextAlign(Paint.Align.CENTER); + canvas.drawPosText(mText, mPos, mLargePaint); + + canvas.translate(0.0f, 50.0f); + mLargePaint.setTextAlign(Paint.Align.RIGHT); + canvas.drawPosText(mText, mPos, mLargePaint); + + canvas.restore(); + } + } +} diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java index f7abe8b..5446f66 100644 --- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java +++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2011-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,10 +22,10 @@ import android.graphics.BitmapFactory; import android.graphics.Bitmap; import android.renderscript.RenderScript; import android.renderscript.Allocation; +import android.util.Log; import android.widget.ImageView; public class ComputePerf extends Activity { - private LaunchTest mLT; private Mandelbrot mMandel; private RenderScript mRS; @@ -35,14 +35,28 @@ public class ComputePerf extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.main); + final int numTries = 100; + + long timesXLW = 0; + long timesXYW = 0; + mRS = RenderScript.create(this); mLT = new LaunchTest(mRS, getResources()); - mLT.run(); - mLT.run(); + mLT.XLW(); + mLT.XYW(); + for (int i = 0; i < numTries; i++) { + timesXLW += mLT.XLW(); + timesXYW += mLT.XYW(); + } + + timesXLW /= numTries; + timesXYW /= numTries; + + // XLW and XYW running times should match pretty closely + Log.v("ComputePerf", "xlw launch test " + timesXLW + "ms"); + Log.v("ComputePerf", "xyw launch test " + timesXYW + "ms"); mMandel = new Mandelbrot(mRS, getResources()); mMandel.run(); - } - } diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java index 0c29ce1..e2312ba 100644 --- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java +++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2011-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ package com.example.android.rs.computeperf; import android.content.res.Resources; import android.renderscript.*; -public class LaunchTest implements Runnable { +public class LaunchTest { private RenderScript mRS; private Allocation mAllocationX; private Allocation mAllocationXY; @@ -40,18 +40,19 @@ public class LaunchTest implements Runnable { mScript_xlw.bind_buf(mAllocationXY); } - public void run() { + public long XLW() { long t = java.lang.System.currentTimeMillis(); mScript_xlw.forEach_root(mAllocationX); mRS.finish(); t = java.lang.System.currentTimeMillis() - t; - android.util.Log.v("ComputePerf", "xlw launch test ms " + t); + return t; + } - t = java.lang.System.currentTimeMillis(); + public long XYW() { + long t = java.lang.System.currentTimeMillis(); mScript_xyw.forEach_root(mAllocationXY); mRS.finish(); t = java.lang.System.currentTimeMillis() - t; - android.util.Log.v("ComputePerf", "xyw launch test ms " + t); + return t; } - } diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs index 8cec409..de2a0a7 100644 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs +++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs @@ -48,6 +48,14 @@ static float gZoom; static float gLastX; static float gLastY; +static float3 toFloat3(float x, float y, float z) { + float3 f; + f.x = x; + f.y = y; + f.z = z; + return f; +} + void onActionDown(float x, float y) { gLastX = x; gLastY = y; @@ -104,8 +112,8 @@ void updateMeshInfo() { rsgMeshComputeBoundingBox(info->mMesh, &minX, &minY, &minZ, &maxX, &maxY, &maxZ); - info->bBoxMin = (minX, minY, minZ); - info->bBoxMax = (maxX, maxY, maxZ); + info->bBoxMin = toFloat3(minX, minY, minZ); + info->bBoxMax = toFloat3(maxX, maxY, maxZ); gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; } gLookAt = gLookAt / (float)size; diff --git a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml index 8234677..59a251d 100644 --- a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml +++ b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml @@ -18,8 +18,11 @@ --> <menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/benchmark_mode" - android:title="@string/benchmark_mode" /> + <item android:id="@+id/benchmark_all" + android:title="@string/benchmark_all" /> + <item android:id="@+id/benchmark_one" + android:title="@string/benchmark_one" /> <item android:id="@+id/debug_mode" android:title="@string/debug_mode" /> </menu> + diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl new file mode 100644 index 0000000..83dfc7f --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl @@ -0,0 +1,8 @@ +varying vec2 varTex0; + +void main() { + lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb; + gl_FragColor.xyz = col0; + gl_FragColor.w = 0.5; +} + diff --git a/tests/RenderScriptTests/PerfTest/res/values/strings.xml b/tests/RenderScriptTests/PerfTest/res/values/strings.xml index 627ac21..ce9819e 100644 --- a/tests/RenderScriptTests/PerfTest/res/values/strings.xml +++ b/tests/RenderScriptTests/PerfTest/res/values/strings.xml @@ -19,6 +19,8 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <skip /> - <string name="benchmark_mode">Benchmark Mode</string> + <string name="benchmark_all">Benchmark All</string> + <string name="benchmark_one">Benchmark One</string> <string name="debug_mode">Debug Mode</string> </resources> + diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java new file mode 100644 index 0000000..ba70c71 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2011 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.perftest; + +import android.os.Environment; +import android.content.res.Resources; +import android.renderscript.*; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + + +import android.util.Log; + + +public class FillTest implements RsBenchBaseTest{ + + private static final String TAG = "FillTest"; + private RenderScriptGL mRS; + private Resources mRes; + + // Custom shaders + private ProgramFragment mProgFragmentMultitex; + private ProgramFragment mProgFragmentSingletex; + private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + int mBenchmarkDimX; + int mBenchmarkDimY; + + private ScriptC_fill_test mFillScript; + ScriptField_TestScripts_s.Item[] mTests; + + private final String[] mNames = { + "Fill screen 10x singletexture", + "Fill screen 10x 3tex multitexture", + "Fill screen 10x blended singletexture", + "Fill screen 10x blended 3tex multitexture" + }; + + public FillTest() { + mOptionsARGB.inScaled = false; + mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; + mBenchmarkDimX = 1280; + mBenchmarkDimY = 720; + } + + void addTest(int index, int testId, int blend, int quadCount) { + mTests[index] = new ScriptField_TestScripts_s.Item(); + mTests[index].testScript = mFillScript; + mTests[index].testName = Allocation.createFromString(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + + ScriptField_FillTestData_s.Item dataItem = new ScriptField_FillTestData_s.Item(); + dataItem.testId = testId; + dataItem.blend = blend; + dataItem.quadCount = quadCount; + ScriptField_FillTestData_s testData = new ScriptField_FillTestData_s(mRS, 1); + testData.set(dataItem, 0, true); + mTests[index].testData = testData.getAllocation(); + } + + public boolean init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initCustomShaders(); + initFillScript(); + mTests = new ScriptField_TestScripts_s.Item[mNames.length]; + + int index = 0; + + addTest(index++, 1 /*testId*/, 0 /*blend*/, 10 /*quadCount*/); + addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/); + addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/); + addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/); + + return true; + } + + public ScriptField_TestScripts_s.Item[] getTests() { + return mTests; + } + + public String[] getTestNames() { + return mNames; + } + + private void initCustomShaders() { + ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); + pfbCustom.setShader(mRes, R.raw.multitexf); + for (int texCount = 0; texCount < 3; texCount ++) { + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + } + mProgFragmentMultitex = pfbCustom.create(); + + pfbCustom = new ProgramFragment.Builder(mRS); + pfbCustom.setShader(mRes, R.raw.singletexf); + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + mProgFragmentSingletex = pfbCustom.create(); + } + + private Allocation loadTextureARGB(int id) { + Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); + return Allocation.createFromBitmap(mRS, b, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + private Allocation loadTextureRGB(int id) { + return Allocation.createFromBitmapResource(mRS, mRes, id, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + void initFillScript() { + mFillScript = new ScriptC_fill_test(mRS, mRes, R.raw.fill_test); + + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); + ProgramVertexFixedFunction progVertex = pvb.create(); + ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA); + Matrix4f proj = new Matrix4f(); + proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY); + PVA.setProjection(proj); + mFillScript.set_gProgVertex(progVertex); + + mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex); + mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex); + mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS)); + mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS)); + + mFillScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); + mFillScript.set_gLinearWrap(Sampler.WRAP_LINEAR(mRS)); + mFillScript.set_gTexTorus(loadTextureRGB(R.drawable.torusmap)); + mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); + mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf)); + mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker)); + } +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java new file mode 100644 index 0000000..cdb4435 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 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.perftest; + +import android.os.Environment; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.renderscript.*; +import android.renderscript.Element.DataKind; +import android.renderscript.Element.DataType; +import android.renderscript.Allocation.MipmapControl; +import android.renderscript.Program.TextureType; +import android.renderscript.RenderScript.RSMessageHandler; +import android.renderscript.Mesh.Primitive; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramVertexFixedFunction; + +import android.util.Log; + + +public class MeshTest implements RsBenchBaseTest{ + + private static final String TAG = "MeshTest"; + private RenderScriptGL mRS; + private Resources mRes; + + int mBenchmarkDimX; + int mBenchmarkDimY; + + private Mesh m10by10Mesh; + private Mesh m100by100Mesh; + private Mesh mWbyHMesh; + + private ScriptC_mesh_test mGeoScript; + + private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + + ScriptField_TestScripts_s.Item[] mTests; + + private final String[] mNames = { + "Full screen mesh 10 by 10", + "Full screen mesh 100 by 100", + "Full screen mesh W / 4 by H / 4" + }; + + public MeshTest() { + mBenchmarkDimX = 1280; + mBenchmarkDimY = 720; + } + + void addTest(int index, int meshNum) { + mTests[index] = new ScriptField_TestScripts_s.Item(); + mTests[index].testScript = mGeoScript; + mTests[index].testName = Allocation.createFromString(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + + ScriptField_MeshTestData_s.Item dataItem = new ScriptField_MeshTestData_s.Item(); + dataItem.meshNum = meshNum; + ScriptField_MeshTestData_s testData = new ScriptField_MeshTestData_s(mRS, 1); + testData.set(dataItem, 0, true); + mTests[index].testData = testData.getAllocation(); + } + + public boolean init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initGeoScript(); + mTests = new ScriptField_TestScripts_s.Item[mNames.length]; + + int index = 0; + addTest(index++, 0 /*meshNum*/); + addTest(index++, 1 /*meshNum*/); + addTest(index++, 2 /*meshNum*/); + + return true; + } + + public ScriptField_TestScripts_s.Item[] getTests() { + return mTests; + } + + public String[] getTestNames() { + return mNames; + } + + private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { + + Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, + 2, Mesh.TriangleMeshBuilder.TEXTURE_0); + + for (int y = 0; y <= hResolution; y++) { + final float normalizedY = (float)y / hResolution; + final float yOffset = (normalizedY - 0.5f) * height; + for (int x = 0; x <= wResolution; x++) { + float normalizedX = (float)x / wResolution; + float xOffset = (normalizedX - 0.5f) * width; + tmb.setTexture((float)x % 2, (float)y % 2); + tmb.addVertex(xOffset, yOffset); + } + } + + for (int y = 0; y < hResolution; y++) { + final int curY = y * (wResolution + 1); + final int belowY = (y + 1) * (wResolution + 1); + for (int x = 0; x < wResolution; x++) { + int curV = curY + x; + int belowV = belowY + x; + tmb.addTriangle(curV, belowV, curV + 1); + tmb.addTriangle(belowV, belowV + 1, curV + 1); + } + } + + return tmb.create(true); + } + + private Allocation loadTextureRGB(int id) { + return Allocation.createFromBitmapResource(mRS, mRes, id, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + void initGeoScript() { + mGeoScript = new ScriptC_mesh_test(mRS, mRes, R.raw.mesh_test); + + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); + ProgramVertexFixedFunction progVertex = pvb.create(); + ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA); + Matrix4f proj = new Matrix4f(); + proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY); + PVA.setProjection(proj); + + mGeoScript.set_gProgVertex(progVertex); + ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); + mGeoScript.set_gProgFragmentTexture(texBuilder.create()); + mGeoScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS)); + + mGeoScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); + mGeoScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); + + m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10); + m100by100Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 100, 100); + mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4); + + mGeoScript.set_g10by10Mesh(m10by10Mesh); + mGeoScript.set_g100by100Mesh(m100by100Mesh); + mGeoScript.set_gWbyHMesh(mWbyHMesh); + } +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java index b336a4d..0dceafe 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java @@ -93,22 +93,41 @@ public class RsBench extends Activity { public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { - case R.id.benchmark_mode: - mView.setBenchmarkMode(); + case R.id.benchmark_all: + mView.setBenchmarkMode(-1); + mView.suspendRendering(false); return true; - case R.id.debug_mode: + case R.id.benchmark_one: + mView.suspendRendering(true); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a Test"); builder.setItems(mView.getTestNames(), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { Toast.makeText(getApplicationContext(), + "Starting to benchmark: " + mView.getTestNames()[item], + Toast.LENGTH_SHORT).show(); + mView.setBenchmarkMode(item); + mView.suspendRendering(false); + } + }); + builder.show(); + return true; + case R.id.debug_mode: + mView.suspendRendering(true); + AlertDialog.Builder debugBuilder = new AlertDialog.Builder(this); + debugBuilder.setTitle("Pick a Test"); + debugBuilder.setItems(mView.getTestNames(), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int item) { + Toast.makeText(getApplicationContext(), "Switching to: " + mView.getTestNames()[item], Toast.LENGTH_SHORT).show(); mView.setDebugMode(item); + mView.suspendRendering(false); } }); - builder.show(); + debugBuilder.show(); return true; default: return super.onOptionsItemSelected(item); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java new file mode 100644 index 0000000..a9e1777 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 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.perftest; +import android.renderscript.*; +import android.content.res.Resources; + +interface RsBenchBaseTest { + boolean init(RenderScriptGL rs, Resources res); + + ScriptField_TestScripts_s.Item[] getTests(); + String[] getTestNames(); +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java index c375be5..4ac7dd5 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2010-2011 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. @@ -26,16 +26,11 @@ import java.io.OutputStream; import android.os.Environment; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.renderscript.*; import android.renderscript.Element.DataKind; import android.renderscript.Element.DataType; import android.renderscript.Allocation.MipmapControl; import android.renderscript.Program.TextureType; -import android.renderscript.ProgramStore.DepthFunc; -import android.renderscript.ProgramStore.BlendSrcFunc; -import android.renderscript.ProgramStore.BlendDstFunc; import android.renderscript.RenderScript.RSMessageHandler; import android.renderscript.Sampler.Value; import android.renderscript.Mesh.Primitive; @@ -48,10 +43,6 @@ import android.util.Log; public class RsBenchRS { private static final String TAG = "RsBenchRS"; - private static final String SAMPLE_TEXT = "Bench Test"; - private static final String LIST_TEXT = - "This is a sample list of text to show in the list view"; - private static int PARTICLES_COUNT = 12000; int mWidth; int mHeight; int mLoops; @@ -68,10 +59,7 @@ public class RsBenchRS { mRes = res; mWidth = width; mHeight = height; - mOptionsARGB.inScaled = false; - mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; mMode = 0; - mMaxModes = 0; mLoops = loops; mCurrentLoop = 0; mBenchmarkDimX = 1280; @@ -84,10 +72,8 @@ public class RsBenchRS { private Resources mRes; private RenderScriptGL mRS; - private ProgramStore mProgStoreBlendNoneDepth; private ProgramStore mProgStoreBlendNone; private ProgramStore mProgStoreBlendAlpha; - private ProgramStore mProgStoreBlendAdd; private ProgramFragment mProgFragmentTexture; private ProgramFragment mProgFragmentColor; @@ -96,58 +82,69 @@ public class RsBenchRS { private ProgramVertexFixedFunction.Constants mPVA; private ProgramVertexFixedFunction.Constants mPvProjectionAlloc; - // Custom shaders - private ProgramVertex mProgVertexCustom; - private ProgramFragment mProgFragmentCustom; - private ProgramFragment mProgFragmentMultitex; - private ProgramVertex mProgVertexPixelLight; - private ProgramVertex mProgVertexPixelLightMove; - private ProgramFragment mProgFragmentPixelLight; - private ScriptField_VertexShaderConstants_s mVSConst; - private ScriptField_FragentShaderConstants_s mFSConst; - private ScriptField_VertexShaderConstants3_s mVSConstPixel; - private ScriptField_FragentShaderConstants3_s mFSConstPixel; - - - private Allocation mTexTorus; - private Allocation mTexOpaque; - private Allocation mTexTransparent; - private Allocation mTexChecker; - private Allocation mTexGlobe; - - private Mesh m10by10Mesh; - private Mesh m100by100Mesh; - private Mesh mWbyHMesh; - private Mesh mTorus; - private Mesh mSingleMesh; - private Mesh mParticlesMesh; - - Font mFontSans; - Font mFontSerif; - private Allocation mTextAlloc; - - private ScriptField_ListAllocs_s mTextureAllocs; - private ScriptField_ListAllocs_s mSampleTextAllocs; - private ScriptField_ListAllocs_s mSampleListViewAllocs; - private ScriptField_VpConsts mPvStarAlloc; - - private ScriptC_rsbench mScript; - private ScriptC_text_test mTextScript; - private ScriptC_torus_test mTorusScript; - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + ScriptField_TestScripts_s.Item[] mIndividualTests; int mMode; - int mMaxModes; String[] mTestNames; float[] mLocalTestResults; - public void onActionDown(int x, int y) { - mMode ++; - mMode = mMode % mMaxModes; - mScript.set_gDisplayMode(mMode); + static Allocation createZeroTerminatedAlloc(RenderScript rs, + String str, + int usage) { + byte[] allocArray = null; + try { + allocArray = str.getBytes("UTF-8"); + byte[] allocArrayZero = new byte[allocArray.length + 1]; + System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length); + allocArrayZero[allocArrayZero.length - 1] = '\0'; + Allocation alloc = Allocation.createSized(rs, Element.U8(rs), + allocArrayZero.length, usage); + alloc.copyFrom(allocArrayZero); + return alloc; + } + catch (Exception e) { + throw new RSRuntimeException("Could not convert string to utf-8."); + } + + } + + void appendTests(RsBenchBaseTest testSet) { + ScriptField_TestScripts_s.Item[] newTests = testSet.getTests(); + if (mIndividualTests != null) { + ScriptField_TestScripts_s.Item[] combined; + combined = new ScriptField_TestScripts_s.Item[newTests.length + mIndividualTests.length]; + System.arraycopy(mIndividualTests, 0, combined, 0, mIndividualTests.length); + System.arraycopy(newTests, 0, combined, mIndividualTests.length, newTests.length); + mIndividualTests = combined; + } else { + mIndividualTests = newTests; + } + + String[] newNames = testSet.getTestNames(); + if (mTestNames != null) { + String[] combinedNames; + combinedNames = new String[newNames.length + mTestNames.length]; + System.arraycopy(mTestNames, 0, combinedNames, 0, mTestNames.length); + System.arraycopy(newNames, 0, combinedNames, mTestNames.length, newNames.length); + mTestNames = combinedNames; + } else { + mTestNames = newNames; + } + } + + void createTestAllocation() { + int numTests = mIndividualTests.length; + mLocalTestResults = new float[numTests]; + ScriptField_TestScripts_s allTests; + allTests = new ScriptField_TestScripts_s(mRS, numTests); + for (int i = 0; i < numTests; i ++) { + allTests.set(mIndividualTests[i], i, false); + } + allTests.copyAll(); + mScript.bind_gTestScripts(allTests); } private void saveTestResults() { @@ -225,98 +222,6 @@ public class RsBenchRS { } } - ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { - ProgramStore.Builder builder = new ProgramStore.Builder(rs); - builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); - builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); - builder.setDitherEnabled(false); - builder.setDepthMaskEnabled(false); - return builder.create(); - } - - private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { - - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, - 2, Mesh.TriangleMeshBuilder.TEXTURE_0); - - for (int y = 0; y <= hResolution; y++) { - final float normalizedY = (float)y / hResolution; - final float yOffset = (normalizedY - 0.5f) * height; - for (int x = 0; x <= wResolution; x++) { - float normalizedX = (float)x / wResolution; - float xOffset = (normalizedX - 0.5f) * width; - tmb.setTexture((float)x % 2, (float)y % 2); - tmb.addVertex(xOffset, yOffset); - } - } - - for (int y = 0; y < hResolution; y++) { - final int curY = y * (wResolution + 1); - final int belowY = (y + 1) * (wResolution + 1); - for (int x = 0; x < wResolution; x++) { - int curV = curY + x; - int belowV = belowY + x; - tmb.addTriangle(curV, belowV, curV + 1); - tmb.addTriangle(belowV, belowV + 1, curV + 1); - } - } - - return tmb.create(true); - } - - /** - * Create a mesh with a single quad for the given width and height. - */ - private Mesh getSingleMesh(float width, float height) { - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, - 2, Mesh.TriangleMeshBuilder.TEXTURE_0); - float xOffset = width/2; - float yOffset = height/2; - tmb.setTexture(0, 0); - tmb.addVertex(-1.0f * xOffset, -1.0f * yOffset); - tmb.setTexture(1, 0); - tmb.addVertex(xOffset, -1.0f * yOffset); - tmb.setTexture(1, 1); - tmb.addVertex(xOffset, yOffset); - tmb.setTexture(0, 1); - tmb.addVertex(-1.0f * xOffset, yOffset); - tmb.addTriangle(0, 3, 1); - tmb.addTriangle(1, 3, 2); - return tmb.create(true); - } - - private void initProgramStore() { - // Use stock the stock program store object - mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS); - mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS); - - // Create a custom program store - ProgramStore.Builder builder = new ProgramStore.Builder(mRS); - builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); - builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, - ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); - builder.setDitherEnabled(false); - builder.setDepthMaskEnabled(false); - mProgStoreBlendAlpha = builder.create(); - - mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS); - - mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); - - mScript.set_gProgStoreBlendNone(mProgStoreBlendNone); - mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha); - mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd); - - // For GALAXY - builder = new ProgramStore.Builder(mRS); - builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); - mRS.bindProgramStore(builder.create()); - - builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE); - mScript.set_gPSLights(builder.create()); - - } - private void initProgramFragment() { ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); @@ -329,64 +234,9 @@ public class RsBenchRS { colBuilder.setVaryingColor(false); mProgFragmentColor = colBuilder.create(); - mScript.set_gProgFragmentColor(mProgFragmentColor); - mScript.set_gProgFragmentTexture(mProgFragmentTexture); - - - - // For Galaxy live wallpaper drawing - ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS); - builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGB, 0); - ProgramFragment pfb = builder.create(); - pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0); - mScript.set_gPFBackground(pfb); - - builder = new ProgramFragmentFixedFunction.Builder(mRS); - builder.setPointSpriteTexCoordinateReplacement(true); - builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - builder.setVaryingColor(true); - ProgramFragment pfs = builder.create(); - pfs.bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0); - mScript.set_gPFStars(pfs); - } - private Matrix4f getProjectionNormalized(int w, int h) { - // range -1,1 in the narrow axis at z = 0. - Matrix4f m1 = new Matrix4f(); - Matrix4f m2 = new Matrix4f(); - - if(w > h) { - float aspect = ((float)w) / h; - m1.loadFrustum(-aspect,aspect, -1,1, 1,100); - } else { - float aspect = ((float)h) / w; - m1.loadFrustum(-1,1, -aspect,aspect, 1,100); - } - - m2.loadRotate(180, 0, 1, 0); - m1.loadMultiply(m1, m2); - - m2.loadScale(-2, 2, 1); - m1.loadMultiply(m1, m2); - - m2.loadTranslate(0, 0, 2); - m1.loadMultiply(m1, m2); - return m1; - } - - private void updateProjectionMatrices() { - Matrix4f projNorm = getProjectionNormalized(mBenchmarkDimX, mBenchmarkDimY); - ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item(); - i.Proj = projNorm; - i.MVP = projNorm; - mPvStarAlloc.set(i, 0, true); - mPvProjectionAlloc.setProjection(projNorm); - } - private void initProgramVertex() { ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); mProgVertex = pvb.create(); @@ -398,201 +248,6 @@ public class RsBenchRS { mPVA.setProjection(proj); mScript.set_gProgVertex(mProgVertex); - - - // For galaxy live wallpaper - mPvStarAlloc = new ScriptField_VpConsts(mRS, 1); - mScript.bind_vpConstants(mPvStarAlloc); - mPvProjectionAlloc = new ProgramVertexFixedFunction.Constants(mRS); - updateProjectionMatrices(); - - pvb = new ProgramVertexFixedFunction.Builder(mRS); - ProgramVertex pvbp = pvb.create(); - ((ProgramVertexFixedFunction)pvbp).bindConstants(mPvProjectionAlloc); - mScript.set_gPVBkProj(pvbp); - - ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS); - String t = "varying vec4 varColor;\n" + - "varying vec2 varTex0;\n" + - "void main() {\n" + - " float dist = ATTRIB_position.y;\n" + - " float angle = ATTRIB_position.x;\n" + - " float x = dist * sin(angle);\n" + - " float y = dist * cos(angle) * 0.892;\n" + - " float p = dist * 5.5;\n" + - " float s = cos(p);\n" + - " float t = sin(p);\n" + - " vec4 pos;\n" + - " pos.x = t * x + s * y;\n" + - " pos.y = s * x - t * y;\n" + - " pos.z = ATTRIB_position.z;\n" + - " pos.w = 1.0;\n" + - " gl_Position = UNI_MVP * pos;\n" + - " gl_PointSize = ATTRIB_color.a * 10.0;\n" + - " varColor.rgb = ATTRIB_color.rgb;\n" + - " varColor.a = 1.0;\n" + - "}\n"; - sb.setShader(t); - sb.addInput(mParticlesMesh.getVertexAllocation(0).getType().getElement()); - sb.addConstant(mPvStarAlloc.getType()); - ProgramVertex pvs = sb.create(); - pvs.bindConstants(mPvStarAlloc.getAllocation(), 0); - mScript.set_gPVStars(pvs); - } - - private void initCustomShaders() { - mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1); - mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1); - - - mVSConstPixel = new ScriptField_VertexShaderConstants3_s(mRS, 1); - mFSConstPixel = new ScriptField_FragentShaderConstants3_s(mRS, 1); - - - // Initialize the shader builder - ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS); - // Specify the resource that contains the shader string - pvbCustom.setShader(mRes, R.raw.shaderv); - // Use a script field to specify the input layout - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - // Define the constant input layout - pvbCustom.addConstant(mVSConst.getAllocation().getType()); - mProgVertexCustom = pvbCustom.create(); - // Bind the source of constant data - mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); - - ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); - // Specify the resource that contains the shader string - pfbCustom.setShader(mRes, R.raw.shaderf); - // Tell the builder how many textures we have - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - // Define the constant input layout - pfbCustom.addConstant(mFSConst.getAllocation().getType()); - mProgFragmentCustom = pfbCustom.create(); - // Bind the source of constant data - mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); - - pvbCustom = new ProgramVertex.Builder(mRS); - pvbCustom.setShader(mRes, R.raw.shader2v); - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); - mProgVertexPixelLight = pvbCustom.create(); - mProgVertexPixelLight.bindConstants(mVSConstPixel.getAllocation(), 0); - - pvbCustom = new ProgramVertex.Builder(mRS); - pvbCustom.setShader(mRes, R.raw.shader2movev); - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); - mProgVertexPixelLightMove = pvbCustom.create(); - mProgVertexPixelLightMove.bindConstants(mVSConstPixel.getAllocation(), 0); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.shader2f); - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - pfbCustom.addConstant(mFSConstPixel.getAllocation().getType()); - mProgFragmentPixelLight = pfbCustom.create(); - mProgFragmentPixelLight.bindConstants(mFSConstPixel.getAllocation(), 0); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.multitexf); - for (int texCount = 0; texCount < 3; texCount ++) { - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - } - mProgFragmentMultitex = pfbCustom.create(); - - - mScript.set_gProgFragmentMultitex(mProgFragmentMultitex); - } - - private Allocation loadTextureRGB(int id) { - return Allocation.createFromBitmapResource(mRS, mRes, id, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private Allocation loadTextureARGB(int id) { - Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); - return Allocation.createFromBitmap(mRS, b, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private void loadImages() { - mTexTorus = loadTextureRGB(R.drawable.torusmap); - mTexOpaque = loadTextureRGB(R.drawable.data); - mTexTransparent = loadTextureARGB(R.drawable.leaf); - mTexChecker = loadTextureRGB(R.drawable.checker); - mTexGlobe = loadTextureRGB(R.drawable.globe); - - mScript.set_gTexTorus(mTexTorus); - mScript.set_gTexOpaque(mTexOpaque); - mScript.set_gTexTransparent(mTexTransparent); - mScript.set_gTexChecker(mTexChecker); - mScript.set_gTexGlobe(mTexGlobe); - - // For Galaxy live wallpaper - mScript.set_gTSpace(loadTextureRGB(R.drawable.space)); - mScript.set_gTLight1(loadTextureRGB(R.drawable.light1)); - mScript.set_gTFlares(loadTextureARGB(R.drawable.flares)); - } - - private void initFonts() { - // Sans font by family name - mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); - mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8); - // Create fonts by family and style - - mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT); - - mScript.set_gFontSans(mFontSans); - mScript.set_gFontSerif(mFontSerif); - } - - private void createParticlesMesh() { - ScriptField_Particle p = new ScriptField_Particle(mRS, PARTICLES_COUNT); - - final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS); - meshBuilder.addVertexAllocation(p.getAllocation()); - final int vertexSlot = meshBuilder.getCurrentVertexTypeIndex(); - meshBuilder.addIndexSetType(Primitive.POINT); - mParticlesMesh = meshBuilder.create(); - - mScript.set_gParticlesMesh(mParticlesMesh); - mScript.bind_Particles(p); - } - - private void initMesh() { - m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10); - mScript.set_g10by10Mesh(m10by10Mesh); - m100by100Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 100, 100); - mScript.set_g100by100Mesh(m100by100Mesh); - mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4); - mScript.set_gWbyHMesh(mWbyHMesh); - mSingleMesh = getSingleMesh(1, 1); // a unit size mesh - mScript.set_gSingleMesh(mSingleMesh); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); - FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { - Log.e("rs", "could not load model"); - } else { - mTorus = (Mesh)entry.getObject(); - } - - createParticlesMesh(); - } - - private void initSamplers() { - mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - mScript.set_gLinearWrap(Sampler.WRAP_LINEAR(mRS)); - mScript.set_gMipLinearWrap(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS)); - mScript.set_gNearestClamp(Sampler.CLAMP_NEAREST(mRS)); - } - - private void initProgramRaster() { - mScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS)); - mScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS)); - mScript.set_gCullNone(ProgramRaster.CULL_NONE(mRS)); } private int strlen(byte[] array) { @@ -603,78 +258,30 @@ public class RsBenchRS { return count; } - private void prepareTestData() { - mTestNames = new String[mMaxModes]; - mLocalTestResults = new float[mMaxModes]; - int scratchSize = 1024; - Allocation scratch = Allocation.createSized(mRS, Element.U8(mRS), scratchSize); - byte[] tmp = new byte[scratchSize]; - mScript.bind_gStringBuffer(scratch); - for (int i = 0; i < mMaxModes; i ++) { - mScript.invoke_getTestName(i); - scratch.copyTo(tmp); - int len = strlen(tmp); - mTestNames[i] = new String(tmp, 0, len); - } - } - public void setDebugMode(int num) { mScript.invoke_setDebugMode(num); } - public void setBenchmarkMode() { - mScript.invoke_setBenchmarkMode(); + public void setBenchmarkMode(int benchNum) { + mScript.invoke_setBenchmarkMode(benchNum); } - void initTextScript() { - mTextScript = new ScriptC_text_test(mRS, mRes, R.raw.text_test); - mTextScript.set_gFontSans(mFontSans); - mTextScript.set_gFontSerif(mFontSerif); - } - - void initTorusScript() { - mTorusScript = new ScriptC_torus_test(mRS, mRes, R.raw.torus_test); - mTorusScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS)); - mTorusScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS)); - mTorusScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - mTorusScript.set_gTorusMesh(mTorus); - mTorusScript.set_gTexTorus(mTexTorus); - mTorusScript.set_gProgVertexCustom(mProgVertexCustom); - mTorusScript.set_gProgFragmentCustom(mProgFragmentCustom); - mTorusScript.set_gProgVertexPixelLight(mProgVertexPixelLight); - mTorusScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove); - mTorusScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight); - mTorusScript.bind_gVSConstPixel(mVSConstPixel); - mTorusScript.bind_gFSConstPixel(mFSConstPixel); - mTorusScript.bind_gVSConstants(mVSConst); - mTorusScript.bind_gFSConstants(mFSConst); - mTorusScript.set_gProgVertex(mProgVertex); - mTorusScript.set_gProgFragmentTexture(mProgFragmentTexture); - mTorusScript.set_gProgFragmentColor(mProgFragmentColor); - mTorusScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); + public void pause(boolean pause) { + mScript.set_gPauseRendering(pause); } private void initRS() { mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench); - + mRS.bindRootScript(mScript); mRS.setMessageHandler(mRsMessage); - mMaxModes = mScript.get_gMaxModes(); mScript.set_gMaxLoops(mLoops); - prepareTestData(); - - initSamplers(); - initMesh(); initProgramVertex(); - initProgramStore(); initProgramFragment(); - initFonts(); - loadImages(); - initProgramRaster(); - initCustomShaders(); + mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8)); Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS)); b.setX(mBenchmarkDimX).setY(mBenchmarkDimY); @@ -692,41 +299,30 @@ public class RsBenchRS { b.create(), Allocation.USAGE_GRAPHICS_RENDER_TARGET); mScript.set_gRenderBufferDepth(offscreen); + mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - mTextureAllocs = new ScriptField_ListAllocs_s(mRS, 100); - for (int i = 0; i < 100; i++) { - ScriptField_ListAllocs_s.Item texElem = new ScriptField_ListAllocs_s.Item(); - texElem.item = loadTextureRGB(R.drawable.globe); - mTextureAllocs.set(texElem, i, false); + RsBenchBaseTest test = new TextTest(); + if (test.init(mRS, mRes)) { + appendTests(test); } - mTextureAllocs.copyAll(); - mScript.bind_gTexList100(mTextureAllocs); - - mSampleTextAllocs = new ScriptField_ListAllocs_s(mRS, 100); - for (int i = 0; i < 100; i++) { - ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item(); - textElem.item = Allocation.createFromString(mRS, SAMPLE_TEXT, Allocation.USAGE_SCRIPT); - mSampleTextAllocs.set(textElem, i, false); + test = new FillTest(); + if (test.init(mRS, mRes)) { + appendTests(test); } - mSampleTextAllocs.copyAll(); - mScript.bind_gSampleTextList100(mSampleTextAllocs); - - mSampleListViewAllocs = new ScriptField_ListAllocs_s(mRS, 1000); - for (int i = 0; i < 1000; i++) { - ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item(); - textElem.item = Allocation.createFromString(mRS, LIST_TEXT, Allocation.USAGE_SCRIPT); - mSampleListViewAllocs.set(textElem, i, false); + test = new MeshTest(); + if (test.init(mRS, mRes)) { + appendTests(test); } - mSampleListViewAllocs.copyAll(); - mScript.bind_gListViewText(mSampleListViewAllocs); - - initTextScript(); - initTorusScript(); - - mScript.set_gFontScript(mTextScript); - mScript.set_gTorusScript(mTorusScript); - mScript.set_gDummyAlloc(Allocation.createSized(mRS, Element.I32(mRS), 1)); + test = new TorusTest(); + if (test.init(mRS, mRes)) { + appendTests(test); + } + test = new UiTest(); + if (test.init(mRS, mRes)) { + appendTests(test); + } + createTestAllocation(); - mRS.bindRootScript(mScript); + mScript.set_gLoadComplete(true); } } diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java index 61aa3e1..124071e 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java @@ -71,24 +71,6 @@ public class RsBenchView extends RSSurfaceView { } } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return super.onKeyDown(keyCode, event); - } - - - @Override - public boolean onTouchEvent(MotionEvent ev) { - boolean ret = false; - int act = ev.getAction(); - if (act == ev.ACTION_DOWN) { - mRender.onActionDown((int)ev.getX(), (int)ev.getY()); - ret = true; - } - - return ret; - } - /** * Set the total number of loops the benchmark tests will run * before the test results are collected. @@ -106,8 +88,12 @@ public class RsBenchView extends RSSurfaceView { return mRender.testIsFinished(); } - void setBenchmarkMode() { - mRender.setBenchmarkMode(); + void setBenchmarkMode(int benchNum) { + mRender.setBenchmarkMode(benchNum); + } + + void suspendRendering(boolean pause) { + mRender.pause(pause); } void setDebugMode(int num) { diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java new file mode 100644 index 0000000..3ca2792 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011 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.perftest; + +import android.os.Environment; +import android.content.res.Resources; +import android.renderscript.*; +import android.util.DisplayMetrics; + +import android.util.Log; + + +public class TextTest implements RsBenchBaseTest{ + + private static final String TAG = "TextTest"; + private RenderScriptGL mRS; + private Resources mRes; + + private ScriptC_text_test mTextScript; + ScriptField_TestScripts_s.Item[] mTests; + + private final String[] mNames = { + "Fill screen with text 1 time", + "Fill screen with text 3 times", + "Fill screen with text 5 times" + }; + + public TextTest() { + } + + void addTest(int index, int fillNum) { + mTests[index] = new ScriptField_TestScripts_s.Item(); + mTests[index].testScript = mTextScript; + mTests[index].testName = Allocation.createFromString(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + + ScriptField_TextTestData_s.Item dataItem = new ScriptField_TextTestData_s.Item(); + dataItem.fillNum = fillNum; + ScriptField_TextTestData_s testData = new ScriptField_TextTestData_s(mRS, 1); + testData.set(dataItem, 0, true); + mTests[index].testData = testData.getAllocation(); + } + + public boolean init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initTextScript(); + mTests = new ScriptField_TestScripts_s.Item[mNames.length]; + + int index = 0; + addTest(index++, 1 /*fillNum*/); + addTest(index++, 3 /*fillNum*/); + addTest(index++, 5 /*fillNum*/); + + return true; + } + + public ScriptField_TestScripts_s.Item[] getTests() { + return mTests; + } + + public String[] getTestNames() { + return mNames; + } + + void initTextScript() { + DisplayMetrics metrics = mRes.getDisplayMetrics(); + + mTextScript = new ScriptC_text_test(mRS, mRes, R.raw.text_test); + mTextScript.set_gFontSans(Font.create(mRS, mRes, "sans-serif", + Font.Style.NORMAL, 8.0f / metrics.density)); + mTextScript.set_gFontSerif(Font.create(mRS, mRes, "serif", + Font.Style.NORMAL, 8.0f / metrics.density)); + } +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java new file mode 100644 index 0000000..5c9ecd5 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2011 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.perftest; + +import android.os.Environment; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.renderscript.*; +import android.renderscript.Element.DataKind; +import android.renderscript.Element.DataType; +import android.renderscript.Allocation.MipmapControl; +import android.renderscript.Program.TextureType; +import android.renderscript.RenderScript.RSMessageHandler; +import android.renderscript.Mesh.Primitive; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramVertexFixedFunction; + +import android.util.Log; + + +public class TorusTest implements RsBenchBaseTest{ + + private static final String TAG = "TorusTest"; + private RenderScriptGL mRS; + private Resources mRes; + + private ProgramStore mProgStoreBlendNoneDepth; + private ProgramStore mProgStoreBlendNone; + private ProgramStore mProgStoreBlendAlpha; + + private ProgramFragment mProgFragmentTexture; + private ProgramFragment mProgFragmentColor; + + private ProgramVertex mProgVertex; + private ProgramVertexFixedFunction.Constants mPVA; + private ProgramVertexFixedFunction.Constants mPvProjectionAlloc; + + // Custom shaders + private ProgramVertex mProgVertexCustom; + private ProgramFragment mProgFragmentCustom; + private ProgramFragment mProgFragmentMultitex; + private ProgramVertex mProgVertexPixelLight; + private ProgramVertex mProgVertexPixelLightMove; + private ProgramFragment mProgFragmentPixelLight; + private ScriptField_VertexShaderConstants_s mVSConst; + private ScriptField_FragentShaderConstants_s mFSConst; + private ScriptField_VertexShaderConstants3_s mVSConstPixel; + private ScriptField_FragentShaderConstants3_s mFSConstPixel; + + private Allocation mTexTorus; + private Mesh mTorus; + + private ScriptC_torus_test mTorusScript; + + private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + + ScriptField_TestScripts_s.Item[] mTests; + + private final String[] mNames = { + "Geo test 25.6k flat color", + "Geo test 51.2k flat color", + "Geo test 204.8k small tries flat color", + "Geo test 25.6k single texture", + "Geo test 51.2k single texture", + "Geo test 204.8k small tries single texture", + "Geo test 25.6k geo heavy vertex", + "Geo test 51.2k geo heavy vertex", + "Geo test 204.8k geo raster load heavy vertex", + "Geo test 25.6k heavy fragment", + "Geo test 51.2k heavy fragment", + "Geo test 204.8k small tries heavy fragment", + "Geo test 25.6k heavy fragment heavy vertex", + "Geo test 51.2k heavy fragment heavy vertex", + "Geo test 204.8k small tries heavy fragment heavy vertex" + }; + + public TorusTest() { + } + + void addTest(int index, int testId, int user1, int user2) { + mTests[index] = new ScriptField_TestScripts_s.Item(); + mTests[index].testScript = mTorusScript; + mTests[index].testName = Allocation.createFromString(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + + ScriptField_TorusTestData_s.Item dataItem = new ScriptField_TorusTestData_s.Item(); + dataItem.testId = testId; + dataItem.user1 = user1; + dataItem.user2 = user2; + ScriptField_TorusTestData_s testData = new ScriptField_TorusTestData_s(mRS, 1); + testData.set(dataItem, 0, true); + mTests[index].testData = testData.getAllocation(); + } + + public boolean init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initCustomShaders(); + loadImages(); + initMesh(); + initTorusScript(); + mTests = new ScriptField_TestScripts_s.Item[mNames.length]; + + int index = 0; + addTest(index++, 0, 0 /*useTexture*/, 1 /*numMeshes*/); + addTest(index++, 0, 0 /*useTexture*/, 2 /*numMeshes*/); + addTest(index++, 0, 0 /*useTexture*/, 8 /*numMeshes*/); + addTest(index++, 0, 1 /*useTexture*/, 1 /*numMeshes*/); + addTest(index++, 0, 1 /*useTexture*/, 2 /*numMeshes*/); + addTest(index++, 0, 1 /*useTexture*/, 8 /*numMeshes*/); + + // Secont test + addTest(index++, 1, 1 /*numMeshes*/, 0 /*unused*/); + addTest(index++, 1, 2 /*numMeshes*/, 0 /*unused*/); + addTest(index++, 1, 8 /*numMeshes*/, 0 /*unused*/); + + // Third test + addTest(index++, 2, 1 /*numMeshes*/, 0 /*heavyVertex*/); + addTest(index++, 2, 2 /*numMeshes*/, 0 /*heavyVertex*/); + addTest(index++, 2, 8 /*numMeshes*/, 0 /*heavyVertex*/); + addTest(index++, 2, 1 /*numMeshes*/, 1 /*heavyVertex*/); + addTest(index++, 2, 2 /*numMeshes*/, 1 /*heavyVertex*/); + addTest(index++, 2, 8 /*numMeshes*/, 1 /*heavyVertex*/); + + return true; + } + + public ScriptField_TestScripts_s.Item[] getTests() { + return mTests; + } + + public String[] getTestNames() { + return mNames; + } + + private void initCustomShaders() { + mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1); + mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1); + + mVSConstPixel = new ScriptField_VertexShaderConstants3_s(mRS, 1); + mFSConstPixel = new ScriptField_FragentShaderConstants3_s(mRS, 1); + + // Initialize the shader builder + ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS); + // Specify the resource that contains the shader string + pvbCustom.setShader(mRes, R.raw.shaderv); + // Use a script field to specify the input layout + pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); + // Define the constant input layout + pvbCustom.addConstant(mVSConst.getAllocation().getType()); + mProgVertexCustom = pvbCustom.create(); + // Bind the source of constant data + mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); + + ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); + // Specify the resource that contains the shader string + pfbCustom.setShader(mRes, R.raw.shaderf); + // Tell the builder how many textures we have + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + // Define the constant input layout + pfbCustom.addConstant(mFSConst.getAllocation().getType()); + mProgFragmentCustom = pfbCustom.create(); + // Bind the source of constant data + mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); + + pvbCustom = new ProgramVertex.Builder(mRS); + pvbCustom.setShader(mRes, R.raw.shader2v); + pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); + pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); + mProgVertexPixelLight = pvbCustom.create(); + mProgVertexPixelLight.bindConstants(mVSConstPixel.getAllocation(), 0); + + pvbCustom = new ProgramVertex.Builder(mRS); + pvbCustom.setShader(mRes, R.raw.shader2movev); + pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); + pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); + mProgVertexPixelLightMove = pvbCustom.create(); + mProgVertexPixelLightMove.bindConstants(mVSConstPixel.getAllocation(), 0); + + pfbCustom = new ProgramFragment.Builder(mRS); + pfbCustom.setShader(mRes, R.raw.shader2f); + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + pfbCustom.addConstant(mFSConstPixel.getAllocation().getType()); + mProgFragmentPixelLight = pfbCustom.create(); + mProgFragmentPixelLight.bindConstants(mFSConstPixel.getAllocation(), 0); + + pfbCustom = new ProgramFragment.Builder(mRS); + pfbCustom.setShader(mRes, R.raw.multitexf); + for (int texCount = 0; texCount < 3; texCount ++) { + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + } + mProgFragmentMultitex = pfbCustom.create(); + + ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + colBuilder.setVaryingColor(false); + mProgFragmentColor = colBuilder.create(); + + ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); + mProgFragmentTexture = texBuilder.create(); + + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); + mProgVertex = pvb.create(); + ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)mProgVertex).bindConstants(PVA); + Matrix4f proj = new Matrix4f(); + proj.loadOrthoWindow(1280, 720); + PVA.setProjection(proj); + } + + private Allocation loadTextureRGB(int id) { + return Allocation.createFromBitmapResource(mRS, mRes, id, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + private void loadImages() { + mTexTorus = loadTextureRGB(R.drawable.torusmap); + } + + private void initMesh() { + FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); + FileA3D.IndexEntry entry = model.getIndexEntry(0); + if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { + Log.e("rs", "could not load model"); + } else { + mTorus = (Mesh)entry.getObject(); + } + } + + void initTorusScript() { + mTorusScript = new ScriptC_torus_test(mRS, mRes, R.raw.torus_test); + mTorusScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS)); + mTorusScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS)); + mTorusScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); + mTorusScript.set_gTorusMesh(mTorus); + mTorusScript.set_gTexTorus(mTexTorus); + mTorusScript.set_gProgVertexCustom(mProgVertexCustom); + mTorusScript.set_gProgFragmentCustom(mProgFragmentCustom); + mTorusScript.set_gProgVertexPixelLight(mProgVertexPixelLight); + mTorusScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove); + mTorusScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight); + mTorusScript.bind_gVSConstPixel(mVSConstPixel); + mTorusScript.bind_gFSConstPixel(mFSConstPixel); + mTorusScript.bind_gVSConstants(mVSConst); + mTorusScript.bind_gFSConstants(mFSConst); + mTorusScript.set_gProgVertex(mProgVertex); + mTorusScript.set_gProgFragmentTexture(mProgFragmentTexture); + mTorusScript.set_gProgFragmentColor(mProgFragmentColor); + mTorusScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); + } +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java new file mode 100644 index 0000000..c8b58b2 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2011 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.perftest; + +import android.os.Environment; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.renderscript.*; +import android.renderscript.Element.DataKind; +import android.renderscript.Element.DataType; +import android.renderscript.Allocation.MipmapControl; +import android.renderscript.Program.TextureType; +import android.renderscript.ProgramStore.DepthFunc; +import android.renderscript.ProgramStore.BlendSrcFunc; +import android.renderscript.ProgramStore.BlendDstFunc; +import android.renderscript.RenderScript.RSMessageHandler; +import android.renderscript.Mesh.Primitive; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramVertexFixedFunction; + +import android.util.Log; + + +public class UiTest implements RsBenchBaseTest{ + + private static final String TAG = "UiTest"; + private static final String SAMPLE_TEXT = "Bench Test"; + private static final String LIST_TEXT = + "This is a sample list of text to show in the list view"; + private static int PARTICLES_COUNT = 12000; + + private RenderScriptGL mRS; + private Resources mRes; + + Font mFontSans; + + private ScriptField_ListAllocs_s mTextureAllocs; + private ScriptField_ListAllocs_s mSampleTextAllocs; + private ScriptField_ListAllocs_s mSampleListViewAllocs; + private ScriptField_VpConsts mPvStarAlloc; + private ProgramVertexFixedFunction.Constants mPvProjectionAlloc; + + private Mesh mSingleMesh; + private Mesh mParticlesMesh; + + private ScriptC_ui_test mUiScript; + + private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); + + ScriptField_TestScripts_s.Item[] mTests; + + private final String[] mNames = { + "UI test with icon display 10 by 10", + "UI test with icon display 100 by 100", + "UI test with image and text display 3 pages", + "UI test with image and text display 5 pages", + "UI test with list view", + "UI test with live wallpaper" + }; + + public UiTest() { + } + + void addTest(int index, int testId, int user1, int user2, int user3) { + mTests[index] = new ScriptField_TestScripts_s.Item(); + mTests[index].testScript = mUiScript; + mTests[index].testName = Allocation.createFromString(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, + mNames[index], + Allocation.USAGE_SCRIPT); + + ScriptField_UiTestData_s.Item dataItem = new ScriptField_UiTestData_s.Item(); + dataItem.testId = testId; + dataItem.user1 = user1; + dataItem.user2 = user2; + dataItem.user3 = user3; + ScriptField_UiTestData_s testData = new ScriptField_UiTestData_s(mRS, 1); + testData.set(dataItem, 0, true); + mTests[index].testData = testData.getAllocation(); + } + + public boolean init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); + mSingleMesh = getSingleMesh(1, 1); // a unit size mesh + + initUiScript(); + mTests = new ScriptField_TestScripts_s.Item[mNames.length]; + + int index = 0; + + addTest(index++, 0, 0 /*meshMode*/, 0 /*unused*/, 0 /*unused*/); + addTest(index++, 0, 1 /*meshMode*/, 0 /*unused*/, 0 /*unused*/); + addTest(index++, 1, 7 /*wResolution*/, 5 /*hResolution*/, 0 /*meshMode*/); + addTest(index++, 1, 7 /*wResolution*/, 5 /*hResolution*/, 1 /*meshMode*/); + addTest(index++, 2, 0 /*unused*/, 0 /*unused*/, 0 /*unused*/); + addTest(index++, 3, 7 /*wResolution*/, 5 /*hResolution*/, 0 /*unused*/); + + return true; + } + + public ScriptField_TestScripts_s.Item[] getTests() { + return mTests; + } + + public String[] getTestNames() { + return mNames; + } + + private Allocation loadTextureRGB(int id) { + return Allocation.createFromBitmapResource(mRS, mRes, id, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + private Allocation loadTextureARGB(int id) { + Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); + return Allocation.createFromBitmap(mRS, b, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + private void createParticlesMesh() { + ScriptField_Particle p = new ScriptField_Particle(mRS, PARTICLES_COUNT); + + final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS); + meshBuilder.addVertexAllocation(p.getAllocation()); + final int vertexSlot = meshBuilder.getCurrentVertexTypeIndex(); + meshBuilder.addIndexSetType(Primitive.POINT); + mParticlesMesh = meshBuilder.create(); + + mUiScript.set_gParticlesMesh(mParticlesMesh); + mUiScript.bind_Particles(p); + } + + /** + * Create a mesh with a single quad for the given width and height. + */ + private Mesh getSingleMesh(float width, float height) { + Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, + 2, Mesh.TriangleMeshBuilder.TEXTURE_0); + float xOffset = width/2; + float yOffset = height/2; + tmb.setTexture(0, 0); + tmb.addVertex(-1.0f * xOffset, -1.0f * yOffset); + tmb.setTexture(1, 0); + tmb.addVertex(xOffset, -1.0f * yOffset); + tmb.setTexture(1, 1); + tmb.addVertex(xOffset, yOffset); + tmb.setTexture(0, 1); + tmb.addVertex(-1.0f * xOffset, yOffset); + tmb.addTriangle(0, 3, 1); + tmb.addTriangle(1, 3, 2); + return tmb.create(true); + } + + private Matrix4f getProjectionNormalized(int w, int h) { + // range -1,1 in the narrow axis at z = 0. + Matrix4f m1 = new Matrix4f(); + Matrix4f m2 = new Matrix4f(); + + if(w > h) { + float aspect = ((float)w) / h; + m1.loadFrustum(-aspect,aspect, -1,1, 1,100); + } else { + float aspect = ((float)h) / w; + m1.loadFrustum(-1,1, -aspect,aspect, 1,100); + } + + m2.loadRotate(180, 0, 1, 0); + m1.loadMultiply(m1, m2); + + m2.loadScale(-2, 2, 1); + m1.loadMultiply(m1, m2); + + m2.loadTranslate(0, 0, 2); + m1.loadMultiply(m1, m2); + return m1; + } + + private void updateProjectionMatrices() { + Matrix4f projNorm = getProjectionNormalized(1280, 720); + ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item(); + i.Proj = projNorm; + i.MVP = projNorm; + mPvStarAlloc.set(i, 0, true); + mPvProjectionAlloc.setProjection(projNorm); + } + + void initUiScript() { + mUiScript = new ScriptC_ui_test(mRS, mRes, R.raw.ui_test); + + ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + colBuilder.setVaryingColor(false); + ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); + texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); + + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); + ProgramVertexFixedFunction progVertex = pvb.create(); + ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA); + Matrix4f proj = new Matrix4f(); + proj.loadOrthoWindow(1280, 720); + PVA.setProjection(proj); + + mUiScript.set_gProgVertex(progVertex); + mUiScript.set_gProgFragmentColor(colBuilder.create()); + mUiScript.set_gProgFragmentTexture(texBuilder.create()); + mUiScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS)); + + mUiScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); + + mUiScript.set_gTexTorus(loadTextureRGB(R.drawable.torusmap)); + mUiScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); + mUiScript.set_gTexGlobe(loadTextureRGB(R.drawable.globe)); + mUiScript.set_gSingleMesh(mSingleMesh); + + // For GALAXY + ProgramStore.Builder psb = new ProgramStore.Builder(mRS); + psb.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); + mRS.bindProgramStore(psb.create()); + + psb.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE); + mUiScript.set_gPSLights(psb.create()); + + // For Galaxy live wallpaper drawing + ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS); + builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGB, 0); + ProgramFragment pfb = builder.create(); + pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0); + mUiScript.set_gPFBackground(pfb); + + builder = new ProgramFragmentFixedFunction.Builder(mRS); + builder.setPointSpriteTexCoordinateReplacement(true); + builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); + builder.setVaryingColor(true); + ProgramFragment pfs = builder.create(); + pfs.bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0); + mUiScript.set_gPFStars(pfs); + + mTextureAllocs = new ScriptField_ListAllocs_s(mRS, 100); + for (int i = 0; i < 100; i++) { + ScriptField_ListAllocs_s.Item texElem = new ScriptField_ListAllocs_s.Item(); + texElem.item = loadTextureRGB(R.drawable.globe); + mTextureAllocs.set(texElem, i, false); + } + mTextureAllocs.copyAll(); + mUiScript.bind_gTexList100(mTextureAllocs); + + mSampleTextAllocs = new ScriptField_ListAllocs_s(mRS, 100); + for (int i = 0; i < 100; i++) { + ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item(); + textElem.item = Allocation.createFromString(mRS, SAMPLE_TEXT, Allocation.USAGE_SCRIPT); + mSampleTextAllocs.set(textElem, i, false); + } + mSampleTextAllocs.copyAll(); + mUiScript.bind_gSampleTextList100(mSampleTextAllocs); + + mSampleListViewAllocs = new ScriptField_ListAllocs_s(mRS, 1000); + for (int i = 0; i < 1000; i++) { + ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item(); + textElem.item = Allocation.createFromString(mRS, LIST_TEXT, Allocation.USAGE_SCRIPT); + mSampleListViewAllocs.set(textElem, i, false); + } + mSampleListViewAllocs.copyAll(); + mUiScript.bind_gListViewText(mSampleListViewAllocs); + + // For galaxy live wallpaper + mPvStarAlloc = new ScriptField_VpConsts(mRS, 1); + mUiScript.bind_vpConstants(mPvStarAlloc); + mPvProjectionAlloc = new ProgramVertexFixedFunction.Constants(mRS); + updateProjectionMatrices(); + + pvb = new ProgramVertexFixedFunction.Builder(mRS); + ProgramVertex pvbp = pvb.create(); + ((ProgramVertexFixedFunction)pvbp).bindConstants(mPvProjectionAlloc); + mUiScript.set_gPVBkProj(pvbp); + + createParticlesMesh(); + + ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS); + String t = "varying vec4 varColor;\n" + + "varying vec2 varTex0;\n" + + "void main() {\n" + + " float dist = ATTRIB_position.y;\n" + + " float angle = ATTRIB_position.x;\n" + + " float x = dist * sin(angle);\n" + + " float y = dist * cos(angle) * 0.892;\n" + + " float p = dist * 5.5;\n" + + " float s = cos(p);\n" + + " float t = sin(p);\n" + + " vec4 pos;\n" + + " pos.x = t * x + s * y;\n" + + " pos.y = s * x - t * y;\n" + + " pos.z = ATTRIB_position.z;\n" + + " pos.w = 1.0;\n" + + " gl_Position = UNI_MVP * pos;\n" + + " gl_PointSize = ATTRIB_color.a * 10.0;\n" + + " varColor.rgb = ATTRIB_color.rgb;\n" + + " varColor.a = 1.0;\n" + + "}\n"; + sb.setShader(t); + sb.addInput(mParticlesMesh.getVertexAllocation(0).getType().getElement()); + sb.addConstant(mPvStarAlloc.getType()); + ProgramVertex pvs = sb.create(); + pvs.bindConstants(mPvStarAlloc.getAllocation(), 0); + mUiScript.set_gPVStars(pvs); + + // For Galaxy live wallpaper + mUiScript.set_gTSpace(loadTextureRGB(R.drawable.space)); + mUiScript.set_gTLight1(loadTextureRGB(R.drawable.light1)); + mUiScript.set_gTFlares(loadTextureARGB(R.drawable.flares)); + + mUiScript.set_gFontSans(mFontSans); + } +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs new file mode 100644 index 0000000..23832d3 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs @@ -0,0 +1,137 @@ +// Copyright (C) 2011 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.perftest) + +#include "rs_graphics.rsh" +#include "subtest_def.rsh" + +rs_program_vertex gProgVertex; +rs_program_fragment gProgFragmentTexture; +rs_program_fragment gProgFragmentMultitex; + +rs_program_store gProgStoreBlendNone; +rs_program_store gProgStoreBlendAlpha; + +rs_allocation gTexOpaque; +rs_allocation gTexTorus; +rs_allocation gTexTransparent; +rs_allocation gTexChecker; + +rs_sampler gLinearClamp; +rs_sampler gLinearWrap; + +typedef struct FillTestData_s { + int testId; + int blend; + int quadCount; +} FillTestData; +FillTestData *gData; + +static float gDt = 0.0f; + +void init() { +} + +static int gRenderSurfaceW = 1280; +static int gRenderSurfaceH = 720; + +static void bindProgramVertexOrtho() { + // Default vertex shader + rsgBindProgramVertex(gProgVertex); + // Setup the projection matrix + rs_matrix4x4 proj; + rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); + rsgProgramVertexLoadProjectionMatrix(&proj); +} + +static void displaySingletexFill(bool blend, int quadCount) { + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + if (!blend) { + rsgBindProgramStore(gProgStoreBlendNone); + } else { + rsgBindProgramStore(gProgStoreBlendAlpha); + } + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + + for (int i = 0; i < quadCount; i ++) { + float startX = 5 * i, startY = 5 * i; + float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1, + startX + width, startY + height, 0, 1, 1, + startX + width, startY, 0, 1, 0); + } +} + +static void displayMultitextureSample(bool blend, int quadCount) { + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + if (!blend) { + rsgBindProgramStore(gProgStoreBlendNone); + } else { + rsgBindProgramStore(gProgStoreBlendAlpha); + } + rsgBindProgramFragment(gProgFragmentMultitex); + rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp); + rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap); + rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp); + rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker); + rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus); + rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent); + + for (int i = 0; i < quadCount; i ++) { + float startX = 10 * i, startY = 10 * i; + float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; + rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, + startX, startY + height, 0, 0, 1, + startX + width, startY + height, 0, 1, 1, + startX + width, startY, 0, 1, 0); + } +} + + +void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { + TestData *testData = (TestData*)usrData; + gRenderSurfaceW = testData->renderSurfaceW; + gRenderSurfaceH = testData->renderSurfaceH; + gDt = testData->dt; + + gData = (FillTestData*)v_in; + + switch(gData->testId) { + case 0: + displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount); + break; + case 1: + displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount); + break; + default: + rsDebug("Wrong test number", 0); + break; + } +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs new file mode 100644 index 0000000..d7e4857 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs @@ -0,0 +1,89 @@ +// Copyright (C) 2011 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.perftest) + +#include "rs_graphics.rsh" +#include "shader_def.rsh" +#include "subtest_def.rsh" + +rs_program_vertex gProgVertex; +rs_program_fragment gProgFragmentTexture; + +rs_program_store gProgStoreBlendNone; + +rs_allocation gTexOpaque; + +rs_mesh g10by10Mesh; +rs_mesh g100by100Mesh; +rs_mesh gWbyHMesh; + +rs_sampler gLinearClamp; +static int gRenderSurfaceW; +static int gRenderSurfaceH; + +static float gDt = 0; + +typedef struct MeshTestData_s { + int meshNum; +} MeshTestData; +MeshTestData *gData; + +void init() { +} + +static void bindProgramVertexOrtho() { + // Default vertex shader + rsgBindProgramVertex(gProgVertex); + // Setup the projection matrix + rs_matrix4x4 proj; + rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); + rsgProgramVertexLoadProjectionMatrix(&proj); +} + +static void displayMeshSamples(int meshNum) { + + bindProgramVertexOrtho(); + rs_matrix4x4 matrix; + rsMatrixLoadTranslate(&matrix, gRenderSurfaceW/2, gRenderSurfaceH/2, 0); + rsgProgramVertexLoadModelMatrix(&matrix); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendNone); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + + rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + + if (meshNum == 0) { + rsgDrawMesh(g10by10Mesh); + } else if (meshNum == 1) { + rsgDrawMesh(g100by100Mesh); + } else if (meshNum == 2) { + rsgDrawMesh(gWbyHMesh); + } +} + +void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { + TestData *testData = (TestData*)usrData; + gRenderSurfaceW = testData->renderSurfaceW; + gRenderSurfaceH = testData->renderSurfaceH; + gDt = testData->dt; + + gData = (MeshTestData*)v_in; + + displayMeshSamples(gData->meshNum); +} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs index db97835..27e5b11 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2009 The Android Open Source Project +// Copyright (C) 2010-2011 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. @@ -24,104 +24,34 @@ const int RS_MSG_TEST_DONE = 100; const int RS_MSG_RESULTS_READY = 101; -const int gMaxModes = 31; -int gMaxLoops; - -// Parameters for galaxy live wallpaper -rs_allocation gTSpace; -rs_allocation gTLight1; -rs_allocation gTFlares; -rs_mesh gParticlesMesh; - -rs_program_fragment gPFBackground; -rs_program_fragment gPFStars; -rs_program_vertex gPVStars; -rs_program_vertex gPVBkProj; -rs_program_store gPSLights; - -float gXOffset = 0.5f; - -#define ELLIPSE_RATIO 0.892f -#define PI 3.1415f -#define TWO_PI 6.283f -#define ELLIPSE_TWIST 0.023333333f - -static float angle = 50.f; -static int gOldWidth; -static int gOldHeight; -static int gWidth; -static int gHeight; -static float gSpeed[12000]; -static int gGalaxyRadius = 300; -static rs_allocation gParticlesBuffer; - -typedef struct __attribute__((packed, aligned(4))) Particle { - uchar4 color; - float3 position; -} Particle_t; -Particle_t *Particles; - -typedef struct VpConsts { - rs_matrix4x4 Proj; - rs_matrix4x4 MVP; -} VpConsts_t; -VpConsts_t *vpConstants; -// End of parameters for galaxy live wallpaper - -// Allocation to send test names back to java -char *gStringBuffer = 0; +static const int gMaxModes = 64; +int gMaxLoops = 1; +int gDisplayMode = 1; + // Allocation to write the results into static float gResultBuffer[gMaxModes]; -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentColor; -rs_program_fragment gProgFragmentTexture; - -rs_program_store gProgStoreBlendNoneDepth; -rs_program_store gProgStoreBlendNone; -rs_program_store gProgStoreBlendAlpha; -rs_program_store gProgStoreBlendAdd; - -rs_allocation gTexOpaque; -rs_allocation gTexTorus; -rs_allocation gTexTransparent; -rs_allocation gTexChecker; -rs_allocation gTexGlobe; - -typedef struct ListAllocs_s { - rs_allocation item; -} ListAllocs; - -ListAllocs *gTexList100; -ListAllocs *gSampleTextList100; -ListAllocs *gListViewText; - -rs_mesh g10by10Mesh; -rs_mesh g100by100Mesh; -rs_mesh gWbyHMesh; -rs_mesh gSingleMesh; - -rs_font gFontSans; rs_font gFontSerif; - -int gDisplayMode; - rs_sampler gLinearClamp; -rs_sampler gLinearWrap; -rs_sampler gMipLinearWrap; -rs_sampler gNearestClamp; -rs_program_raster gCullBack; -rs_program_raster gCullFront; -rs_program_raster gCullNone; +rs_program_vertex gProgVertex; +rs_program_fragment gProgFragmentTexture; + +rs_allocation gRenderBufferColor; +rs_allocation gRenderBufferDepth; -// Export these out to easily set the inputs to shader VertexShaderInputs *gVSInputs; -rs_program_fragment gProgFragmentMultitex; +typedef struct TestScripts_s { + rs_allocation testData; + rs_allocation testName; + rs_allocation debugName; + rs_script testScript; +} TestScripts; +TestScripts *gTestScripts; -rs_allocation gRenderBufferColor; -rs_allocation gRenderBufferDepth; +bool gLoadComplete = false; +bool gPauseRendering = false; static float gDt = 0; @@ -131,158 +61,17 @@ void init() { static int gRenderSurfaceW; static int gRenderSurfaceH; -/** - * Methods to draw the galaxy live wall paper - */ -static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) { - return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); -} - -/** - * Helper function to generate the stars. - */ -static float randomGauss() { - float x1; - float x2; - float w = 2.f; - - while (w >= 1.0f) { - x1 = rsRand(2.0f) - 1.0f; - x2 = rsRand(2.0f) - 1.0f; - w = x1 * x1 + x2 * x2; - } - - w = sqrt(-2.0f * log(w) / w); - return x1 * w; +static void fillSurfaceParams(TestData *testData) { + testData->renderSurfaceW = gRenderSurfaceW; + testData->renderSurfaceH = gRenderSurfaceH; + testData->dt = gDt; } -/** - * Generates the properties for a given star. - */ -static void createParticle(Particle_t *part, int idx, float scale) { - float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f); - float id = d / gGalaxyRadius; - float z = randomGauss() * 0.4f * (1.0f - id); - float p = -d * ELLIPSE_TWIST; - - if (d < gGalaxyRadius * 0.33f) { - part->color.x = (uchar) (220 + id * 35); - part->color.y = 220; - part->color.z = 220; - } else { - part->color.x = 180; - part->color.y = 180; - part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f); - } - // Stash point size * 10 in Alpha - part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60); - - if (d > gGalaxyRadius * 0.15f) { - z *= 0.6f * (1.0f - id); - } else { - z *= 0.72f; - } - - // Map to the projection coordinates (viewport.x = -1.0 -> 1.0) - d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d); - - part->position.x = rsRand(TWO_PI); - part->position.y = d; - gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f; - - part->position.z = z / 5.0f; -} - -/** - * Initialize all the starts, called from Java - */ -void initParticles() { - Particle_t *part = Particles; - float scale = gGalaxyRadius / (gWidth * 0.5f); - int count = rsAllocationGetDimX(gParticlesBuffer); - for (int i = 0; i < count; i ++) { - createParticle(part, i, scale); - part++; - } -} - -static void drawSpace() { - rsgBindProgramFragment(gPFBackground); - rsgBindTexture(gPFBackground, 0, gTSpace); - rsgDrawQuadTexCoords( - 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - gWidth, 0.0f, 0.0f, 2.0f, 1.0f, - gWidth, gHeight, 0.0f, 2.0f, 0.0f, - 0.0f, gHeight, 0.0f, 0.0f, 0.0f); -} - -static void drawLights() { - rsgBindProgramVertex(gPVBkProj); - rsgBindProgramFragment(gPFBackground); - rsgBindTexture(gPFBackground, 0, gTLight1); - - float scale = 512.0f / gWidth; - float x = -scale - scale * 0.05f; - float y = -scale; - - scale *= 2.0f; - - rsgDrawQuad(x, y, 0.0f, - x + scale * 1.1f, y, 0.0f, - x + scale * 1.1f, y + scale, 0.0f, - x, y + scale, 0.0f); -} - -static void drawParticles(float offset) { - float a = offset * angle; - float absoluteAngle = fabs(a); - - rs_matrix4x4 matrix; - rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f); - if (gHeight > gWidth) { - rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f); - } else { - rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f); - } - rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f); - rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj); - rsMatrixMultiply(&vpConstants->MVP, &matrix); - rsgAllocationSyncAll(rsGetAllocation(vpConstants)); - - rsgBindProgramVertex(gPVStars); - rsgBindProgramFragment(gPFStars); - rsgBindProgramStore(gPSLights); - rsgBindTexture(gPFStars, 0, gTFlares); - - Particle_t *vtx = Particles; - int count = rsAllocationGetDimX(gParticlesBuffer); - for (int i = 0; i < count; i++) { - vtx->position.x = vtx->position.x + gSpeed[i]; - vtx++; - } - - rsgDrawMesh(gParticlesMesh); -} -/* end of methods for drawing galaxy */ - static void setupOffscreenTarget() { rsgBindColorTarget(gRenderBufferColor, 0); rsgBindDepthTarget(gRenderBufferDepth); } -rs_script gFontScript; -rs_script gTorusScript; -rs_allocation gDummyAlloc; - -static void displayFontSamples(int fillNum) { - TestData testData; - testData.renderSurfaceW = gRenderSurfaceW; - testData.renderSurfaceH = gRenderSurfaceH; - testData.user = fillNum; - rsForEach(gFontScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData)); -} - static void bindProgramVertexOrtho() { // Default vertex shader rsgBindProgramVertex(gProgVertex); @@ -292,302 +81,31 @@ static void bindProgramVertexOrtho() { rsgProgramVertexLoadProjectionMatrix(&proj); } -static void displaySingletexFill(bool blend, int quadCount) { - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - if (!blend) { - rsgBindProgramStore(gProgStoreBlendNone); - } else { - rsgBindProgramStore(gProgStoreBlendAlpha); - } - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - - for (int i = 0; i < quadCount; i ++) { - float startX = 5 * i, startY = 5 * i; - float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - } -} - -static void displayMeshSamples(int meshNum) { - - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadTranslate(&matrix, gRenderSurfaceW/2, gRenderSurfaceH/2, 0); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - - if (meshNum == 0) { - rsgDrawMesh(g10by10Mesh); - } else if (meshNum == 1) { - rsgDrawMesh(g100by100Mesh); - } else if (meshNum == 2) { - rsgDrawMesh(gWbyHMesh); - } -} - -// Display sample images in a mesh with different texture -static void displayIcons(int meshMode) { - bindProgramVertexOrtho(); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); - rsgDrawQuadTexCoords( - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, gRenderSurfaceH, 0.0f, 0.0f, 1.0f, - gRenderSurfaceW, gRenderSurfaceH, 0.0f, 1.0f, 1.0f, - gRenderSurfaceW, 0.0f, 0.0f, 1.0f, 0.0f); - - int meshCount = (int)pow(10.0f, (float)(meshMode + 1)); - - float wSize = gRenderSurfaceW/(float)meshCount; - float hSize = gRenderSurfaceH/(float)meshCount; - rs_matrix4x4 matrix; - rsMatrixLoadScale(&matrix, wSize, hSize, 1.0); - - float yPos = 0; - float yPad = hSize / 2; - float xPad = wSize / 2; - for (int y = 0; y < meshCount; y++) { - yPos = y * hSize + yPad; - float xPos = 0; - for (int x = 0; x < meshCount; x++) { - xPos = x * wSize + xPad; - rs_matrix4x4 transMatrix; - rsMatrixLoadTranslate(&transMatrix, xPos, yPos, 0); - rsMatrixMultiply(&transMatrix, &matrix); - rsgProgramVertexLoadModelMatrix(&transMatrix); - int i = (x + y * meshCount) % 100; - rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); - rsgDrawMesh(gSingleMesh); - } - } -} - -// Draw meshes in a single page with top left corner coordinates (xStart, yStart) -static void drawMeshInPage(float xStart, float yStart, int wResolution, int hResolution) { - // Draw wResolution * hResolution meshes in one page - float wMargin = 100.0f; - float hMargin = 100.0f; - float xPad = 50.0f; - float yPad = 20.0f; - float size = 100.0f; // size of images - - // font info - rs_font font = gFontSans; - rsgBindFont(font); - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - - // Measure text size - int left = 0, right = 0, top = 0, bottom = 0; - rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom); - float textHeight = (float)(top - bottom); - float textWidth = (float)(right - left); - - rs_matrix4x4 matrix; - rsMatrixLoadScale(&matrix, size, size, 1.0); - - for (int y = 0; y < hResolution; y++) { - float yPos = yStart + hMargin + y * size + y * yPad; - for (int x = 0; x < wResolution; x++) { - float xPos = xStart + wMargin + x * size + x * xPad; - - rs_matrix4x4 transMatrix; - rsMatrixLoadTranslate(&transMatrix, xPos + size/2, yPos + size/2, 0); - rsMatrixMultiply(&transMatrix, &matrix); // scale the mesh - rsgProgramVertexLoadModelMatrix(&transMatrix); - - int i = (y * wResolution + x) % 100; - rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); - rsgDrawMesh(gSingleMesh); - rsgDrawText(gSampleTextList100[i].item, xPos, yPos + size + yPad/2 + textHeight); - } - } -} - -// Display both images and text as shown in launcher and homepage -// meshMode will decide how many pages we draw -// meshMode = 0: draw 3 pages of meshes -// meshMode = 1: draw 5 pages of meshes -static void displayImageWithText(int wResolution, int hResolution, int meshMode) { - bindProgramVertexOrtho(); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - - drawMeshInPage(0, 0, wResolution, hResolution); - drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - if (meshMode == 1) { - // draw another two pages of meshes - drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); - } -} - -// Display a list of text as the list view -static void displayListView() { - // set text color - rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); - rsgBindFont(gFontSans); - - // get the size of the list - rs_allocation textAlloc; - textAlloc = rsGetAllocation(gListViewText); - int allocSize = rsAllocationGetDimX(textAlloc); - - int listItemHeight = 80; - int yOffset = listItemHeight; - - // set the color for the list divider - rsgBindProgramFragment(gProgFragmentColor); - rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1); - - // draw the list with divider - for (int i = 0; i < allocSize; i++) { - if (yOffset - listItemHeight > gRenderSurfaceH) { - break; - } - rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0); - rsgDrawText(gListViewText[i].item, 20, yOffset - 10); - yOffset += listItemHeight; - } -} - -static void drawGalaxy() { - rsgClearColor(0.f, 0.f, 0.f, 1.f); - gParticlesBuffer = rsGetAllocation(Particles); - rsgBindProgramFragment(gPFBackground); - - gWidth = rsgGetWidth(); - gHeight = rsgGetHeight(); - if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) { - initParticles(); - gOldWidth = gWidth; - gOldHeight = gHeight; - } - - float offset = mix(-1.0f, 1.0f, gXOffset); - drawSpace(); - drawParticles(offset); - drawLights(); -} - -// Display images and text with live wallpaper in the background -static void displayLiveWallPaper(int wResolution, int hResolution) { - bindProgramVertexOrtho(); - - drawGalaxy(); - - rsgBindProgramVertex(gProgVertex); - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - - drawMeshInPage(0, 0, wResolution, hResolution); - drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); -} - -// Quick hack to get some geometry numbers -static void displaySimpleGeoSamples(bool useTexture, int numMeshes) { +static void runSubTest(int index) { TestData testData; - testData.renderSurfaceW = gRenderSurfaceW; - testData.renderSurfaceH = gRenderSurfaceH; - testData.dt = gDt; - testData.user = 0; - testData.user1 = useTexture ? 1 : 0; - testData.user2 = numMeshes; - rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData)); -} + fillSurfaceParams(&testData); -static void displayCustomShaderSamples(int numMeshes) { - TestData testData; - testData.renderSurfaceW = gRenderSurfaceW; - testData.renderSurfaceH = gRenderSurfaceH; - testData.dt = gDt; - testData.user = 1; - testData.user1 = numMeshes; - rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData)); + rs_allocation null_alloc; + rsForEach(gTestScripts[index].testScript, + gTestScripts[index].testData, + null_alloc, + &testData, + sizeof(testData)); } -static void displayPixelLightSamples(int numMeshes, bool heavyVertex) { - TestData testData; - testData.renderSurfaceW = gRenderSurfaceW; - testData.renderSurfaceH = gRenderSurfaceH; - testData.dt = gDt; - testData.user = 2; - testData.user1 = numMeshes; - testData.user2 = heavyVertex ? 1 : 0; - rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData, sizeof(testData)); -} - -static void displayMultitextureSample(bool blend, int quadCount) { - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - if (!blend) { - rsgBindProgramStore(gProgStoreBlendNone); - } else { - rsgBindProgramStore(gProgStoreBlendAlpha); - } - rsgBindProgramFragment(gProgFragmentMultitex); - rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp); - rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap); - rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp); - rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker); - rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus); - rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent); - - for (int i = 0; i < quadCount; i ++) { - float startX = 10 * i, startY = 10 * i; - float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - } -} static bool checkInit() { - static int countdown = 5; + static int countdown = 3; // Perform all the uploads so we only measure rendered time if(countdown > 1) { - displayFontSamples(5); - displaySingletexFill(true, 3); - displayMeshSamples(0); - displayMeshSamples(1); - displayMeshSamples(2); - displayMultitextureSample(true, 5); - displayPixelLightSamples(1, false); - displayPixelLightSamples(1, true); + int testCount = rsAllocationGetDimX(rsGetAllocation(gTestScripts)); + for(int i = 0; i < testCount; i ++) { + rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); + runSubTest(i); + rsgFinish(); + } countdown --; rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); @@ -606,43 +124,11 @@ static bool checkInit() { } static int benchMode = 0; +static bool benchmarkSingleTest = false; +static int benchSubMode = 0; static int runningLoops = 0; static bool sendMsgFlag = false; -static const char *testNames[] = { - "Fill screen with text 1 time", - "Fill screen with text 3 times", - "Fill screen with text 5 times", - "Geo test 25.6k flat color", - "Geo test 51.2k flat color", - "Geo test 204.8k small tries flat color", - "Geo test 25.6k single texture", - "Geo test 51.2k single texture", - "Geo test 204.8k small tries single texture", - "Full screen mesh 10 by 10", - "Full screen mesh 100 by 100", - "Full screen mesh W / 4 by H / 4", - "Geo test 25.6k geo heavy vertex", - "Geo test 51.2k geo heavy vertex", - "Geo test 204.8k geo raster load heavy vertex", - "Fill screen 10x singletexture", - "Fill screen 10x 3tex multitexture", - "Fill screen 10x blended singletexture", - "Fill screen 10x blended 3tex multitexture", - "Geo test 25.6k heavy fragment", - "Geo test 51.2k heavy fragment", - "Geo test 204.8k small tries heavy fragment", - "Geo test 25.6k heavy fragment heavy vertex", - "Geo test 51.2k heavy fragment heavy vertex", - "Geo test 204.8k small tries heavy fragment heavy vertex", - "UI test with icon display 10 by 10", - "UI test with icon display 100 by 100", - "UI test with image and text display 3 pages", - "UI test with image and text display 5 pages", - "UI test with list view", - "UI test with live wallpaper", -}; - static bool gIsDebugMode = false; void setDebugMode(int testNumber) { gIsDebugMode = true; @@ -650,122 +136,17 @@ void setDebugMode(int testNumber) { rsgClearAllRenderTargets(); } -void setBenchmarkMode() { +void setBenchmarkMode(int testNumber) { gIsDebugMode = false; - benchMode = 0; - runningLoops = 0; -} - - -void getTestName(int testIndex) { - int bufferLen = rsAllocationGetDimX(rsGetAllocation(gStringBuffer)); - if (testIndex >= gMaxModes) { - return; - } - uint charIndex = 0; - while (testNames[testIndex][charIndex] != '\0' && charIndex < bufferLen) { - gStringBuffer[charIndex] = testNames[testIndex][charIndex]; - charIndex ++; + if (testNumber == -1) { + benchmarkSingleTest = false; + benchMode = 0; + } else { + benchmarkSingleTest = true; + benchMode = testNumber; } - gStringBuffer[charIndex] = '\0'; -} -static void runTest(int index) { - switch (index) { - case 0: - displayFontSamples(1); - break; - case 1: - displayFontSamples(3); - break; - case 2: - displayFontSamples(5); - break; - case 3: - displaySimpleGeoSamples(false, 1); - break; - case 4: - displaySimpleGeoSamples(false, 2); - break; - case 5: - displaySimpleGeoSamples(false, 8); - break; - case 6: - displaySimpleGeoSamples(true, 1); - break; - case 7: - displaySimpleGeoSamples(true, 2); - break; - case 8: - displaySimpleGeoSamples(true, 8); - break; - case 9: - displayMeshSamples(0); - break; - case 10: - displayMeshSamples(1); - break; - case 11: - displayMeshSamples(2); - break; - case 12: - displayCustomShaderSamples(1); - break; - case 13: - displayCustomShaderSamples(2); - break; - case 14: - displayCustomShaderSamples(10); - break; - case 15: - displaySingletexFill(false, 10); - break; - case 16: - displayMultitextureSample(false, 10); - break; - case 17: - displaySingletexFill(true, 10); - break; - case 18: - displayMultitextureSample(true, 10); - break; - case 19: - displayPixelLightSamples(1, false); - break; - case 20: - displayPixelLightSamples(2, false); - break; - case 21: - displayPixelLightSamples(8, false); - break; - case 22: - displayPixelLightSamples(1, true); - break; - case 23: - displayPixelLightSamples(2, true); - break; - case 24: - displayPixelLightSamples(8, true); - break; - case 25: - displayIcons(0); - break; - case 26: - displayIcons(1); - break; - case 27: - displayImageWithText(7, 5, 0); - break; - case 28: - displayImageWithText(7, 5, 1); - break; - case 29: - displayListView(); - break; - case 30: - displayLiveWallPaper(7, 5); - break; - } + runningLoops = 0; } static void drawOffscreenResult(int posX, int posY, int width, int height) { @@ -803,7 +184,7 @@ static void benchmark() { rsgClearColor(0.1f, 0.1f, 0.1f, 1.0f); rsgClearDepth(1.0f); - runTest(benchMode); + runSubTest(benchMode); rsgClearAllRenderTargets(); gRenderSurfaceW = rsgGetWidth(); gRenderSurfaceH = rsgGetHeight(); @@ -816,25 +197,34 @@ static void benchmark() { int64_t end = rsUptimeMillis(); float fps = (float)(frameCount) / ((float)(end - start)*0.001f); - rsDebug(testNames[benchMode], fps); + const char *testName = rsGetElementAt(gTestScripts[benchMode].debugName, 0); + rsDebug(testName, fps); + gResultBuffer[benchMode] = fps; - drawOffscreenResult(0, 0, - gRenderSurfaceW / 2, - gRenderSurfaceH / 2); - const char* text = testNames[benchMode]; + int bufferW = rsAllocationGetDimX(gRenderBufferColor); + int bufferH = rsAllocationGetDimY(gRenderBufferColor); + + int quadW = gRenderSurfaceW / 2; + int quadH = (quadW * bufferH) / bufferW; + drawOffscreenResult(0, 0, quadW, quadH); + int left = 0, right = 0, top = 0, bottom = 0; uint width = rsgGetWidth(); uint height = rsgGetHeight(); rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); rsgBindFont(gFontSerif); - rsgMeasureText(text, &left, &right, &top, &bottom); + rsgMeasureText(gTestScripts[benchMode].testName, &left, &right, &top, &bottom); rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgDrawText(text, 2 -left, height - 2 + bottom); + rsgDrawText(gTestScripts[benchMode].testName, 2 -left, height - 2 + bottom); - benchMode ++; + if (benchmarkSingleTest) { + return; + } - if (benchMode == gMaxModes) { - rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, gMaxModes*sizeof(float)); + benchMode ++; + int testCount = rsAllocationGetDimX(rsGetAllocation(gTestScripts)); + if (benchMode == testCount) { + rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, testCount*sizeof(float)); benchMode = 0; runningLoops++; if ((gMaxLoops > 0) && (runningLoops > gMaxLoops) && !sendMsgFlag) { @@ -844,14 +234,11 @@ static void benchmark() { sendMsgFlag = true; } } - } static void debug() { gDt = rsGetDt(); - - rsgFinish(); - runTest(benchMode); + runSubTest(benchMode); } int root(void) { @@ -859,10 +246,22 @@ int root(void) { gRenderSurfaceH = rsgGetHeight(); rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f); rsgClearDepth(1.0f); + + if (!gLoadComplete) { + rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); + rsgBindFont(gFontSerif); + rsgDrawText("Loading", 50, 50); + return 0; + } + if(!checkInit()) { return 1; } + if (gPauseRendering) { + rsgDrawText("Paused", 50, 50); + return 30; + } if (gIsDebugMode) { debug(); } else { diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh index b635373..43658b1 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh @@ -20,9 +20,5 @@ typedef struct TestData_s { int renderSurfaceW; int renderSurfaceH; float dt; - int user; - int user1; - int user2; - int user3; } TestData; diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs index 0df6b35..7f10019 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs @@ -22,6 +22,11 @@ rs_font gFontSans; rs_font gFontSerif; +typedef struct TextTestData_s { + int fillNum; +} TextTestData; +TextTestData *gData; + void init() { } @@ -78,5 +83,8 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32 TestData *testData = (TestData*)usrData; gRenderSurfaceW = testData->renderSurfaceW; gRenderSurfaceH = testData->renderSurfaceH; - displayFontSamples(testData->user); + + gData = (TextTestData*)v_in; + + displayFontSamples(gData->fillNum); } diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs index 26d5680..853a05d 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs @@ -47,6 +47,13 @@ rs_program_vertex gProgVertexPixelLight; rs_program_vertex gProgVertexPixelLightMove; rs_program_fragment gProgFragmentPixelLight; +typedef struct TorusTestData_s { + int testId; + int user1; + int user2; +} TorusTestData; +TorusTestData *gData; + static float gDt = 0.0f; static int gRenderSurfaceW; @@ -269,15 +276,20 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32 gRenderSurfaceH = testData->renderSurfaceH; gDt = testData->dt; - switch(testData->user) { + gData = (TorusTestData*)v_in; + + switch(gData->testId) { case 0: - displaySimpleGeoSamples(testData->user1 == 1 ? true : false, testData->user2); + displaySimpleGeoSamples(gData->user1 == 1 ? true : false, gData->user2); break; case 1: - displayCustomShaderSamples(testData->user1); + displayCustomShaderSamples(gData->user1); break; case 2: - displayPixelLightSamples(testData->user1, testData->user2 == 1 ? true : false); + displayPixelLightSamples(gData->user1, gData->user2 == 1 ? true : false); + break; + default: + rsDebug("Wrong test number", gData->testId); break; } } diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs new file mode 100644 index 0000000..5089092 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs @@ -0,0 +1,444 @@ +// Copyright (C) 2011 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. + +#pragma version(1) + +#pragma rs java_package_name(com.android.perftest) + +#include "rs_graphics.rsh" +#include "shader_def.rsh" +#include "subtest_def.rsh" + +// Parameters for galaxy live wallpaper +rs_allocation gTSpace; +rs_allocation gTLight1; +rs_allocation gTFlares; +rs_mesh gParticlesMesh; + +rs_program_fragment gPFBackground; +rs_program_fragment gPFStars; +rs_program_vertex gPVStars; +rs_program_vertex gPVBkProj; +rs_program_store gPSLights; + +float gXOffset = 0.5f; + +#define ELLIPSE_RATIO 0.892f +#define PI 3.1415f +#define TWO_PI 6.283f +#define ELLIPSE_TWIST 0.023333333f + +static float angle = 50.f; +static int gOldWidth; +static int gOldHeight; +static int gWidth; +static int gHeight; +static float gSpeed[12000]; +static int gGalaxyRadius = 300; +static rs_allocation gParticlesBuffer; + +typedef struct __attribute__((packed, aligned(4))) Particle { + uchar4 color; + float3 position; +} Particle_t; +Particle_t *Particles; + +typedef struct VpConsts { + rs_matrix4x4 Proj; + rs_matrix4x4 MVP; +} VpConsts_t; +VpConsts_t *vpConstants; +// End of parameters for galaxy live wallpaper + +rs_program_vertex gProgVertex; +rs_program_fragment gProgFragmentColor; +rs_program_fragment gProgFragmentTexture; + +rs_program_store gProgStoreBlendAlpha; + +rs_allocation gTexOpaque; +rs_allocation gTexTorus; +rs_allocation gTexGlobe; + +typedef struct ListAllocs_s { + rs_allocation item; +} ListAllocs; + +ListAllocs *gTexList100; +ListAllocs *gSampleTextList100; +ListAllocs *gListViewText; + +rs_mesh gSingleMesh; + +rs_font gFontSans; + +rs_sampler gLinearClamp; + +typedef struct UiTestData_s { + int testId; + int user1; + int user2; + int user3; +} UiTestData; +UiTestData *gData; + +static float gDt = 0; + + +void init() { +} + +static int gRenderSurfaceW; +static int gRenderSurfaceH; + +static void bindProgramVertexOrtho() { + // Default vertex shader + rsgBindProgramVertex(gProgVertex); + // Setup the projection matrix + rs_matrix4x4 proj; + rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); + rsgProgramVertexLoadProjectionMatrix(&proj); +} + +/** + * Methods to draw the galaxy live wall paper + */ +static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) { + return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); +} + +/** + * Helper function to generate the stars. + */ +static float randomGauss() { + float x1; + float x2; + float w = 2.f; + + while (w >= 1.0f) { + x1 = rsRand(2.0f) - 1.0f; + x2 = rsRand(2.0f) - 1.0f; + w = x1 * x1 + x2 * x2; + } + + w = sqrt(-2.0f * log(w) / w); + return x1 * w; +} + +/** + * Generates the properties for a given star. + */ +static void createParticle(Particle_t *part, int idx, float scale) { + float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f); + float id = d / gGalaxyRadius; + float z = randomGauss() * 0.4f * (1.0f - id); + float p = -d * ELLIPSE_TWIST; + + if (d < gGalaxyRadius * 0.33f) { + part->color.x = (uchar) (220 + id * 35); + part->color.y = 220; + part->color.z = 220; + } else { + part->color.x = 180; + part->color.y = 180; + part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f); + } + // Stash point size * 10 in Alpha + part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60); + + if (d > gGalaxyRadius * 0.15f) { + z *= 0.6f * (1.0f - id); + } else { + z *= 0.72f; + } + + // Map to the projection coordinates (viewport.x = -1.0 -> 1.0) + d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d); + + part->position.x = rsRand(TWO_PI); + part->position.y = d; + gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f; + + part->position.z = z / 5.0f; +} + +/** + * Initialize all the starts, called from Java + */ +void initParticles() { + Particle_t *part = Particles; + float scale = gGalaxyRadius / (gWidth * 0.5f); + int count = rsAllocationGetDimX(gParticlesBuffer); + for (int i = 0; i < count; i ++) { + createParticle(part, i, scale); + part++; + } +} + +static void drawSpace() { + rsgBindProgramFragment(gPFBackground); + rsgBindTexture(gPFBackground, 0, gTSpace); + rsgDrawQuadTexCoords( + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + gWidth, 0.0f, 0.0f, 2.0f, 1.0f, + gWidth, gHeight, 0.0f, 2.0f, 0.0f, + 0.0f, gHeight, 0.0f, 0.0f, 0.0f); +} + +static void drawLights() { + rsgBindProgramVertex(gPVBkProj); + rsgBindProgramFragment(gPFBackground); + rsgBindTexture(gPFBackground, 0, gTLight1); + + float scale = 512.0f / gWidth; + float x = -scale - scale * 0.05f; + float y = -scale; + + scale *= 2.0f; + + rsgDrawQuad(x, y, 0.0f, + x + scale * 1.1f, y, 0.0f, + x + scale * 1.1f, y + scale, 0.0f, + x, y + scale, 0.0f); +} + +static void drawParticles(float offset) { + float a = offset * angle; + float absoluteAngle = fabs(a); + + rs_matrix4x4 matrix; + rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f); + if (gHeight > gWidth) { + rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f); + } else { + rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f); + } + rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f); + rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj); + rsMatrixMultiply(&vpConstants->MVP, &matrix); + rsgAllocationSyncAll(rsGetAllocation(vpConstants)); + + rsgBindProgramVertex(gPVStars); + rsgBindProgramFragment(gPFStars); + rsgBindProgramStore(gPSLights); + rsgBindTexture(gPFStars, 0, gTFlares); + + Particle_t *vtx = Particles; + int count = rsAllocationGetDimX(gParticlesBuffer); + for (int i = 0; i < count; i++) { + vtx->position.x = vtx->position.x + gSpeed[i]; + vtx++; + } + + rsgDrawMesh(gParticlesMesh); +} +/* end of methods for drawing galaxy */ + +// Display sample images in a mesh with different texture +static void displayIcons(int meshMode) { + bindProgramVertexOrtho(); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendAlpha); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); + rsgDrawQuadTexCoords( + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, gRenderSurfaceH, 0.0f, 0.0f, 1.0f, + gRenderSurfaceW, gRenderSurfaceH, 0.0f, 1.0f, 1.0f, + gRenderSurfaceW, 0.0f, 0.0f, 1.0f, 0.0f); + + int meshCount = (int)pow(10.0f, (float)(meshMode + 1)); + + float wSize = gRenderSurfaceW/(float)meshCount; + float hSize = gRenderSurfaceH/(float)meshCount; + rs_matrix4x4 matrix; + rsMatrixLoadScale(&matrix, wSize, hSize, 1.0); + + float yPos = 0; + float yPad = hSize / 2; + float xPad = wSize / 2; + for (int y = 0; y < meshCount; y++) { + yPos = y * hSize + yPad; + float xPos = 0; + for (int x = 0; x < meshCount; x++) { + xPos = x * wSize + xPad; + rs_matrix4x4 transMatrix; + rsMatrixLoadTranslate(&transMatrix, xPos, yPos, 0); + rsMatrixMultiply(&transMatrix, &matrix); + rsgProgramVertexLoadModelMatrix(&transMatrix); + int i = (x + y * meshCount) % 100; + rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); + rsgDrawMesh(gSingleMesh); + } + } +} + +// Draw meshes in a single page with top left corner coordinates (xStart, yStart) +static void drawMeshInPage(float xStart, float yStart, int wResolution, int hResolution) { + // Draw wResolution * hResolution meshes in one page + float wMargin = 100.0f; + float hMargin = 100.0f; + float xPad = 50.0f; + float yPad = 20.0f; + float size = 100.0f; // size of images + + // font info + rs_font font = gFontSans; + rsgBindFont(font); + rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); + + // Measure text size + int left = 0, right = 0, top = 0, bottom = 0; + rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom); + float textHeight = (float)(top - bottom); + float textWidth = (float)(right - left); + + rs_matrix4x4 matrix; + rsMatrixLoadScale(&matrix, size, size, 1.0); + + for (int y = 0; y < hResolution; y++) { + float yPos = yStart + hMargin + y * size + y * yPad; + for (int x = 0; x < wResolution; x++) { + float xPos = xStart + wMargin + x * size + x * xPad; + + rs_matrix4x4 transMatrix; + rsMatrixLoadTranslate(&transMatrix, xPos + size/2, yPos + size/2, 0); + rsMatrixMultiply(&transMatrix, &matrix); // scale the mesh + rsgProgramVertexLoadModelMatrix(&transMatrix); + + int i = (y * wResolution + x) % 100; + rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); + rsgDrawMesh(gSingleMesh); + rsgDrawText(gSampleTextList100[i].item, xPos, yPos + size + yPad/2 + textHeight); + } + } +} + +// Display both images and text as shown in launcher and homepage +// meshMode will decide how many pages we draw +// meshMode = 0: draw 3 pages of meshes +// meshMode = 1: draw 5 pages of meshes +static void displayImageWithText(int wResolution, int hResolution, int meshMode) { + bindProgramVertexOrtho(); + + // Fragment shader with texture + rsgBindProgramStore(gProgStoreBlendAlpha); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + + drawMeshInPage(0, 0, wResolution, hResolution); + drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); + drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); + if (meshMode == 1) { + // draw another two pages of meshes + drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); + drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); + } +} + +// Display a list of text as the list view +static void displayListView() { + // set text color + rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); + rsgBindFont(gFontSans); + + // get the size of the list + rs_allocation textAlloc; + textAlloc = rsGetAllocation(gListViewText); + int allocSize = rsAllocationGetDimX(textAlloc); + + int listItemHeight = 80; + int yOffset = listItemHeight; + + // set the color for the list divider + rsgBindProgramFragment(gProgFragmentColor); + rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1); + + // draw the list with divider + for (int i = 0; i < allocSize; i++) { + if (yOffset - listItemHeight > gRenderSurfaceH) { + break; + } + rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0); + rsgDrawText(gListViewText[i].item, 20, yOffset - 10); + yOffset += listItemHeight; + } +} + +static void drawGalaxy() { + rsgClearColor(0.f, 0.f, 0.f, 1.f); + gParticlesBuffer = rsGetAllocation(Particles); + rsgBindProgramFragment(gPFBackground); + + gWidth = rsgGetWidth(); + gHeight = rsgGetHeight(); + if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) { + initParticles(); + gOldWidth = gWidth; + gOldHeight = gHeight; + } + + float offset = mix(-1.0f, 1.0f, gXOffset); + drawSpace(); + drawParticles(offset); + drawLights(); +} + +// Display images and text with live wallpaper in the background +static void displayLiveWallPaper(int wResolution, int hResolution) { + bindProgramVertexOrtho(); + + drawGalaxy(); + + rsgBindProgramVertex(gProgVertex); + rsgBindProgramStore(gProgStoreBlendAlpha); + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + + drawMeshInPage(0, 0, wResolution, hResolution); + drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); + drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); + drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); + drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); +} + +void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { + TestData *testData = (TestData*)usrData; + gRenderSurfaceW = testData->renderSurfaceW; + gRenderSurfaceH = testData->renderSurfaceH; + gDt = testData->dt; + + gData = (UiTestData*)v_in; + + switch(gData->testId) { + case 0: + displayIcons(gData->user1); + break; + case 1: + displayImageWithText(gData->user1, gData->user2, gData->user3); + break; + case 2: + displayListView(); + break; + case 3: + displayLiveWallPaper(gData->user1, gData->user2); + break; + default: + rsDebug("Wrong test number", 0); + break; + } +} diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs index 53f10f9..ae32e3a 100644 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs +++ b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs @@ -57,6 +57,14 @@ static float gZoom; static float gLastX; static float gLastY; +static float3 toFloat3(float x, float y, float z) { + float3 f; + f.x = x; + f.y = y; + f.z = z; + return f; +} + void onActionDown(float x, float y) { gLastX = x; gLastY = y; @@ -112,8 +120,8 @@ void updateMeshInfo() { rsgMeshComputeBoundingBox(info->mMesh, &minX, &minY, &minZ, &maxX, &maxY, &maxZ); - info->bBoxMin = (minX, minY, minZ); - info->bBoxMax = (maxX, maxY, maxZ); + info->bBoxMin = toFloat3(minX, minY, minZ); + info->bBoxMax = toFloat3(maxX, maxY, maxZ); gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; } gLookAt = gLookAt / (float)size; diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java index c038478..2293678 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 The Android Open Source Project + * Copyright (C) 2008-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,6 +65,7 @@ public class RSTestCore { unitTests = new ArrayList<UnitTest>(); unitTests.add(new UT_primitives(this, mRes, mCtx)); + unitTests.add(new UT_constant(this, mRes, mCtx)); unitTests.add(new UT_vector(this, mRes, mCtx)); unitTests.add(new UT_rsdebug(this, mRes, mCtx)); unitTests.add(new UT_rstime(this, mRes, mCtx)); @@ -72,6 +73,8 @@ public class RSTestCore { unitTests.add(new UT_alloc(this, mRes, mCtx)); unitTests.add(new UT_refcount(this, mRes, mCtx)); unitTests.add(new UT_foreach(this, mRes, mCtx)); + unitTests.add(new UT_atomic(this, mRes, mCtx)); + unitTests.add(new UT_struct(this, mRes, mCtx)); unitTests.add(new UT_math(this, mRes, mCtx)); unitTests.add(new UT_fp_mad(this, mRes, mCtx)); /* @@ -91,7 +94,7 @@ public class RSTestCore { for (int i = 0; i < uta.length; i++) { ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item(); listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT); - listElem.result = uta[i].result; + listElem.result = uta[i].getResult(); mListAllocs.set(listElem, i, false); uta[i].setItem(listElem); } diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java new file mode 100644 index 0000000..267c5b2 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_atomic extends UnitTest { + private Resources mRes; + + protected UT_atomic(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Atomics", ctx); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_atomic s = new ScriptC_atomic(pRS, mRes, R.raw.atomic); + pRS.setMessageHandler(mRsMessage); + s.invoke_atomic_test(); + pRS.finish(); + waitForMessage(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java new file mode 100644 index 0000000..adda5a3 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_constant extends UnitTest { + private Resources mRes; + + protected UT_constant(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Const", ctx); + mRes = res; + } + + private void Assert(boolean b) { + if (!b) { + failTest(); + } + } + + public void run() { + Assert(ScriptC_constant.const_floatTest == 1.99f); + Assert(ScriptC_constant.const_doubleTest == 2.05); + Assert(ScriptC_constant.const_charTest == -8); + Assert(ScriptC_constant.const_shortTest == -16); + Assert(ScriptC_constant.const_intTest == -32); + Assert(ScriptC_constant.const_longTest == 17179869184l); + Assert(ScriptC_constant.const_longlongTest == 68719476736l); + + Assert(ScriptC_constant.const_ucharTest == 8); + Assert(ScriptC_constant.const_ushortTest == 16); + Assert(ScriptC_constant.const_uintTest == 32); + Assert(ScriptC_constant.const_ulongTest == 4611686018427387904L); + Assert(ScriptC_constant.const_int64_tTest == -17179869184l); + Assert(ScriptC_constant.const_uint64_tTest == 117179869184l); + + Assert(ScriptC_constant.const_boolTest == true); + + passTest(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java index b7a65a5..18829c2 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java @@ -92,8 +92,7 @@ public class UT_primitives extends UnitTest { ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives); pRS.setMessageHandler(mRsMessage); if (!initializeGlobals(s)) { - // initializeGlobals failed - result = -1; + failTest(); } else { s.invoke_primitives_test(0, 0); pRS.finish(); diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java index f302e1a..21e657c 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_rstime.java @@ -32,6 +32,7 @@ public class UT_rstime extends UnitTest { RenderScript pRS = RenderScript.create(mCtx); ScriptC_rstime s = new ScriptC_rstime(pRS, mRes, R.raw.rstime); pRS.setMessageHandler(mRsMessage); + s.setTimeZone("America/Los_Angeles"); s.invoke_test_rstime(0, 0); pRS.finish(); waitForMessage(); diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java new file mode 100644 index 0000000..2a55686 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; + +public class UT_struct extends UnitTest { + private Resources mRes; + + protected UT_struct(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Struct", ctx); + mRes = res; + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + ScriptC_struct s = new ScriptC_struct(pRS, mRes, R.raw.struct); + pRS.setMessageHandler(mRsMessage); + + ScriptField_Point2 p = new ScriptField_Point2(pRS, 1); + ScriptField_Point2.Item i = new ScriptField_Point2.Item(); + int val = 100; + i.x = val; + i.y = val; + p.set(i, 0, true); + s.bind_point2(p); + s.invoke_struct_test(val); + pRS.finish(); + waitForMessage(); + + val = 200; + p.set_x(0, val, true); + p.set_y(0, val, true); + s.invoke_struct_test(val); + pRS.finish(); + waitForMessage(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java index 748701d..0ac09ca 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java @@ -307,7 +307,7 @@ public class UT_vector extends UnitTest { ScriptC_vector s = new ScriptC_vector(pRS, mRes, R.raw.vector); pRS.setMessageHandler(mRsMessage); if (!initializeGlobals(s)) { - result = -1; + failTest(); } else { s.invoke_vector_test(); pRS.finish(); diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java index a97ffa7..edff83f 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java @@ -21,7 +21,7 @@ import android.renderscript.RenderScript.RSMessageHandler; public class UnitTest extends Thread { public String name; - public int result; + private int result; private ScriptField_ListAllocs_s.Item mItem; private RSTestCore mRSTC; private boolean msgHandled; @@ -63,7 +63,7 @@ public class UnitTest extends Thread { } } - protected void updateUI() { + private void updateUI() { if (mItem != null) { mItem.result = result; msgHandled = true; @@ -104,6 +104,22 @@ public class UnitTest extends Thread { } } + public int getResult() { + return result; + } + + public void failTest() { + result = -1; + updateUI(); + } + + public void passTest() { + if (result != -1) { + result = 1; + } + updateUI(); + } + public void setItem(ScriptField_ListAllocs_s.Item item) { mItem = item; } diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs new file mode 100644 index 0000000..f0a5041 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs @@ -0,0 +1,77 @@ +#include "shared.rsh" + +// Testing atomic operations +static bool testUMax(uint32_t dst, uint32_t src) { + bool failed = false; + uint32_t old = dst; + uint32_t expect = (dst > src ? dst : src); + uint32_t ret = rsAtomicMax(&dst, src); + _RS_ASSERT(old == ret); + _RS_ASSERT(dst == expect); + return failed; +} + +static bool testUMin(uint32_t dst, uint32_t src) { + bool failed = false; + uint32_t old = dst; + uint32_t expect = (dst < src ? dst : src); + uint32_t ret = rsAtomicMin(&dst, src); + _RS_ASSERT(old == ret); + _RS_ASSERT(dst == expect); + return failed; +} + +static bool testUCas(uint32_t dst, uint32_t cmp, uint32_t swp) { + bool failed = false; + uint32_t old = dst; + uint32_t expect = (dst == cmp ? swp : dst); + uint32_t ret = rsAtomicCas(&dst, cmp, swp); + _RS_ASSERT(old == ret); + _RS_ASSERT(dst == expect); + return failed; +} + +static bool test_atomics() { + bool failed = false; + + failed |= testUMax(5, 6); + failed |= testUMax(6, 5); + failed |= testUMax(5, 0xf0000006); + failed |= testUMax(0xf0000006, 5); + + failed |= testUMin(5, 6); + failed |= testUMin(6, 5); + failed |= testUMin(5, 0xf0000006); + failed |= testUMin(0xf0000006, 5); + + failed |= testUCas(4, 4, 5); + failed |= testUCas(4, 5, 5); + failed |= testUCas(5, 5, 4); + failed |= testUCas(5, 4, 4); + failed |= testUCas(0xf0000004, 0xf0000004, 0xf0000005); + failed |= testUCas(0xf0000004, 0xf0000005, 0xf0000005); + failed |= testUCas(0xf0000005, 0xf0000005, 0xf0000004); + failed |= testUCas(0xf0000005, 0xf0000004, 0xf0000004); + + if (failed) { + rsDebug("test_atomics FAILED", 0); + } + else { + rsDebug("test_atomics PASSED", 0); + } + + return failed; +} + +void atomic_test() { + bool failed = false; + failed |= test_atomics(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs new file mode 100644 index 0000000..732eaef --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs @@ -0,0 +1,19 @@ +#include "shared.rsh" + +const float floatTest = 1.99f; +const double doubleTest = 2.05; +const char charTest = -8; +const short shortTest = -16; +const int intTest = -32; +const long longTest = 17179869184l; // 1 << 34 +const long long longlongTest = 68719476736l; // 1 << 36 + +const uchar ucharTest = 8; +const ushort ushortTest = 16; +const uint uintTest = 32; +const ulong ulongTest = 4611686018427387904L; +const int64_t int64_tTest = -17179869184l; // - 1 << 34 +const uint64_t uint64_tTest = 117179869184l; + +const bool boolTest = true; + diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs index 5e3e078..7be955d 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstime.rs @@ -19,7 +19,7 @@ static bool basic_test(uint32_t index) { rsDebug("tm.tm_yday", tm.tm_yday); rsDebug("tm.tm_isdst", tm.tm_isdst); - // Test a specific time (only valid for PST localtime) + // Test a specific time (since we set America/Los_Angeles localtime) curTime = 1294438893; rsLocaltime(&tm, &curTime); diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs new file mode 100644 index 0000000..1cd728e --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs @@ -0,0 +1,37 @@ +#include "shared.rsh" + +typedef struct Point2 { + int x; + int y; +} Point_2; +Point_2 *point2; + +static bool test_Point_2(int expected) { + bool failed = false; + + rsDebug("Point: ", point2[0].x, point2[0].y); + _RS_ASSERT(point2[0].x == expected); + _RS_ASSERT(point2[0].y == expected); + + if (failed) { + rsDebug("test_Point_2 FAILED", 0); + } + else { + rsDebug("test_Point_2 PASSED", 0); + } + + return failed; +} + +void struct_test(int expected) { + bool failed = false; + failed |= test_Point_2(expected); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/TileBenchmark/Android.mk b/tests/TileBenchmark/Android.mk index 430f0f1..5851113 100644 --- a/tests/TileBenchmark/Android.mk +++ b/tests/TileBenchmark/Android.mk @@ -21,12 +21,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := TileBenchmark -include $(BUILD_PACKAGE) +LOCAL_MODULE_TAGS := tests -################################################## -include $(CLEAR_VARS) - -include $(BUILD_MULTI_PREBUILT) +LOCAL_JAVA_LIBRARIES := android.test.runner -# Use the folloing include to make our test apk. -include $(call all-makefiles-under,$(LOCAL_PATH)) +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml index ab61a9e..f125c70 100644 --- a/tests/TileBenchmark/AndroidManifest.xml +++ b/tests/TileBenchmark/AndroidManifest.xml @@ -18,5 +18,9 @@ android:label="@string/playback_activity" android:theme="@android:style/Theme.Holo.NoActionBar"> </activity> + <uses-library android:name="android.test.runner" /> </application> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.test.tilebenchmark" + android:label="Tests for WebView Tiles."/> </manifest> diff --git a/tests/TileBenchmark/res/layout/main.xml b/tests/TileBenchmark/res/layout/main.xml index 577c466..1b39d5d 100644 --- a/tests/TileBenchmark/res/layout/main.xml +++ b/tests/TileBenchmark/res/layout/main.xml @@ -18,46 +18,52 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - <LinearLayout - android:id="@+id/top" - android:layout_width="match_parent" + <HorizontalScrollView + android:id="@+id/horizontalScrollView" + android:layout_width="wrap_content" android:layout_height="wrap_content" > - <Spinner - android:id="@+id/movement" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:prompt="@string/movement_method" - /> - <Spinner - android:id="@+id/velocity" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="center_horizontal" - android:prompt="@string/desired_scroll_velocity" - /> - <ToggleButton - android:id="@+id/capture" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textOn="@string/capture_stop" - android:textOff="@string/capture_start" - /> - <EditText - android:id="@+id/url" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:inputType="textUri" - android:imeOptions="actionGo" - android:layout_weight="1" - /> - <Button - android:id="@+id/inspect" - android:layout_width="wrap_content" + <LinearLayout + android:id="@+id/top" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/inspect_log" - /> - </LinearLayout> + > + <Spinner + android:id="@+id/movement" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:prompt="@string/movement_method" + /> + <Spinner + android:id="@+id/velocity" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:prompt="@string/desired_scroll_velocity" + /> + <ToggleButton + android:id="@+id/capture" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textOn="@string/capture_stop" + android:textOff="@string/capture_start" + /> + <EditText + android:id="@+id/url" + android:layout_width="400dp" + android:layout_height="wrap_content" + android:inputType="textUri" + android:imeOptions="actionGo|flagNoExtractUi" + android:layout_weight="1" + /> + <Button + android:id="@+id/inspect" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/inspect_log" + /> + </LinearLayout> + </HorizontalScrollView> <com.test.tilebenchmark.ProfiledWebView android:id="@+id/web" android:layout_width="match_parent" diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml index 5af52dc..6c7055b 100644 --- a/tests/TileBenchmark/res/values/strings.xml +++ b/tests/TileBenchmark/res/values/strings.xml @@ -49,8 +49,9 @@ <!-- Drop down menu entry - automatically scroll to the end of the page with scrollBy() [CHAR LIMIT=15] --> <string name="movement_auto_scroll">Auto-scroll</string> - <!-- Drop down menu entry - [CHAR LIMIT=15] --> - <string name="movement_auto_fling">Auto-fling</string> + <!-- Drop down menu entry - automatically record for a set time before + stopping [CHAR LIMIT=15] --> + <string name="movement_timed">Timed</string> <!-- Drop down menu entry - manually navigate the page(s), hit 'capture' button [CHAR LIMIT=15] --> <string name="movement_manual">Manual</string> @@ -67,14 +68,21 @@ <!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12] --> <string name="percentile_75">75%ile</string> + <!-- standard deviation [CHAR LIMIT=12] --> + <string name="std_dev">StdDev</string> + <!-- mean [CHAR LIMIT=12] --> + <string name="mean">mean</string> + + + <!-- Frame rate [CHAR LIMIT=15] --> <string name="frames_per_second">Frames/sec</string> <!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] --> <string name="viewport_coverage">Coverage</string> <!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] --> <string name="render_millis">RenderMillis</string> - <!-- Number of rendering stalls while running the test [CHAR LIMIT=15] --> - <string name="render_stalls">Stalls</string> + <!-- Animation Framerate [CHAR LIMIT=15] --> + <string name="animation_framerate">AnimFramerate</string> <!-- Format string for stat value overlay [CHAR LIMIT=15] --> <string name="format_stat">%4.4f</string> diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java new file mode 100644 index 0000000..6356cc1 --- /dev/null +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2011 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.test.tilebenchmark; + +import com.test.tilebenchmark.ProfileActivity.ProfileCallback; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import android.content.res.Resources; +import android.os.Bundle; +import android.os.Environment; +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; +import android.webkit.WebSettings; +import android.widget.Spinner; + +public class PerformanceTest extends + ActivityInstrumentationTestCase2<ProfileActivity> { + + public static class AnimStat { + double aggVal = 0; + double aggSqrVal = 0; + double count = 0; + } + + private class StatAggregator extends PlaybackGraphs { + private HashMap<String, Double> mDataMap = new HashMap<String, Double>(); + private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>(); + private int mCount = 0; + + + public void aggregate() { + boolean inAnimTests = mAnimTests != null; + Resources resources = mWeb.getResources(); + String animFramerateString = resources.getString(R.string.animation_framerate); + for (Map.Entry<String, Double> e : mSingleStats.entrySet()) { + String name = e.getKey(); + if (inAnimTests) { + if (name.equals(animFramerateString)) { + // in animation testing phase, record animation framerate and aggregate + // stats, differentiating on values of mAnimTestNr and mDoubleBuffering + String fullName = ANIM_TEST_NAMES[mAnimTestNr] + " " + name; + fullName += mDoubleBuffering ? " tiled" : " webkit"; + + if (!mAnimDataMap.containsKey(fullName)) { + mAnimDataMap.put(fullName, new AnimStat()); + } + AnimStat statVals = mAnimDataMap.get(fullName); + statVals.aggVal += e.getValue(); + statVals.aggSqrVal += e.getValue() * e.getValue(); + statVals.count += 1; + } + } else { + double aggVal = mDataMap.containsKey(name) + ? mDataMap.get(name) : 0; + mDataMap.put(name, aggVal + e.getValue()); + } + } + + if (inAnimTests) { + return; + } + + mCount++; + for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { + for (int statIndex = 0; statIndex < Stats.length; statIndex++) { + String metricLabel = resources.getString( + Metrics[metricIndex].getLabelId()); + String statLabel = resources.getString( + Stats[statIndex].getLabelId()); + + String label = metricLabel + " " + statLabel; + double aggVal = mDataMap.containsKey(label) ? mDataMap + .get(label) : 0; + + aggVal += mStats[metricIndex][statIndex]; + mDataMap.put(label, aggVal); + } + } + + } + + // build the final bundle of results + public Bundle getBundle() { + Bundle b = new Bundle(); + int count = (0 == mCount) ? Integer.MAX_VALUE : mCount; + for (Map.Entry<String, Double> e : mDataMap.entrySet()) { + b.putDouble(e.getKey(), e.getValue() / count); + } + + for (Map.Entry<String, AnimStat> e : mAnimDataMap.entrySet()) { + String statName = e.getKey(); + AnimStat statVals = e.getValue(); + + double avg = statVals.aggVal/statVals.count; + double stdDev = Math.sqrt((statVals.aggSqrVal / statVals.count) - avg * avg); + + b.putDouble(statName, avg); + b.putDouble(statName + " STD DEV", stdDev); + } + + return b; + } + } + + ProfileActivity mActivity; + ProfiledWebView mWeb; + Spinner mMovementSpinner; + StatAggregator mStats; + + private static final String LOGTAG = "PerformanceTest"; + private static final String TEST_LOCATION = "webkit/page_cycler"; + private static final String URL_PREFIX = "file://"; + private static final String URL_POSTFIX = "/index.html?skip=true"; + private static final int MAX_ITERATIONS = 4; + private static final String SCROLL_TEST_DIRS[] = { + "alexa25_2011" + }; + private static final String ANIM_TEST_DIRS[] = { + "dhtml" + }; + + public PerformanceTest() { + super(ProfileActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mActivity = getActivity(); + mWeb = (ProfiledWebView) mActivity.findViewById(R.id.web); + mMovementSpinner = (Spinner) mActivity.findViewById(R.id.movement); + mStats = new StatAggregator(); + + // use mStats as a condition variable between the UI thread and + // this(the testing) thread + mActivity.setCallback(new ProfileCallback() { + @Override + public void profileCallback(RunData data) { + mStats.setData(data); + synchronized (mStats) { + mStats.notify(); + } + } + }); + + } + + private boolean loadUrl(final String url) { + try { + Log.d(LOGTAG, "test starting for url " + url); + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mWeb.loadUrl(url); + } + }); + synchronized (mStats) { + mStats.wait(); + } + + mStats.aggregate(); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + return true; + } + + private boolean validTest(String nextTest) { + // if testing animations, test must be in mAnimTests + if (mAnimTests == null) + return true; + + for (String test : mAnimTests) { + if (test.equals(nextTest)) { + return true; + } + } + return false; + } + + private boolean runIteration(String[] testDirs) { + File sdFile = Environment.getExternalStorageDirectory(); + for (String testDirName : testDirs) { + File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName); + Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath() + + "', exists=" + testDir.exists()); + + for (File siteDir : testDir.listFiles()) { + if (!siteDir.isDirectory() || !validTest(siteDir.getName())) { + continue; + } + + if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath() + + URL_POSTFIX)) { + return false; + } + } + } + return true; + } + + private boolean runTestDirs(String[] testDirs) { + for (int i = 0; i < MAX_ITERATIONS; i++) + if (!runIteration(testDirs)) { + return false; + } + return true; + } + + private void pushDoubleBuffering() { + getInstrumentation().runOnMainSync(new Runnable() { + public void run() { + mWeb.setDoubleBuffering(mDoubleBuffering); + } + }); + } + + private void setScrollingTestingMode(final boolean scrolled) { + getInstrumentation().runOnMainSync(new Runnable() { + public void run() { + mMovementSpinner.setSelection(scrolled ? 0 : 2); + } + }); + } + + + private String[] mAnimTests = null; + private int mAnimTestNr = -1; + private boolean mDoubleBuffering = true; + private static final String[] ANIM_TEST_NAMES = { + "slow", "fast" + }; + private static final String[][] ANIM_TESTS = { + {"scrolling", "replaceimages", "layers5", "layers1"}, + {"slidingballs", "meter", "slidein", "fadespacing", "colorfade", + "mozilla", "movingtext", "diagball", "zoom", "imageslide"}, + }; + + private boolean checkMedia() { + String state = Environment.getExternalStorageState(); + + if (!Environment.MEDIA_MOUNTED.equals(state) + && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + Log.d(LOGTAG, "ARG Can't access sd card!"); + // Can't read the SD card, fail and die! + getInstrumentation().sendStatus(1, null); + return false; + } + return true; + } + + public void testMetrics() { + setScrollingTestingMode(true); + if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) { + getInstrumentation().sendStatus(0, mStats.getBundle()); + } else { + getInstrumentation().sendStatus(1, null); + } + } + + private boolean runAnimationTests() { + for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) { + mDoubleBuffering = doubleBuffer == 1; + pushDoubleBuffering(); + for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) { + mAnimTests = ANIM_TESTS[mAnimTestNr]; + if (!runTestDirs(ANIM_TEST_DIRS)) { + return false; + } + } + } + return true; + } + + public void testAnimations() { + // instead of autoscrolling, load each page until either an timer fires, + // or the animation signals complete via javascript + setScrollingTestingMode(false); + + if (checkMedia() && runAnimationTests()) { + getInstrumentation().sendStatus(0, mStats.getBundle()); + } else { + getInstrumentation().sendStatus(1, null); + } + } +} diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java index 9ea90f8..a3ae9be 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java @@ -80,7 +80,7 @@ public class PlaybackGraphs { for (int tileID = 1; tileID < frame.length; tileID++) { TileData data = frame[tileID]; double coverage = viewportCoverage(frame[0], data); - total += coverage * (data.isReady ? 1 : 0); + total += coverage * (data.isReady ? 100 : 0); totalCount += coverage; } if (totalCount == 0) { @@ -91,7 +91,7 @@ public class PlaybackGraphs { @Override public double getMax() { - return 1; + return 100; } @Override @@ -108,6 +108,9 @@ public class PlaybackGraphs { } public static double getPercentile(double sortedValues[], double ratioAbove) { + if (sortedValues.length == 0) + return -1; + double index = ratioAbove * (sortedValues.length - 1); int intIndex = (int) Math.floor(index); if (index == intIndex) { @@ -118,6 +121,31 @@ public class PlaybackGraphs { + sortedValues[intIndex + 1] * (alpha); } + public static double getMean(double sortedValues[]) { + if (sortedValues.length == 0) + return -1; + + double agg = 0; + for (double val : sortedValues) { + agg += val; + } + return agg / sortedValues.length; + } + + public static double getStdDev(double sortedValues[]) { + if (sortedValues.length == 0) + return -1; + + double agg = 0; + double sqrAgg = 0; + for (double val : sortedValues) { + agg += val; + sqrAgg += val*val; + } + double mean = agg / sortedValues.length; + return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean)); + } + protected static StatGen[] Stats = new StatGen[] { new StatGen() { @Override @@ -149,6 +177,26 @@ public class PlaybackGraphs { public int getLabelId() { return R.string.percentile_75; } + }, new StatGen() { + @Override + public double getValue(double[] sortedValues) { + return getStdDev(sortedValues); + } + + @Override + public int getLabelId() { + return R.string.std_dev; + } + }, new StatGen() { + @Override + public double getValue(double[] sortedValues) { + return getMean(sortedValues); + } + + @Override + public int getLabelId() { + return R.string.mean; + } }, }; @@ -159,40 +207,47 @@ public class PlaybackGraphs { } private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>(); - protected double[][] mStats = new double[Metrics.length][Stats.length]; + protected final double[][] mStats = new double[Metrics.length][Stats.length]; protected HashMap<String, Double> mSingleStats; + private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) { + // create graph out of rectangles, one per frame + int lastBar = 0; + for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) { + TileData frame[] = data.frames[frameIndex]; + int newBar = (frame[0].top + frame[0].bottom) / 2; + + MetricGen s = Metrics[metricIndex]; + double absoluteValue = s.getValue(frame); + double relativeValue = absoluteValue / s.getMax(); + relativeValue = Math.min(1,relativeValue); + relativeValue = Math.max(0,relativeValue); + int rightPos = (int) (-BAR_WIDTH * metricIndex); + int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue)); + + ShapeDrawable graphBar = new ShapeDrawable(); + graphBar.getPaint().setColor(Color.BLUE); + graphBar.setBounds(leftPos, lastBar, rightPos, newBar); + + mShapes.add(graphBar); + metricValues[frameIndex] = absoluteValue; + lastBar = newBar; + } + } + public void setData(RunData data) { mShapes.clear(); double metricValues[] = new double[data.frames.length]; + mSingleStats = data.singleStats; + if (data.frames.length == 0) { return; } for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { - // create graph out of rectangles, one per frame - int lastBar = 0; - for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) { - TileData frame[] = data.frames[frameIndex]; - int newBar = (frame[0].top + frame[0].bottom) / 2; - - MetricGen s = Metrics[metricIndex]; - double absoluteValue = s.getValue(frame); - double relativeValue = absoluteValue / s.getMax(); - relativeValue = Math.min(1,relativeValue); - relativeValue = Math.max(0,relativeValue); - int rightPos = (int) (-BAR_WIDTH * metricIndex); - int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue)); - - ShapeDrawable graphBar = new ShapeDrawable(); - graphBar.getPaint().setColor(Color.BLUE); - graphBar.setBounds(leftPos, lastBar, rightPos, newBar); - - mShapes.add(graphBar); - metricValues[frameIndex] = absoluteValue; - lastBar = newBar; - } + // calculate metric based on list of frames + gatherFrameMetric(metricIndex, metricValues, data); // store aggregate statistics per metric (median, and similar) Arrays.sort(metricValues); @@ -200,8 +255,6 @@ public class PlaybackGraphs { mStats[metricIndex][statIndex] = Stats[statIndex].getValue(metricValues); } - - mSingleStats = data.singleStats; } } diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java index e7a21ad..2e77157 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java @@ -22,11 +22,12 @@ import android.content.Context; import android.graphics.Bitmap; import android.os.AsyncTask; import android.os.Bundle; +import android.os.CountDownTimer; +import android.util.Log; import android.util.Pair; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; -import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.AdapterView; @@ -49,6 +50,8 @@ import java.io.ObjectOutputStream; */ public class ProfileActivity extends Activity { + private static final int TIMED_RECORD_MILLIS = 2000; + public interface ProfileCallback { public void profileCallback(RunData data); } @@ -65,6 +68,7 @@ public class ProfileActivity extends Activity { LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient(); AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient(); + TimedLoggingWebViewClient mTimedLoggingWebViewClient = new TimedLoggingWebViewClient(); private enum TestingState { NOT_TESTING, @@ -93,18 +97,18 @@ public class ProfileActivity extends Activity { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { String movementStr = parent.getItemAtPosition(position).toString(); - if (movementStr == getResources().getString( - R.string.movement_auto_scroll) - || movementStr == getResources().getString( - R.string.movement_auto_fling)) { + if (movementStr == getResources().getString(R.string.movement_auto_scroll)) { mWeb.setWebViewClient(mAutoLoggingWebViewClient); mCaptureButton.setEnabled(false); mVelocitySpinner.setEnabled(true); - } else if (movementStr == getResources().getString( - R.string.movement_manual)) { + } else if (movementStr == getResources().getString(R.string.movement_manual)) { mWeb.setWebViewClient(mLoggingWebViewClient); mCaptureButton.setEnabled(true); mVelocitySpinner.setEnabled(false); + } else if (movementStr == getResources().getString(R.string.movement_timed)) { + mWeb.setWebViewClient(mTimedLoggingWebViewClient); + mCaptureButton.setEnabled(false); + mVelocitySpinner.setEnabled(false); } } @@ -124,16 +128,46 @@ public class ProfileActivity extends Activity { super.onPageStarted(view, url, favicon); mUrl.setText(url); } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + view.requestFocus(); + ((ProfiledWebView)view).onPageFinished(); + } } private class AutoLoggingWebViewClient extends LoggingWebViewClient { + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + startViewProfiling(true); + } @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + setTestingState(TestingState.PRE_TESTING); + } + } + + private class TimedLoggingWebViewClient extends LoggingWebViewClient { + @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); - view.requestFocus(); + startViewProfiling(false); - startViewProfiling(true); + // after a fixed time after page finished, stop testing + new CountDownTimer(TIMED_RECORD_MILLIS, TIMED_RECORD_MILLIS) { + @Override + public void onTick(long millisUntilFinished) { + } + + @Override + public void onFinish() { + mWeb.stopScrollTest(); + } + }.start(); } @Override @@ -178,11 +212,13 @@ public class ProfileActivity extends Activity { mMovementSpinner.setEnabled(false); break; case START_TESTING: + mCaptureButton.setChecked(true); mUrl.setBackgroundResource(R.color.background_start_testing); mInspectButton.setEnabled(false); mMovementSpinner.setEnabled(false); break; case STOP_TESTING: + mCaptureButton.setChecked(false); mUrl.setBackgroundResource(R.color.background_stop_testing); break; case SAVED_TESTING: @@ -195,7 +231,6 @@ public class ProfileActivity extends Activity { /** auto - automatically scroll. */ private void startViewProfiling(boolean auto) { // toggle capture button to indicate capture state to user - mCaptureButton.setChecked(true); mWeb.startScrollTest(mCallback, auto); setTestingState(TestingState.START_TESTING); } @@ -217,7 +252,7 @@ public class ProfileActivity extends Activity { public void profileCallback(RunData data) { new StoreFileTask().execute(new Pair<String, RunData>( TEMP_FILENAME, data)); - mCaptureButton.setChecked(false); + Log.d("ProfileActivity", "stored " + data.frames.length + " frames in file"); setTestingState(TestingState.STOP_TESTING); } }); @@ -245,8 +280,8 @@ public class ProfileActivity extends Activity { // Movement spinner String content[] = { getResources().getString(R.string.movement_auto_scroll), - getResources().getString(R.string.movement_auto_fling), - getResources().getString(R.string.movement_manual) + getResources().getString(R.string.movement_manual), + getResources().getString(R.string.movement_timed) }; adapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, content); @@ -270,12 +305,7 @@ public class ProfileActivity extends Activity { }); // Custom profiling WebView - WebSettings settings = mWeb.getSettings(); - settings.setJavaScriptEnabled(true); - settings.setSupportZoom(true); - settings.setEnableSmoothTransition(true); - settings.setBuiltInZoomControls(true); - settings.setLoadWithOverviewMode(true); + mWeb.init(this); mWeb.setWebViewClient(new LoggingWebViewClient()); // URL text entry diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java index 10802b4..a38ac25 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java @@ -20,23 +20,32 @@ import android.content.Context; import android.os.CountDownTimer; import android.util.AttributeSet; import android.util.Log; +import android.webkit.WebSettings; import android.webkit.WebView; +import android.widget.Toast; + +import java.util.ArrayList; import com.test.tilebenchmark.ProfileActivity.ProfileCallback; import com.test.tilebenchmark.RunData.TileData; public class ProfiledWebView extends WebView { + private static final String LOGTAG = "ProfiledWebView"; + private int mSpeed; private boolean mIsTesting = false; private boolean mIsScrolling = false; private ProfileCallback mCallback; private long mContentInvalMillis; - private boolean mHadToBeForced = false; - private int mTestCount = 0; - private static final int LOAD_STALL_MILLIS = 5000; // nr of millis after load, + private static final int LOAD_STALL_MILLIS = 2000; // nr of millis after load, // before test is forced + // ignore anim end events until this many millis after load + private static final long ANIM_SAFETY_THRESHOLD = 200; + private long mLoadTime; + private long mAnimationTime; + public ProfiledWebView(Context context) { super(context); } @@ -54,6 +63,39 @@ public class ProfiledWebView extends WebView { super(context, attrs, defStyle, privateBrowsing); } + private class JavaScriptInterface { + Context mContext; + + /** Instantiate the interface and set the context */ + JavaScriptInterface(Context c) { + mContext = c; + } + + /** Show a toast from the web page */ + public void animationComplete() { + Toast.makeText(mContext, "Animation complete!", Toast.LENGTH_SHORT).show(); + //Log.d(LOGTAG, "anim complete"); + mAnimationTime = System.currentTimeMillis(); + } + } + + public void init(Context c) { + WebSettings settings = getSettings(); + settings.setJavaScriptEnabled(true); + settings.setSupportZoom(true); + settings.setEnableSmoothTransition(true); + settings.setBuiltInZoomControls(true); + settings.setLoadWithOverviewMode(true); + settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does + addJavascriptInterface(new JavaScriptInterface(c), "Android"); + mAnimationTime = 0; + mLoadTime = 0; + } + + public void onPageFinished() { + mLoadTime = System.currentTimeMillis(); + } + @Override protected void onDraw(android.graphics.Canvas canvas) { if (mIsTesting && mIsScrolling) { @@ -73,16 +115,12 @@ public class ProfiledWebView extends WebView { * scrolling, invalidate all content and redraw it, measuring time taken. */ public void startScrollTest(ProfileCallback callback, boolean autoScrolling) { - mIsScrolling = autoScrolling; mCallback = callback; mIsTesting = false; - mContentInvalMillis = System.currentTimeMillis(); - registerPageSwapCallback(); - contentInvalidateAll(); - invalidate(); + mIsScrolling = false; + WebSettings settings = getSettings(); + settings.setProperty("tree_updates", "0"); - mTestCount++; - final int testCount = mTestCount; if (autoScrolling) { // after a while, force it to start even if the pages haven't swapped @@ -93,15 +131,18 @@ public class ProfiledWebView extends WebView { @Override public void onFinish() { - if (testCount == mTestCount && !mIsTesting) { - mHadToBeForced = true; - Log.d("ProfiledWebView", "num " + testCount - + " forcing a page swap with a scroll..."); - scrollBy(0, 1); - invalidate(); // ensure a redraw so that auto-scrolling can occur - } + // invalidate all content, and kick off redraw + Log.d("ProfiledWebView", + "kicking off test with callback registration, and tile discard..."); + discardAllTextures(); + invalidate(); + mIsScrolling = true; + mContentInvalMillis = System.currentTimeMillis(); } }.start(); + } else { + mIsTesting = true; + tileProfilingStart(); } } @@ -111,13 +152,36 @@ public class ProfiledWebView extends WebView { */ @Override protected void pageSwapCallback(boolean startAnim) { - mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis; super.pageSwapCallback(startAnim); - Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis - + "millis"); - mIsTesting = true; - invalidate(); // ensure a redraw so that auto-scrolling can occur - tileProfilingStart(); + + if (!mIsTesting && mIsScrolling) { + // kick off testing + mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis; + Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis"); + mIsTesting = true; + invalidate(); // ensure a redraw so that auto-scrolling can occur + tileProfilingStart(); + } + } + + private double animFramerate() { + WebSettings settings = getSettings(); + String updatesString = settings.getProperty("tree_updates"); + int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString); + + long animationTime; + if (mAnimationTime == 0 || mAnimationTime - mLoadTime < ANIM_SAFETY_THRESHOLD) { + animationTime = System.currentTimeMillis() - mLoadTime; + } else { + animationTime = mAnimationTime - mLoadTime; + } + + return updates * 1000.0 / animationTime; + } + + public void setDoubleBuffering(boolean useDoubleBuffering) { + WebSettings settings = getSettings(); + settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false"); } /* @@ -136,11 +200,12 @@ public class ProfiledWebView extends WebView { // record the time spent (before scrolling) rendering the page data.singleStats.put(getResources().getString(R.string.render_millis), (double)mContentInvalMillis); - // record if the page render timed out - Log.d("ProfiledWebView", "hadtobeforced = " + mHadToBeForced); - data.singleStats.put(getResources().getString(R.string.render_stalls), - mHadToBeForced ? 1.0 : 0.0); - mHadToBeForced = false; + + // record framerate + double framerate = animFramerate(); + Log.d(LOGTAG, "anim framerate was "+framerate); + data.singleStats.put(getResources().getString(R.string.animation_framerate), + framerate); for (int frame = 0; frame < data.frames.length; frame++) { data.frames[frame] = new TileData[ @@ -168,6 +233,8 @@ public class ProfiledWebView extends WebView { @Override public void loadUrl(String url) { + mAnimationTime = 0; + mLoadTime = 0; if (!url.startsWith("http://") && !url.startsWith("file://")) { url = "http://" + url; } diff --git a/tests/TileBenchmark/tests/Android.mk b/tests/TileBenchmark/tests/Android.mk deleted file mode 100644 index 8b235ec..0000000 --- a/tests/TileBenchmark/tests/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.test.runner - -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := TileBenchmarkTests - -LOCAL_INSTRUMENTATION_FOR := TileBenchmark - -include $(BUILD_PACKAGE) diff --git a/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java deleted file mode 100644 index 6bf6f6b..0000000 --- a/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2011 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.test.tilebenchmark; - -import com.test.tilebenchmark.ProfileActivity.ProfileCallback; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; - -import android.content.res.Resources; -import android.os.Bundle; -import android.os.Environment; -import android.test.ActivityInstrumentationTestCase2; -import android.util.Log; - -public class PerformanceTest extends - ActivityInstrumentationTestCase2<ProfileActivity> { - - private class StatAggregator extends PlaybackGraphs { - private HashMap<String, Double> mDataMap = new HashMap<String, Double>(); - private int mCount = 0; - - public void aggregate() { - mCount++; - Resources resources = mView.getResources(); - for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { - for (int statIndex = 0; statIndex < Stats.length; statIndex++) { - String metricLabel = resources.getString( - Metrics[metricIndex].getLabelId()); - String statLabel = resources.getString( - Stats[statIndex].getLabelId()); - - String label = metricLabel + " " + statLabel; - double aggVal = mDataMap.containsKey(label) ? mDataMap - .get(label) : 0; - - aggVal += mStats[metricIndex][statIndex]; - mDataMap.put(label, aggVal); - } - } - for (Map.Entry<String, Double> e : mSingleStats.entrySet()) { - double aggVal = mDataMap.containsKey(e.getKey()) - ? mDataMap.get(e.getKey()) : 0; - mDataMap.put(e.getKey(), aggVal + e.getValue()); - } - } - - public Bundle getBundle() { - Bundle b = new Bundle(); - int count = 0 == mCount ? Integer.MAX_VALUE : mCount; - for (Map.Entry<String, Double> e : mDataMap.entrySet()) { - b.putDouble(e.getKey(), e.getValue() / count); - } - return b; - } - } - - ProfileActivity mActivity; - ProfiledWebView mView; - StatAggregator mStats = new StatAggregator(); - - private static final String LOGTAG = "PerformanceTest"; - private static final String TEST_LOCATION = "webkit/page_cycler"; - private static final String URL_PREFIX = "file://"; - private static final String URL_POSTFIX = "/index.html?skip=true"; - private static final int MAX_ITERATIONS = 4; - private static final String TEST_DIRS[] = { - "intl1"//, "alexa_us", "android", "dom", "intl2", "moz", "moz2" - }; - - public PerformanceTest() { - super(ProfileActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - mActivity = getActivity(); - mView = (ProfiledWebView) mActivity.findViewById(R.id.web); - } - - private boolean loadUrl(final String url) { - try { - Log.d(LOGTAG, "test starting for url " + url); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mView.loadUrl(url); - } - }); - synchronized (mStats) { - mStats.wait(); - } - mStats.aggregate(); - } catch (InterruptedException e) { - e.printStackTrace(); - return false; - } - return true; - } - - private boolean runIteration() { - File sdFile = Environment.getExternalStorageDirectory(); - for (String testDirName : TEST_DIRS) { - File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName); - Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath() - + "', exists=" + testDir.exists()); - for (File siteDir : testDir.listFiles()) { - if (!siteDir.isDirectory()) - continue; - - if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath() - + URL_POSTFIX)) { - return false; - } - } - } - return true; - } - - public void testMetrics() { - String state = Environment.getExternalStorageState(); - - if (!Environment.MEDIA_MOUNTED.equals(state) - && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { - Log.d(LOGTAG, "ARG Can't access sd card!"); - // Can't read the SD card, fail and die! - getInstrumentation().sendStatus(1, null); - return; - } - - // use mGraphs as a condition variable between the UI thread and - // this(the testing) thread - mActivity.setCallback(new ProfileCallback() { - @Override - public void profileCallback(RunData data) { - Log.d(LOGTAG, "test completion callback"); - mStats.setData(data); - synchronized (mStats) { - mStats.notify(); - } - } - }); - - for (int i = 0; i < MAX_ITERATIONS; i++) - if (!runIteration()) { - getInstrumentation().sendStatus(1, null); - return; - } - getInstrumentation().sendStatus(0, mStats.getBundle()); - } -} diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk new file mode 100644 index 0000000..e049c90 --- /dev/null +++ b/tests/TtsTests/Android.mk @@ -0,0 +1,28 @@ +# +# Copyright (C) 2011 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_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_STATIC_JAVA_LIBRARIES := littlemock +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := TtsTests + +include $(BUILD_PACKAGE) diff --git a/tests/TtsTests/AndroidManifest.xml b/tests/TtsTests/AndroidManifest.xml new file mode 100644 index 0000000..b6d5111 --- /dev/null +++ b/tests/TtsTests/AndroidManifest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2011 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.speech.tts"> + <application> + <uses-library android:name="android.test.runner" /> + + + <service android:name=".MockableTextToSpeechService" + android:label="Mockable Text-to-speech Service"> + <intent-filter> + <action android:name="android.intent.action.TTS_SERVICE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </service> + + <activity android:name=".MockableCheckVoiceData" + android:theme="@android:style/Theme.NoDisplay"> + <intent-filter> + <action android:name="android.speech.tts.engine.CHECK_TTS_DATA" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.speech.tts" + android:label="Tests for android.speech.tts" /> +</manifest> diff --git a/tests/TtsTests/src/com/android/speech/tts/MockableCheckVoiceData.java b/tests/TtsTests/src/com/android/speech/tts/MockableCheckVoiceData.java new file mode 100644 index 0000000..0ab8ed6 --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/MockableCheckVoiceData.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 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.speech.tts; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.speech.tts.TextToSpeech; + +import java.util.ArrayList; +import java.util.List; + +public class MockableCheckVoiceData extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + MockableTextToSpeechService.IDelegate delegate = + MockableTextToSpeechService.getMocker(); + + ArrayList<String> availableLangs = delegate.getAvailableVoices(); + ArrayList<String> unavailableLangs = delegate.getUnavailableVoices(); + + final Intent returnVal = new Intent(); + + // Returns early. + if (availableLangs == null) { + setResult(TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL, returnVal); + finish(); + return; + } + + returnVal.putStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, + availableLangs); + + if (unavailableLangs != null && unavailableLangs.size() > 0) { + returnVal.putStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, + unavailableLangs); + } + + setResult(TextToSpeech.Engine.CHECK_VOICE_DATA_PASS, returnVal); + finish(); + } + +} diff --git a/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java b/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java new file mode 100644 index 0000000..20648a4 --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 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.speech.tts; + +import android.speech.tts.SynthesisCallback; +import android.speech.tts.SynthesisRequest; +import android.speech.tts.TextToSpeechService; + +import java.util.ArrayList; + +public class MockableTextToSpeechService extends TextToSpeechService { + + private static IDelegate sDelegate; + + public static void setMocker(IDelegate delegate) { + sDelegate = delegate; + } + + static IDelegate getMocker() { + return sDelegate; + } + + @Override + protected int onIsLanguageAvailable(String lang, String country, String variant) { + return sDelegate.onIsLanguageAvailable(lang, country, variant); + } + + @Override + protected String[] onGetLanguage() { + return sDelegate.onGetLanguage(); + } + + @Override + protected int onLoadLanguage(String lang, String country, String variant) { + return sDelegate.onLoadLanguage(lang, country, variant); + } + + @Override + protected void onStop() { + sDelegate.onStop(); + } + + @Override + protected void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback) { + sDelegate.onSynthesizeText(request, callback); + } + + public static interface IDelegate { + int onIsLanguageAvailable(String lang, String country, String variant); + + String[] onGetLanguage(); + + int onLoadLanguage(String lang, String country, String variant); + + void onStop(); + + void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback); + + ArrayList<String> getAvailableVoices(); + + ArrayList<String> getUnavailableVoices(); + } + +} diff --git a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java new file mode 100644 index 0000000..b736e9f --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2011 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.speech.tts; + +import android.speech.tts.SynthesisCallback; +import android.speech.tts.SynthesisRequest; +import android.speech.tts.TextToSpeech; +import android.test.InstrumentationTestCase; + +import com.android.speech.tts.MockableTextToSpeechService.IDelegate; +import com.google.testing.littlemock.ArgumentCaptor; +import com.google.testing.littlemock.Behaviour; +import com.google.testing.littlemock.LittleMock; +import junit.framework.Assert; + +import java.util.Locale; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TextToSpeechTests extends InstrumentationTestCase { + private static final String MOCK_ENGINE = "com.android.speech.tts"; + private static final String MOCK_PACKAGE = "com.android.speech.tts.__testpackage__"; + + private TextToSpeech mTts; + + @Override + public void setUp() throws Exception { + IDelegate passThrough = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(passThrough); + + blockingInitAndVerify(MOCK_ENGINE, TextToSpeech.SUCCESS); + assertEquals(MOCK_ENGINE, mTts.getCurrentEngine()); + } + + + @Override + public void tearDown() { + if (mTts != null) { + mTts.shutdown(); + } + } + + public void testEngineInitialized() throws Exception { + // Fail on an engine that doesn't exist. + blockingInitAndVerify("__DOES_NOT_EXIST__", TextToSpeech.ERROR); + + // Also, the "current engine" must be null + assertNull(mTts.getCurrentEngine()); + } + + public void testSetLanguage_delegation() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // Test 1 :Tests that calls to onLoadLanguage( ) are delegated through to the + // service without any caching or intermediate steps. + mTts.setLanguage(new Locale("eng", "USA", "variant")); + LittleMock.verify(delegate, LittleMock.times(1)).onLoadLanguage( + "eng", "USA", "variant"); + } + + public void testSetLanguage_availableLanguage() throws Exception { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // --------------------------------------------------------- + // Test 2 : Tests that when the language is successfully set + // like above (returns LANG_COUNTRY_AVAILABLE). That the + // request language changes from that point on. + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage( + "eng", "USA", "variant"); + mTts.setLanguage(new Locale("eng", "USA", "variant")); + blockingCallSpeak("foo bar", delegate); + ArgumentCaptor<SynthesisRequest> req = LittleMock.createCaptor(); + LittleMock.verify(delegate, LittleMock.times(1)).onSynthesizeText(req.capture(), + LittleMock.<SynthesisCallback>anyObject()); + + assertEquals("eng", req.getValue().getLanguage()); + assertEquals("USA", req.getValue().getCountry()); + assertEquals("", req.getValue().getVariant()); + } + + public void testSetLanguage_unavailableLanguage() throws Exception { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // --------------------------------------------------------- + // TEST 3 : Tests that the language that is set does not change when the + // engine reports it could not load the specified language. + LittleMock.doReturn(TextToSpeech.LANG_NOT_SUPPORTED).when( + delegate).onLoadLanguage("fra", "FRA", ""); + mTts.setLanguage(Locale.FRANCE); + blockingCallSpeak("le fou barre", delegate); + ArgumentCaptor<SynthesisRequest> req2 = LittleMock.createCaptor(); + LittleMock.verify(delegate, LittleMock.times(1)).onSynthesizeText(req2.capture(), + LittleMock.<SynthesisCallback>anyObject()); + + // The params are basically unchanged. + assertEquals("eng", req2.getValue().getLanguage()); + assertEquals("USA", req2.getValue().getCountry()); + assertEquals("", req2.getValue().getVariant()); + } + + + public void testGetLanguage_invalidReturnValues() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // Test1: Simple end to end test. Ensure that bad return values + // are dealt with appropriately. + LittleMock.doReturn(null).when(delegate).onGetLanguage(); + Locale returnVal = mTts.getLanguage(); + assertNull(returnVal); + + + // Bad value 2. An array of length < 3. + LittleMock.doReturn(new String[] {"eng", "usa"}).when(delegate).onGetLanguage(); + returnVal = mTts.getLanguage(); + assertNull(returnVal); + } + + public void testGetLanguage_validReturnValues() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // A correct value. + LittleMock.doReturn(new String[] {"eng", "usa", ""}).when(delegate).onGetLanguage(); + Locale returnVal = mTts.getLanguage(); + + // Note: This is not the same as Locale.US . Well tough luck for + // being the only component of the entire framework that standardized + // three letter country and language codes. + assertEquals(new Locale("eng", "USA", ""), returnVal); + } + + public void testIsLanguageAvailable() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // Test1: Simple end to end test. + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when( + delegate).onIsLanguageAvailable("eng", "USA", ""); + + assertEquals(TextToSpeech.LANG_COUNTRY_AVAILABLE, mTts.isLanguageAvailable(Locale.US)); + LittleMock.verify(delegate, LittleMock.times(1)).onIsLanguageAvailable( + "eng", "USA", ""); + } + + + private void blockingCallSpeak(String speech, IDelegate mock) throws + InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + doCountDown(latch).when(mock).onSynthesizeText(LittleMock.<SynthesisRequest>anyObject(), + LittleMock.<SynthesisCallback>anyObject()); + mTts.speak(speech, TextToSpeech.QUEUE_ADD, null); + + awaitCountDown(latch, 5, TimeUnit.SECONDS); + } + + private void blockingInitAndVerify(final String engine, int errorCode) throws + InterruptedException { + TextToSpeech.OnInitListener listener = LittleMock.mock( + TextToSpeech.OnInitListener.class); + + final CountDownLatch latch = new CountDownLatch(1); + doCountDown(latch).when(listener).onInit(errorCode); + + mTts = new TextToSpeech(getInstrumentation().getTargetContext(), + listener, engine, MOCK_PACKAGE, false /* use fallback package */); + + awaitCountDown(latch, 5, TimeUnit.SECONDS); + } + + public interface CountDownBehaviour extends Behaviour { + /** Used to mock methods that return a result. */ + Behaviour andReturn(Object result); + } + + public static CountDownBehaviour doCountDown(final CountDownLatch latch) { + return new CountDownBehaviour() { + @Override + public <T> T when(T mock) { + return LittleMock.doAnswer(new Callable<Void>() { + @Override + public Void call() throws Exception { + latch.countDown(); + return null; + } + }).when(mock); + } + + @Override + public Behaviour andReturn(final Object result) { + return new Behaviour() { + @Override + public <T> T when(T mock) { + return LittleMock.doAnswer(new Callable<Object>() { + @Override + public Object call() throws Exception { + latch.countDown(); + return result; + } + }).when(mock); + } + }; + } + }; + } + + public static void awaitCountDown(CountDownLatch latch, long timeout, TimeUnit unit) + throws InterruptedException { + Assert.assertTrue("Waited too long for method call", latch.await(timeout, unit)); + } +} diff --git a/tests/WebViewTests/Android.mk b/tests/WebViewTests/Android.mk new file mode 100644 index 0000000..b118845 --- /dev/null +++ b/tests/WebViewTests/Android.mk @@ -0,0 +1,27 @@ +# +# Copyright (C) 2011 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_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := WebViewTests + +include $(BUILD_PACKAGE) diff --git a/tests/WebViewTests/AndroidManifest.xml b/tests/WebViewTests/AndroidManifest.xml new file mode 100644 index 0000000..8b080c1 --- /dev/null +++ b/tests/WebViewTests/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2011 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.webviewtests"> + <application> + <uses-library android:name="android.test.runner" /> + <activity android:name="WebViewStubActivity" android:label="WebViewStubActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.TEST" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.webviewtests" + android:label="Tests for android.webkit.WebView" /> +</manifest> diff --git a/tests/WebViewTests/res/layout/webview_layout.xml b/tests/WebViewTests/res/layout/webview_layout.xml new file mode 100644 index 0000000..d266d21 --- /dev/null +++ b/tests/WebViewTests/res/layout/webview_layout.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2009 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"> + + <WebView android:id="@+id/web_page" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</LinearLayout> diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayCoercionTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayCoercionTest.java new file mode 100644 index 0000000..c2bbdf5 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayCoercionTest.java @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Part of the test suite for the WebView's Java Bridge. This class tests that + * we correctly convert JavaScript arrays to Java arrays when passing them to + * the methods of injected Java objects. + * + * The conversions should follow + * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in + * which the implementation differs from the spec are marked with + * LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not + * break backwards-compatibility. See b/4408210. + * + * To run this test ... + * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeArrayCoercionTest \ + * com.android.webviewtests/android.test.InstrumentationTestRunner + */ + +package com.android.webviewtests; + +public class JavaBridgeArrayCoercionTest extends JavaBridgeTestBase { + private class TestObject extends Controller { + private Object mObjectInstance; + private CustomType mCustomTypeInstance; + + private boolean[] mBooleanArray; + private byte[] mByteArray; + private char[] mCharArray; + private short[] mShortArray; + private int[] mIntArray; + private long[] mLongArray; + private float[] mFloatArray; + private double[] mDoubleArray; + private String[] mStringArray; + private Object[] mObjectArray; + private CustomType[] mCustomTypeArray; + + public TestObject() { + mObjectInstance = new Object(); + mCustomTypeInstance = new CustomType(); + } + + public Object getObjectInstance() { + return mObjectInstance; + } + public CustomType getCustomTypeInstance() { + return mCustomTypeInstance; + } + + public synchronized void setBooleanArray(boolean[] x) { + mBooleanArray = x; + notifyResultIsReady(); + } + public synchronized void setByteArray(byte[] x) { + mByteArray = x; + notifyResultIsReady(); + } + public synchronized void setCharArray(char[] x) { + mCharArray = x; + notifyResultIsReady(); + } + public synchronized void setShortArray(short[] x) { + mShortArray = x; + notifyResultIsReady(); + } + public synchronized void setIntArray(int[] x) { + mIntArray = x; + notifyResultIsReady(); + } + public synchronized void setLongArray(long[] x) { + mLongArray = x; + notifyResultIsReady(); + } + public synchronized void setFloatArray(float[] x) { + mFloatArray = x; + notifyResultIsReady(); + } + public synchronized void setDoubleArray(double[] x) { + mDoubleArray = x; + notifyResultIsReady(); + } + public synchronized void setStringArray(String[] x) { + mStringArray = x; + notifyResultIsReady(); + } + public synchronized void setObjectArray(Object[] x) { + mObjectArray = x; + notifyResultIsReady(); + } + public synchronized void setCustomTypeArray(CustomType[] x) { + mCustomTypeArray = x; + notifyResultIsReady(); + } + + public synchronized boolean[] waitForBooleanArray() { + waitForResult(); + return mBooleanArray; + } + public synchronized byte[] waitForByteArray() { + waitForResult(); + return mByteArray; + } + public synchronized char[] waitForCharArray() { + waitForResult(); + return mCharArray; + } + public synchronized short[] waitForShortArray() { + waitForResult(); + return mShortArray; + } + public synchronized int[] waitForIntArray() { + waitForResult(); + return mIntArray; + } + public synchronized long[] waitForLongArray() { + waitForResult(); + return mLongArray; + } + public synchronized float[] waitForFloatArray() { + waitForResult(); + return mFloatArray; + } + public synchronized double[] waitForDoubleArray() { + waitForResult(); + return mDoubleArray; + } + public synchronized String[] waitForStringArray() { + waitForResult(); + return mStringArray; + } + public synchronized Object[] waitForObjectArray() { + waitForResult(); + return mObjectArray; + } + public synchronized CustomType[] waitForCustomTypeArray() { + waitForResult(); + return mCustomTypeArray; + } + } + + // Two custom types used when testing passing objects. + private class CustomType { + } + + private TestObject mTestObject; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestObject = new TestObject(); + setUpWebView(mTestObject, "testObject"); + } + + // Note that all tests use a single element array for simplicity. We test + // multiple elements elsewhere. + + // Test passing an array of JavaScript numbers in the int32 range to a + // method which takes a Java array. + public void testPassNumberInt32() throws Throwable { + executeJavaScript("testObject.setBooleanArray([0]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + // LIVECONNECT_COMPLIANCE: Should convert to boolean. + executeJavaScript("testObject.setBooleanArray([42]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + executeJavaScript("testObject.setByteArray([42]);"); + assertEquals(42, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should convert to numeric char value. + executeJavaScript("testObject.setCharArray([42]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + executeJavaScript("testObject.setShortArray([42]);"); + assertEquals(42, mTestObject.waitForShortArray()[0]); + + executeJavaScript("testObject.setIntArray([42]);"); + assertEquals(42, mTestObject.waitForIntArray()[0]); + + executeJavaScript("testObject.setLongArray([42]);"); + assertEquals(42L, mTestObject.waitForLongArray()[0]); + + executeJavaScript("testObject.setFloatArray([42]);"); + assertEquals(42.0f, mTestObject.waitForFloatArray()[0]); + + executeJavaScript("testObject.setDoubleArray([42]);"); + assertEquals(42.0, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number. + executeJavaScript("testObject.setObjectArray([42]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String. + executeJavaScript("testObject.setStringArray([42]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([42]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript numbers in the double range to a + // method which takes a Java array. + public void testPassNumberDouble() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should convert to boolean. + executeJavaScript("testObject.setBooleanArray([42.1]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + executeJavaScript("testObject.setByteArray([42.1]);"); + assertEquals(42, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should convert to numeric char value. + executeJavaScript("testObject.setCharArray([42.1]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + executeJavaScript("testObject.setShortArray([42.1]);"); + assertEquals(42, mTestObject.waitForShortArray()[0]); + + executeJavaScript("testObject.setIntArray([42.1]);"); + assertEquals(42, mTestObject.waitForIntArray()[0]); + + executeJavaScript("testObject.setLongArray([42.1]);"); + assertEquals(42L, mTestObject.waitForLongArray()[0]); + + executeJavaScript("testObject.setFloatArray([42.1]);"); + assertEquals(42.1f, mTestObject.waitForFloatArray()[0]); + + executeJavaScript("testObject.setDoubleArray([42.1]);"); + assertEquals(42.1, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number. + executeJavaScript("testObject.setObjectArray([42.1]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String. + executeJavaScript("testObject.setStringArray([42.1]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([42.1]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript NaN values to a method which takes a + // Java array. + public void testPassNumberNaN() throws Throwable { + executeJavaScript("testObject.setBooleanArray([Number.NaN]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + executeJavaScript("testObject.setByteArray([Number.NaN]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + executeJavaScript("testObject.setCharArray([Number.NaN]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + executeJavaScript("testObject.setShortArray([Number.NaN]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + executeJavaScript("testObject.setIntArray([Number.NaN]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + executeJavaScript("testObject.setLongArray([Number.NaN]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + executeJavaScript("testObject.setFloatArray([Number.NaN]);"); + assertEquals(Float.NaN, mTestObject.waitForFloatArray()[0]); + + executeJavaScript("testObject.setDoubleArray([Number.NaN]);"); + assertEquals(Double.NaN, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number. + executeJavaScript("testObject.setObjectArray([Number.NaN]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String. + executeJavaScript("testObject.setStringArray([Number.NaN]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([Number.NaN]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript infinity values to a method which + // takes a Java array. + public void testPassNumberInfinity() throws Throwable { + executeJavaScript("testObject.setBooleanArray([Infinity]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + executeJavaScript("testObject.setByteArray([Infinity]);"); + assertEquals(-1, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value. + executeJavaScript("testObject.setCharArray([Infinity]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + executeJavaScript("testObject.setShortArray([Infinity]);"); + assertEquals(-1, mTestObject.waitForShortArray()[0]); + + executeJavaScript("testObject.setIntArray([Infinity]);"); + assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE. + executeJavaScript("testObject.setLongArray([Infinity]);"); + assertEquals(-1L, mTestObject.waitForLongArray()[0]); + + executeJavaScript("testObject.setFloatArray([Infinity]);"); + assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatArray()[0]); + + executeJavaScript("testObject.setDoubleArray([Infinity]);"); + assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number. + executeJavaScript("testObject.setObjectArray([Infinity]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String. + executeJavaScript("testObject.setStringArray([Infinity]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([Infinity]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript boolean values to a method which + // takes a Java array. + public void testPassBoolean() throws Throwable { + executeJavaScript("testObject.setBooleanArray([true]);"); + assertTrue(mTestObject.waitForBooleanArray()[0]); + executeJavaScript("testObject.setBooleanArray([false]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setByteArray([true]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + executeJavaScript("testObject.setByteArray([false]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1. + executeJavaScript("testObject.setCharArray([true]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + executeJavaScript("testObject.setCharArray([false]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setShortArray([true]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + executeJavaScript("testObject.setShortArray([false]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setIntArray([true]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + executeJavaScript("testObject.setIntArray([false]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setLongArray([true]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + executeJavaScript("testObject.setLongArray([false]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be 1.0. + executeJavaScript("testObject.setFloatArray([true]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + executeJavaScript("testObject.setFloatArray([false]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should be 1.0. + executeJavaScript("testObject.setDoubleArray([true]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + executeJavaScript("testObject.setDoubleArray([false]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number. + executeJavaScript("testObject.setObjectArray([true]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should create instances of java.lang.String. + executeJavaScript("testObject.setStringArray([true]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([true]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript strings to a method which takes a + // Java array. + public void testPassString() throws Throwable { + // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true. + executeJavaScript("testObject.setBooleanArray([\"+042.10\"]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setByteArray([\"+042.10\"]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value. + executeJavaScript("testObject.setCharArray([\"+042.10\"]);"); + assertEquals(0, mTestObject.waitForCharArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setShortArray([\"+042.10\"]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setIntArray([\"+042.10\"]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setLongArray([\"+042.10\"]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setFloatArray([\"+042.10\"]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setDoubleArray([\"+042.10\"]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and create instances of java.lang.Number. + executeJavaScript("testObject.setObjectArray([\"+042.10\"]);"); + assertNull(mTestObject.waitForObjectArray()); + + executeJavaScript("testObject.setStringArray([\"+042.10\"]);"); + assertEquals("+042.10", mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([\"+042.10\"]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript objects to a method which takes a + // Java array. + public void testPassJavaScriptObject() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setBooleanArray([{foo: 42}]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setByteArray([{foo: 42}]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCharArray([{foo: 42}]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setShortArray([{foo: 42}]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setIntArray([{foo: 42}]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setLongArray([{foo: 42}]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setFloatArray([{foo: 42}]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setDoubleArray([{foo: 42}]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setObjectArray([{foo: 42}]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should call toString() on object. + executeJavaScript("testObject.setStringArray([{foo: 42}]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeArray([{foo: 42}]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of Java objects to a method which takes a Java + // array. + public void testPassJavaObject() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setBooleanArray([testObject.getObjectInstance()]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setByteArray([testObject.getObjectInstance()]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCharArray([testObject.getObjectInstance()]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setShortArray([testObject.getObjectInstance()]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setIntArray([testObject.getObjectInstance()]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setLongArray([testObject.getObjectInstance()]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setFloatArray([testObject.getObjectInstance()]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setDoubleArray([testObject.getObjectInstance()]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create an array and pass Java object. + executeJavaScript("testObject.setObjectArray([testObject.getObjectInstance()]);"); + assertNull(mTestObject.waitForObjectArray()); + + // LIVECONNECT_COMPLIANCE: Should call toString() on object. + executeJavaScript("testObject.setStringArray([testObject.getObjectInstance()]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and pass Java object. + executeJavaScript("testObject.setCustomTypeArray([testObject.getObjectInstance()]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + executeJavaScript("testObject.setCustomTypeArray([testObject.getCustomTypeInstance()]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript null values to a method which takes + // a Java array. + public void testPassNull() throws Throwable { + executeJavaScript("testObject.setByteArray([null]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + executeJavaScript("testObject.setCharArray([null]);"); + assertEquals('\u0000', mTestObject.waitForCharArray()[0]); + + executeJavaScript("testObject.setShortArray([null]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + executeJavaScript("testObject.setIntArray([null]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + executeJavaScript("testObject.setLongArray([null]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + executeJavaScript("testObject.setFloatArray([null]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + + executeJavaScript("testObject.setDoubleArray([null]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + + executeJavaScript("testObject.setBooleanArray([null]);"); + assertFalse(mTestObject.waitForBooleanArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and pass null. + executeJavaScript("testObject.setObjectArray([null]);"); + assertNull(mTestObject.waitForObjectArray()); + + executeJavaScript("testObject.setStringArray([null]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and pass null. + executeJavaScript("testObject.setCustomTypeArray([null]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } + + // Test passing an array of JavaScript undefined values to a method which + // takes a Java array. + public void testPassUndefined() throws Throwable { + executeJavaScript("testObject.setByteArray([undefined]);"); + assertEquals(0, mTestObject.waitForByteArray()[0]); + + executeJavaScript("testObject.setCharArray([undefined]);"); + assertEquals(0, mTestObject.waitForCharArray()[0]); + + executeJavaScript("testObject.setShortArray([undefined]);"); + assertEquals(0, mTestObject.waitForShortArray()[0]); + + executeJavaScript("testObject.setIntArray([undefined]);"); + assertEquals(0, mTestObject.waitForIntArray()[0]); + + executeJavaScript("testObject.setLongArray([undefined]);"); + assertEquals(0L, mTestObject.waitForLongArray()[0]); + + executeJavaScript("testObject.setFloatArray([undefined]);"); + assertEquals(0.0f, mTestObject.waitForFloatArray()[0]); + + executeJavaScript("testObject.setDoubleArray([undefined]);"); + assertEquals(0.0, mTestObject.waitForDoubleArray()[0]); + + executeJavaScript("testObject.setBooleanArray([undefined]);"); + assertEquals(false, mTestObject.waitForBooleanArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and pass null. + executeJavaScript("testObject.setObjectArray([undefined]);"); + assertNull(mTestObject.waitForObjectArray()); + + executeJavaScript("testObject.setStringArray([undefined]);"); + assertNull(mTestObject.waitForStringArray()[0]); + + // LIVECONNECT_COMPLIANCE: Should create array and pass null. + executeJavaScript("testObject.setCustomTypeArray([undefined]);"); + assertNull(mTestObject.waitForCustomTypeArray()); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayTest.java new file mode 100644 index 0000000..2fd42a7 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeArrayTest.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Part of the test suite for the WebView's Java Bridge. This class tests the + * general use of arrays. + * + * The conversions should follow + * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in + * which the implementation differs from the spec are marked with + * LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not + * break backwards-compatibility. See b/4408210. + * + * To run this test ... + * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeArrayTest \ + * com.android.webviewtests/android.test.InstrumentationTestRunner + */ + +package com.android.webviewtests; + +public class JavaBridgeArrayTest extends JavaBridgeTestBase { + private class TestObject extends Controller { + private boolean mBooleanValue; + private int mIntValue; + private String mStringValue; + + private int[] mIntArray; + private int[][] mIntIntArray; + + private boolean mWasArrayMethodCalled; + + public synchronized void setBooleanValue(boolean x) { + mBooleanValue = x; + notifyResultIsReady(); + } + public synchronized void setIntValue(int x) { + mIntValue = x; + notifyResultIsReady(); + } + public synchronized void setStringValue(String x) { + mStringValue = x; + notifyResultIsReady(); + } + + public synchronized boolean waitForBooleanValue() { + waitForResult(); + return mBooleanValue; + } + public synchronized int waitForIntValue() { + waitForResult(); + return mIntValue; + } + public synchronized String waitForStringValue() { + waitForResult(); + return mStringValue; + } + + public synchronized void setIntArray(int[] x) { + mIntArray = x; + notifyResultIsReady(); + } + public synchronized void setIntIntArray(int[][] x) { + mIntIntArray = x; + notifyResultIsReady(); + } + + public synchronized int[] waitForIntArray() { + waitForResult(); + return mIntArray; + } + public synchronized int[][] waitForIntIntArray() { + waitForResult(); + return mIntIntArray; + } + + public synchronized int[] arrayMethod() { + mWasArrayMethodCalled = true; + return new int[] {42, 43, 44}; + } + + public synchronized boolean wasArrayMethodCalled() { + return mWasArrayMethodCalled; + } + } + + private TestObject mTestObject; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestObject = new TestObject(); + setUpWebView(mTestObject, "testObject"); + } + + public void testArrayLength() throws Throwable { + executeJavaScript("testObject.setIntArray([42, 43, 44]);"); + int[] result = mTestObject.waitForIntArray(); + assertEquals(3, result.length); + assertEquals(42, result[0]); + assertEquals(43, result[1]); + assertEquals(44, result[2]); + } + + public void testPassNull() throws Throwable { + executeJavaScript("testObject.setIntArray(null);"); + assertNull(mTestObject.waitForIntArray()); + } + + public void testPassUndefined() throws Throwable { + executeJavaScript("testObject.setIntArray(undefined);"); + assertNull(mTestObject.waitForIntArray()); + } + + public void testPassEmptyArray() throws Throwable { + executeJavaScript("testObject.setIntArray([]);"); + assertEquals(0, mTestObject.waitForIntArray().length); + } + + // Note that this requires being able to pass a string from JavaScript to + // Java. + public void testPassArrayToStringMethod() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should call toString() on array. + executeJavaScript("testObject.setStringValue([42, 42, 42]);"); + assertEquals("undefined", mTestObject.waitForStringValue()); + } + + // Note that this requires being able to pass an integer from JavaScript to + // Java. + public void testPassArrayToNonStringNonArrayMethod() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception. + executeJavaScript("testObject.setIntValue([42, 42, 42]);"); + assertEquals(0, mTestObject.waitForIntValue()); + } + + public void testPassNonArrayToArrayMethod() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should raise JavaScript exception. + executeJavaScript("testObject.setIntArray(42);"); + assertNull(mTestObject.waitForIntArray()); + } + + public void testObjectWithLengthProperty() throws Throwable { + executeJavaScript("testObject.setIntArray({length: 3, 1: 42});"); + int[] result = mTestObject.waitForIntArray(); + assertEquals(3, result.length); + assertEquals(0, result[0]); + assertEquals(42, result[1]); + assertEquals(0, result[2]); + } + + public void testNonNumericLengthProperty() throws Throwable { + // LIVECONNECT_COMPLIANCE: This should not count as an array, so we + // should raise a JavaScript exception. + executeJavaScript("testObject.setIntArray({length: \"foo\"});"); + assertNull(mTestObject.waitForIntArray()); + } + + public void testLengthOutOfBounds() throws Throwable { + // LIVECONNECT_COMPLIANCE: This should not count as an array, so we + // should raise a JavaScript exception. + executeJavaScript("testObject.setIntArray({length: -1});"); + assertNull(mTestObject.waitForIntArray()); + + // LIVECONNECT_COMPLIANCE: This should not count as an array, so we + // should raise a JavaScript exception. + long length = (long)Integer.MAX_VALUE + 1L; + executeJavaScript("testObject.setIntArray({length: " + length + "});"); + assertNull(mTestObject.waitForIntArray()); + + // LIVECONNECT_COMPLIANCE: This should not count as an array, so we + // should raise a JavaScript exception. + length = (long)Integer.MAX_VALUE + 1L - (long)Integer.MIN_VALUE + 1L; + executeJavaScript("testObject.setIntArray({length: " + length + "});"); + assertNull(mTestObject.waitForIntArray()); + } + + public void testSparseArray() throws Throwable { + executeJavaScript("var x = [42, 43]; x[3] = 45; testObject.setIntArray(x);"); + int[] result = mTestObject.waitForIntArray(); + assertEquals(4, result.length); + assertEquals(42, result[0]); + assertEquals(43, result[1]); + assertEquals(0, result[2]); + assertEquals(45, result[3]); + } + + // Note that this requires being able to pass a boolean from JavaScript to + // Java. + public void testMethodReturningArrayNotCalled() throws Throwable { + // We don't invoke methods which return arrays, but note that no + // exception is raised. + // LIVECONNECT_COMPLIANCE: Should call method and convert result to + // JavaScript array. + executeJavaScript("testObject.setBooleanValue(undefined === testObject.arrayMethod())"); + assertTrue(mTestObject.waitForBooleanValue()); + assertFalse(mTestObject.wasArrayMethodCalled()); + } + + public void testMultiDimensionalArrayMethod() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays. + executeJavaScript("testObject.setIntIntArray([ [42, 43], [44, 45] ]);"); + assertNull(mTestObject.waitForIntIntArray()); + } + + public void testPassMultiDimensionalArray() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should handle multi-dimensional arrays. + executeJavaScript("testObject.setIntArray([ [42, 43], [44, 45] ]);"); + int[] result = mTestObject.waitForIntArray(); + assertEquals(2, result.length); + assertEquals(0, result[0]); + assertEquals(0, result[1]); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java new file mode 100644 index 0000000..c9bbb77 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeBasicsTest.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Part of the test suite for the WebView's Java Bridge. Tests a number of features including ... + * - The type of injected objects + * - The type of their methods + * - Replacing objects + * - Removing objects + * - Access control + * - Calling methods on returned objects + * - Multiply injected objects + * - Threading + * - Inheritance + * + * To run this test ... + * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeBasicsTest \ + * com.android.webviewtests/android.test.InstrumentationTestRunner + */ + +package com.android.webviewtests; + +public class JavaBridgeBasicsTest extends JavaBridgeTestBase { + private class TestController extends Controller { + private int mIntValue; + private long mLongValue; + private String mStringValue; + private boolean mBooleanValue; + + public synchronized void setIntValue(int x) { + mIntValue = x; + notifyResultIsReady(); + } + public synchronized void setLongValue(long x) { + mLongValue = x; + notifyResultIsReady(); + } + public synchronized void setStringValue(String x) { + mStringValue = x; + notifyResultIsReady(); + } + public synchronized void setBooleanValue(boolean x) { + mBooleanValue = x; + notifyResultIsReady(); + } + + public synchronized int waitForIntValue() { + waitForResult(); + return mIntValue; + } + public synchronized long waitForLongValue() { + waitForResult(); + return mLongValue; + } + public synchronized String waitForStringValue() { + waitForResult(); + return mStringValue; + } + public synchronized boolean waitForBooleanValue() { + waitForResult(); + return mBooleanValue; + } + } + + private static class ObjectWithStaticMethod { + public static String staticMethod() { + return "foo"; + } + } + + TestController mTestController; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestController = new TestController(); + setUpWebView(mTestController, "testController"); + } + + // Note that this requires that we can pass a JavaScript string to Java. + protected String executeJavaScriptAndGetStringResult(String script) throws Throwable { + executeJavaScript("testController.setStringValue(" + script + ");"); + return mTestController.waitForStringValue(); + } + + protected void injectObjectAndReload(final Object object, final String name) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().addJavascriptInterface(object, name); + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + } + + // Note that this requires that we can pass a JavaScript boolean to Java. + private void assertRaisesException(String script) throws Throwable { + executeJavaScript("try {" + + script + ";" + + " testController.setBooleanValue(false);" + + "} catch (exception) {" + + " testController.setBooleanValue(true);" + + "}"); + assertTrue(mTestController.waitForBooleanValue()); + } + + public void testTypeOfInjectedObject() throws Throwable { + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); + } + + public void testAdditionNotReflectedUntilReload() throws Throwable { + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().addJavascriptInterface(new Object(), "testObject"); + } + }); + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + } + + public void testRemovalNotReflectedUntilReload() throws Throwable { + injectObjectAndReload(new Object(), "testObject"); + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().removeJavascriptInterface("testObject"); + } + }); + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); + } + + public void testRemoveObjectNotAdded() throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().removeJavascriptInterface("foo"); + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof foo")); + } + + public void testTypeOfMethod() throws Throwable { + assertEquals("function", + executeJavaScriptAndGetStringResult("typeof testController.setStringValue")); + } + + public void testTypeOfInvalidMethod() throws Throwable { + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testController.foo")); + } + + public void testCallingInvalidMethodRaisesException() throws Throwable { + assertRaisesException("testController.foo()"); + } + + // Note that this requires that we can pass a JavaScript string to Java. + public void testTypeOfStaticMethod() throws Throwable { + injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); + executeJavaScript("testController.setStringValue(typeof testObject.staticMethod)"); + assertEquals("function", mTestController.waitForStringValue()); + } + + // Note that this requires that we can pass a JavaScript string to Java. + public void testCallStaticMethod() throws Throwable { + injectObjectAndReload(new ObjectWithStaticMethod(), "testObject"); + executeJavaScript("testController.setStringValue(testObject.staticMethod())"); + assertEquals("foo", mTestController.waitForStringValue()); + } + + public void testPrivateMethodNotExposed() throws Throwable { + injectObjectAndReload(new Object() { + private void method() {} + }, "testObject"); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.method")); + } + + public void testReplaceInjectedObject() throws Throwable { + injectObjectAndReload(new Object() { + public void method() { mTestController.setStringValue("object 1"); } + }, "testObject"); + executeJavaScript("testObject.method()"); + assertEquals("object 1", mTestController.waitForStringValue()); + + injectObjectAndReload(new Object() { + public void method() { mTestController.setStringValue("object 2"); } + }, "testObject"); + executeJavaScript("testObject.method()"); + assertEquals("object 2", mTestController.waitForStringValue()); + } + + public void testInjectNullObjectIsIgnored() throws Throwable { + injectObjectAndReload(null, "testObject"); + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); + } + + public void testReplaceInjectedObjectWithNullObjectIsIgnored() throws Throwable { + injectObjectAndReload(new Object(), "testObject"); + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + injectObjectAndReload(null, "testObject"); + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + } + + public void testCallOverloadedMethodWithDifferentNumberOfArguments() throws Throwable { + injectObjectAndReload(new Object() { + public void method() { mTestController.setStringValue("0 args"); } + public void method(int x) { mTestController.setStringValue("1 arg"); } + public void method(int x, int y) { mTestController.setStringValue("2 args"); } + }, "testObject"); + executeJavaScript("testObject.method()"); + assertEquals("0 args", mTestController.waitForStringValue()); + executeJavaScript("testObject.method(42)"); + assertEquals("1 arg", mTestController.waitForStringValue()); + executeJavaScript("testObject.method(null)"); + assertEquals("1 arg", mTestController.waitForStringValue()); + executeJavaScript("testObject.method(undefined)"); + assertEquals("1 arg", mTestController.waitForStringValue()); + executeJavaScript("testObject.method(42, 42)"); + assertEquals("2 args", mTestController.waitForStringValue()); + } + + public void testCallMethodWithWrongNumberOfArgumentsRaisesException() throws Throwable { + assertRaisesException("testController.setIntValue()"); + assertRaisesException("testController.setIntValue(42, 42)"); + } + + public void testObjectPersistsAcrossPageLoads() throws Throwable { + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + assertEquals("object", executeJavaScriptAndGetStringResult("typeof testController")); + } + + public void testSameObjectInjectedMultipleTimes() throws Throwable { + class TestObject { + private int mNumMethodInvocations; + public void method() { mTestController.setIntValue(++mNumMethodInvocations); } + } + final TestObject testObject = new TestObject(); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().addJavascriptInterface(testObject, "testObject1"); + getWebView().addJavascriptInterface(testObject, "testObject2"); + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + executeJavaScript("testObject1.method()"); + assertEquals(1, mTestController.waitForIntValue()); + executeJavaScript("testObject2.method()"); + assertEquals(2, mTestController.waitForIntValue()); + } + + public void testCallMethodOnReturnedObject() throws Throwable { + injectObjectAndReload(new Object() { + public Object getInnerObject() { + return new Object() { + public void method(int x) { mTestController.setIntValue(x); } + }; + } + }, "testObject"); + executeJavaScript("testObject.getInnerObject().method(42)"); + assertEquals(42, mTestController.waitForIntValue()); + } + + public void testReturnedObjectInjectedElsewhere() throws Throwable { + class InnerObject { + private int mNumMethodInvocations; + public void method() { mTestController.setIntValue(++mNumMethodInvocations); } + } + final InnerObject innerObject = new InnerObject(); + final Object object = new Object() { + public InnerObject getInnerObject() { + return innerObject; + } + }; + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().addJavascriptInterface(object, "testObject"); + getWebView().addJavascriptInterface(innerObject, "innerObject"); + getWebView().reload(); + } + }); + mWebViewClient.waitForOnPageFinished(); + executeJavaScript("testObject.getInnerObject().method()"); + assertEquals(1, mTestController.waitForIntValue()); + executeJavaScript("innerObject.method()"); + assertEquals(2, mTestController.waitForIntValue()); + } + + public void testMethodInvokedOnBackgroundThread() throws Throwable { + injectObjectAndReload(new Object() { + public void captureThreadId() { + mTestController.setLongValue(Thread.currentThread().getId()); + } + }, "testObject"); + executeJavaScript("testObject.captureThreadId()"); + final long threadId = mTestController.waitForLongValue(); + assertFalse(threadId == Thread.currentThread().getId()); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertFalse(threadId == Thread.currentThread().getId()); + } + }); + } + + public void testPublicInheritedMethod() throws Throwable { + class Base { + public void method(int x) { mTestController.setIntValue(x); } + } + class Derived extends Base { + } + injectObjectAndReload(new Derived(), "testObject"); + assertEquals("function", executeJavaScriptAndGetStringResult("typeof testObject.method")); + executeJavaScript("testObject.method(42)"); + assertEquals(42, mTestController.waitForIntValue()); + } + + public void testPrivateInheritedMethod() throws Throwable { + class Base { + private void method() {} + } + class Derived extends Base { + } + injectObjectAndReload(new Derived(), "testObject"); + assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject.method")); + } + + public void testOverriddenMethod() throws Throwable { + class Base { + public void method() { mTestController.setStringValue("base"); } + } + class Derived extends Base { + public void method() { mTestController.setStringValue("derived"); } + } + injectObjectAndReload(new Derived(), "testObject"); + executeJavaScript("testObject.method()"); + assertEquals("derived", mTestController.waitForStringValue()); + } + + public void testEnumerateMembers() throws Throwable { + injectObjectAndReload(new Object() { + public void method() {} + private void privateMethod() {} + public int field; + private int privateField; + }, "testObject"); + executeJavaScript( + "var result = \"\"; " + + "for (x in testObject) { result += \" \" + x } " + + "testController.setStringValue(result);"); + // LIVECONNECT_COMPLIANCE: Should be able to enumerate members. + assertEquals("", mTestController.waitForStringValue()); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java new file mode 100644 index 0000000..a0f78a4 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeCoercionTest.java @@ -0,0 +1,646 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Part of the test suite for the WebView's Java Bridge. This class tests that + * we correctly convert JavaScript values to Java values when passing them to + * the methods of injected Java objects. + * + * The conversions should follow + * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in + * which the implementation differs from the spec are marked with + * LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not + * break backwards-compatibility. See b/4408210. + * + * To run this test ... + * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeCoercionTest \ + * com.android.webviewtests/android.test.InstrumentationTestRunner + */ + +package com.android.webviewtests; + +public class JavaBridgeCoercionTest extends JavaBridgeTestBase { + private class TestObject extends Controller { + private Object objectInstance; + private CustomType customTypeInstance; + private CustomType2 customType2Instance; + + private boolean mBooleanValue; + private byte mByteValue; + private char mCharValue; + private short mShortValue; + private int mIntValue; + private long mLongValue; + private float mFloatValue; + private double mDoubleValue; + private String mStringValue; + private Object mObjectValue; + private CustomType mCustomTypeValue; + + public TestObject() { + objectInstance = new Object(); + customTypeInstance = new CustomType(); + customType2Instance = new CustomType2(); + } + + public Object getObjectInstance() { + return objectInstance; + } + public CustomType getCustomTypeInstance() { + return customTypeInstance; + } + public CustomType2 getCustomType2Instance() { + return customType2Instance; + } + + public synchronized void setBooleanValue(boolean x) { + mBooleanValue = x; + notifyResultIsReady(); + } + public synchronized void setByteValue(byte x) { + mByteValue = x; + notifyResultIsReady(); + } + public synchronized void setCharValue(char x) { + mCharValue = x; + notifyResultIsReady(); + } + public synchronized void setShortValue(short x) { + mShortValue = x; + notifyResultIsReady(); + } + public synchronized void setIntValue(int x) { + mIntValue = x; + notifyResultIsReady(); + } + public synchronized void setLongValue(long x) { + mLongValue = x; + notifyResultIsReady(); + } + public synchronized void setFloatValue(float x) { + mFloatValue = x; + notifyResultIsReady(); + } + public synchronized void setDoubleValue(double x) { + mDoubleValue = x; + notifyResultIsReady(); + } + public synchronized void setStringValue(String x) { + mStringValue = x; + notifyResultIsReady(); + } + public synchronized void setObjectValue(Object x) { + mObjectValue = x; + notifyResultIsReady(); + } + public synchronized void setCustomTypeValue(CustomType x) { + mCustomTypeValue = x; + notifyResultIsReady(); + } + + public synchronized boolean waitForBooleanValue() { + waitForResult(); + return mBooleanValue; + } + public synchronized byte waitForByteValue() { + waitForResult(); + return mByteValue; + } + public synchronized char waitForCharValue() { + waitForResult(); + return mCharValue; + } + public synchronized short waitForShortValue() { + waitForResult(); + return mShortValue; + } + public synchronized int waitForIntValue() { + waitForResult(); + return mIntValue; + } + public synchronized long waitForLongValue() { + waitForResult(); + return mLongValue; + } + public synchronized float waitForFloatValue() { + waitForResult(); + return mFloatValue; + } + public synchronized double waitForDoubleValue() { + waitForResult(); + return mDoubleValue; + } + public synchronized String waitForStringValue() { + waitForResult(); + return mStringValue; + } + public synchronized Object waitForObjectValue() { + waitForResult(); + return mObjectValue; + } + public synchronized CustomType waitForCustomTypeValue() { + waitForResult(); + return mCustomTypeValue; + } + } + + // Two custom types used when testing passing objects. + private static class CustomType { + } + private static class CustomType2 { + } + + private TestObject mTestObject; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestObject = new TestObject(); + setUpWebView(mTestObject, "testObject"); + } + + // Test passing a JavaScript number in the int32 range to a method of an + // injected object. + public void testPassNumberInt32() throws Throwable { + executeJavaScript("testObject.setByteValue(42);"); + assertEquals(42, mTestObject.waitForByteValue()); + executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42);"); + assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should convert to numeric char value. + executeJavaScript("testObject.setCharValue(42);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + executeJavaScript("testObject.setShortValue(42);"); + assertEquals(42, mTestObject.waitForShortValue()); + executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42);"); + assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue()); + + executeJavaScript("testObject.setIntValue(42);"); + assertEquals(42, mTestObject.waitForIntValue()); + + executeJavaScript("testObject.setLongValue(42);"); + assertEquals(42L, mTestObject.waitForLongValue()); + + executeJavaScript("testObject.setFloatValue(42);"); + assertEquals(42.0f, mTestObject.waitForFloatValue()); + + executeJavaScript("testObject.setDoubleValue(42);"); + assertEquals(42.0, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number. + executeJavaScript("testObject.setObjectValue(42);"); + assertNull(mTestObject.waitForObjectValue()); + + // The spec allows the JS engine flexibility in how to format the number. + executeJavaScript("testObject.setStringValue(42);"); + String str = mTestObject.waitForStringValue(); + assertTrue("42".equals(str) || "42.0".equals(str)); + + executeJavaScript("testObject.setBooleanValue(0);"); + assertFalse(mTestObject.waitForBooleanValue()); + // LIVECONNECT_COMPLIANCE: Should be true; + executeJavaScript("testObject.setBooleanValue(42);"); + assertFalse(mTestObject.waitForBooleanValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue(42);"); + assertNull(mTestObject.waitForCustomTypeValue()); + } + + // Test passing a JavaScript number in the double range to a method of an + // injected object. + public void testPassNumberDouble() throws Throwable { + executeJavaScript("testObject.setByteValue(42.1);"); + assertEquals(42, mTestObject.waitForByteValue()); + executeJavaScript("testObject.setByteValue(" + Byte.MAX_VALUE + " + 42.1);"); + assertEquals(Byte.MIN_VALUE + 42 - 1, mTestObject.waitForByteValue()); + executeJavaScript("testObject.setByteValue(" + Integer.MAX_VALUE + " + 42.1);"); + assertEquals(-1, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should convert to numeric char value. + executeJavaScript("testObject.setCharValue(42.1);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + executeJavaScript("testObject.setShortValue(42.1);"); + assertEquals(42, mTestObject.waitForShortValue()); + executeJavaScript("testObject.setShortValue(" + Short.MAX_VALUE + " + 42.1);"); + assertEquals(Short.MIN_VALUE + 42 - 1, mTestObject.waitForShortValue()); + executeJavaScript("testObject.setShortValue(" + Integer.MAX_VALUE + " + 42.1);"); + assertEquals(-1, mTestObject.waitForShortValue()); + + executeJavaScript("testObject.setIntValue(42.1);"); + assertEquals(42, mTestObject.waitForIntValue()); + executeJavaScript("testObject.setIntValue(" + Integer.MAX_VALUE + " + 42.1);"); + assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue()); + + executeJavaScript("testObject.setLongValue(42.1);"); + assertEquals(42L, mTestObject.waitForLongValue()); + // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE. + executeJavaScript("testObject.setLongValue(" + Long.MAX_VALUE + " + 42.1);"); + assertEquals(Long.MIN_VALUE, mTestObject.waitForLongValue()); + + executeJavaScript("testObject.setFloatValue(42.1);"); + assertEquals(42.1f, mTestObject.waitForFloatValue()); + + executeJavaScript("testObject.setDoubleValue(42.1);"); + assertEquals(42.1, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number. + executeJavaScript("testObject.setObjectValue(42.1);"); + assertNull(mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setStringValue(42.1);"); + assertEquals("42.1", mTestObject.waitForStringValue()); + + executeJavaScript("testObject.setBooleanValue(0.0);"); + assertFalse(mTestObject.waitForBooleanValue()); + // LIVECONNECT_COMPLIANCE: Should be true. + executeJavaScript("testObject.setBooleanValue(42.1);"); + assertFalse(mTestObject.waitForBooleanValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue(42.1);"); + assertNull(mTestObject.waitForCustomTypeValue()); + } + + // Test passing JavaScript NaN to a method of an injected object. + public void testPassNumberNaN() throws Throwable { + executeJavaScript("testObject.setByteValue(Number.NaN);"); + assertEquals(0, mTestObject.waitForByteValue()); + + executeJavaScript("testObject.setCharValue(Number.NaN);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + executeJavaScript("testObject.setShortValue(Number.NaN);"); + assertEquals(0, mTestObject.waitForShortValue()); + + executeJavaScript("testObject.setIntValue(Number.NaN);"); + assertEquals(0, mTestObject.waitForIntValue()); + + executeJavaScript("testObject.setLongValue(Number.NaN);"); + assertEquals(0L, mTestObject.waitForLongValue()); + + executeJavaScript("testObject.setFloatValue(Number.NaN);"); + assertEquals(Float.NaN, mTestObject.waitForFloatValue()); + + executeJavaScript("testObject.setDoubleValue(Number.NaN);"); + assertEquals(Double.NaN, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number. + executeJavaScript("testObject.setObjectValue(Number.NaN);"); + assertNull(mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setStringValue(Number.NaN);"); + assertEquals("NaN", mTestObject.waitForStringValue()); + + executeJavaScript("testObject.setBooleanValue(Number.NaN);"); + assertFalse(mTestObject.waitForBooleanValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue(Number.NaN);"); + assertNull(mTestObject.waitForCustomTypeValue()); + } + + // Test passing JavaScript infinity to a method of an injected object. + public void testPassNumberInfinity() throws Throwable { + executeJavaScript("testObject.setByteValue(Infinity);"); + assertEquals(-1, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should convert to maximum numeric char value. + executeJavaScript("testObject.setCharValue(Infinity);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + executeJavaScript("testObject.setShortValue(Infinity);"); + assertEquals(-1, mTestObject.waitForShortValue()); + + executeJavaScript("testObject.setIntValue(Infinity);"); + assertEquals(Integer.MAX_VALUE, mTestObject.waitForIntValue()); + + // LIVECONNECT_COMPLIANCE: Should be Long.MAX_VALUE. + executeJavaScript("testObject.setLongValue(Infinity);"); + assertEquals(-1L, mTestObject.waitForLongValue()); + + executeJavaScript("testObject.setFloatValue(Infinity);"); + assertEquals(Float.POSITIVE_INFINITY, mTestObject.waitForFloatValue()); + + executeJavaScript("testObject.setDoubleValue(Infinity);"); + assertEquals(Double.POSITIVE_INFINITY, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Number. + executeJavaScript("testObject.setObjectValue(Infinity);"); + assertNull(mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setStringValue(Infinity);"); + assertEquals("Inf", mTestObject.waitForStringValue()); + + executeJavaScript("testObject.setBooleanValue(Infinity);"); + assertFalse(mTestObject.waitForBooleanValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue(Infinity);"); + assertNull(mTestObject.waitForCustomTypeValue()); + } + + // Test passing a JavaScript boolean to a method of an injected object. + public void testPassBoolean() throws Throwable { + executeJavaScript("testObject.setBooleanValue(true);"); + assertTrue(mTestObject.waitForBooleanValue()); + executeJavaScript("testObject.setBooleanValue(false);"); + assertFalse(mTestObject.waitForBooleanValue()); + + // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.Boolean. + executeJavaScript("testObject.setObjectValue(true);"); + assertNull(mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setStringValue(false);"); + assertEquals("false", mTestObject.waitForStringValue()); + executeJavaScript("testObject.setStringValue(true);"); + assertEquals("true", mTestObject.waitForStringValue()); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setByteValue(true);"); + assertEquals(0, mTestObject.waitForByteValue()); + executeJavaScript("testObject.setByteValue(false);"); + assertEquals(0, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should convert to numeric char value 1. + executeJavaScript("testObject.setCharValue(true);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + executeJavaScript("testObject.setCharValue(false);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setShortValue(true);"); + assertEquals(0, mTestObject.waitForShortValue()); + executeJavaScript("testObject.setShortValue(false);"); + assertEquals(0, mTestObject.waitForShortValue()); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setIntValue(true);"); + assertEquals(0, mTestObject.waitForIntValue()); + executeJavaScript("testObject.setIntValue(false);"); + assertEquals(0, mTestObject.waitForIntValue()); + + // LIVECONNECT_COMPLIANCE: Should be 1. + executeJavaScript("testObject.setLongValue(true);"); + assertEquals(0L, mTestObject.waitForLongValue()); + executeJavaScript("testObject.setLongValue(false);"); + assertEquals(0L, mTestObject.waitForLongValue()); + + // LIVECONNECT_COMPLIANCE: Should be 1.0. + executeJavaScript("testObject.setFloatValue(true);"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + executeJavaScript("testObject.setFloatValue(false);"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + + // LIVECONNECT_COMPLIANCE: Should be 1.0. + executeJavaScript("testObject.setDoubleValue(true);"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + executeJavaScript("testObject.setDoubleValue(false);"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue(true);"); + assertNull(mTestObject.waitForCustomTypeValue()); + } + + // Test passing a JavaScript string to a method of an injected object. + public void testPassString() throws Throwable { + executeJavaScript("testObject.setStringValue(\"+042.10\");"); + assertEquals("+042.10", mTestObject.waitForStringValue()); + + // Make sure that we distinguish between the empty string and NULL. + executeJavaScript("testObject.setStringValue(\"\");"); + assertEquals("", mTestObject.waitForStringValue()); + + // LIVECONNECT_COMPLIANCE: Should create an instance of java.lang.String. + executeJavaScript("testObject.setObjectValue(\"+042.10\");"); + assertNull(mTestObject.waitForObjectValue()); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setByteValue(\"+042.10\");"); + assertEquals(0, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setShortValue(\"+042.10\");"); + assertEquals(0, mTestObject.waitForShortValue()); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setIntValue(\"+042.10\");"); + assertEquals(0, mTestObject.waitForIntValue()); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setLongValue(\"+042.10\");"); + assertEquals(0L, mTestObject.waitForLongValue()); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setFloatValue(\"+042.10\");"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + + // LIVECONNECT_COMPLIANCE: Should use valueOf() of appropriate type. + executeJavaScript("testObject.setDoubleValue(\"+042.10\");"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should decode and convert to numeric char value. + executeJavaScript("testObject.setCharValue(\"+042.10\");"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + // LIVECONNECT_COMPLIANCE: Non-empty string should convert to true. + executeJavaScript("testObject.setBooleanValue(\"+042.10\");"); + assertFalse(mTestObject.waitForBooleanValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue(\"+042.10\");"); + assertNull(mTestObject.waitForCustomTypeValue()); + } + + // Test passing a JavaScript object to a method of an injected object. + public void testPassJavaScriptObject() throws Throwable { + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setObjectValue({foo: 42});"); + assertNull(mTestObject.waitForObjectValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCustomTypeValue({foo: 42});"); + assertNull(mTestObject.waitForCustomTypeValue()); + + // LIVECONNECT_COMPLIANCE: Should call toString() on object. + executeJavaScript("testObject.setStringValue({foo: 42});"); + assertEquals("undefined", mTestObject.waitForStringValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setByteValue({foo: 42});"); + assertEquals(0, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCharValue({foo: 42});"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setShortValue({foo: 42});"); + assertEquals(0, mTestObject.waitForShortValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setIntValue({foo: 42});"); + assertEquals(0, mTestObject.waitForIntValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setLongValue({foo: 42});"); + assertEquals(0L, mTestObject.waitForLongValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setFloatValue({foo: 42});"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setDoubleValue({foo: 42});"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setBooleanValue({foo: 42});"); + assertFalse(mTestObject.waitForBooleanValue()); + } + + // Test passing a Java object to a method of an injected object. Note that + // this test requires being able to return objects from the methods of + // injected objects. This is tested elsewhere. + public void testPassJavaObject() throws Throwable { + executeJavaScript("testObject.setObjectValue(testObject.getObjectInstance());"); + assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForObjectValue()); + executeJavaScript("testObject.setObjectValue(testObject.getCustomTypeInstance());"); + assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setCustomTypeValue(testObject.getObjectInstance());"); + assertTrue(mTestObject.getObjectInstance() == mTestObject.waitForCustomTypeValue()); + executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomTypeInstance());"); + assertTrue(mTestObject.getCustomTypeInstance() == mTestObject.waitForCustomTypeValue()); + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception, as the types are unrelated. + executeJavaScript("testObject.setCustomTypeValue(testObject.getCustomType2Instance());"); + assertTrue(mTestObject.getCustomType2Instance() == + (Object)mTestObject.waitForCustomTypeValue()); + + // LIVECONNECT_COMPLIANCE: Should call toString() on object. + executeJavaScript("testObject.setStringValue(testObject.getObjectInstance());"); + assertEquals("undefined", mTestObject.waitForStringValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setByteValue(testObject.getObjectInstance());"); + assertEquals(0, mTestObject.waitForByteValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setCharValue(testObject.getObjectInstance());"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setShortValue(testObject.getObjectInstance());"); + assertEquals(0, mTestObject.waitForShortValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setIntValue(testObject.getObjectInstance());"); + assertEquals(0, mTestObject.waitForIntValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setLongValue(testObject.getObjectInstance());"); + assertEquals(0L, mTestObject.waitForLongValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setFloatValue(testObject.getObjectInstance());"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setDoubleValue(testObject.getObjectInstance());"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + + // LIVECONNECT_COMPLIANCE: Should raise a JavaScript exception. + executeJavaScript("testObject.setBooleanValue(testObject.getObjectInstance());"); + assertFalse(mTestObject.waitForBooleanValue()); + } + + // Test passing JavaScript null to a method of an injected object. + public void testPassNull() throws Throwable { + executeJavaScript("testObject.setObjectValue(null);"); + assertNull(mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setCustomTypeValue(null);"); + assertNull(mTestObject.waitForCustomTypeValue()); + + executeJavaScript("testObject.setStringValue(null);"); + assertNull(mTestObject.waitForStringValue()); + + executeJavaScript("testObject.setByteValue(null);"); + assertEquals(0, mTestObject.waitForByteValue()); + + executeJavaScript("testObject.setCharValue(null);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + executeJavaScript("testObject.setShortValue(null);"); + assertEquals(0, mTestObject.waitForShortValue()); + + executeJavaScript("testObject.setIntValue(null);"); + assertEquals(0, mTestObject.waitForIntValue()); + + executeJavaScript("testObject.setLongValue(null);"); + assertEquals(0L, mTestObject.waitForLongValue()); + + executeJavaScript("testObject.setFloatValue(null);"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + + executeJavaScript("testObject.setDoubleValue(null);"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + + executeJavaScript("testObject.setBooleanValue(null);"); + assertFalse(mTestObject.waitForBooleanValue()); + } + + // Test passing JavaScript undefined to a method of an injected object. + public void testPassUndefined() throws Throwable { + executeJavaScript("testObject.setObjectValue(undefined);"); + assertNull(mTestObject.waitForObjectValue()); + + executeJavaScript("testObject.setCustomTypeValue(undefined);"); + assertNull(mTestObject.waitForCustomTypeValue()); + + // LIVECONNECT_COMPLIANCE: Should be NULL. + executeJavaScript("testObject.setStringValue(undefined);"); + assertEquals("undefined", mTestObject.waitForStringValue()); + + executeJavaScript("testObject.setByteValue(undefined);"); + assertEquals(0, mTestObject.waitForByteValue()); + + executeJavaScript("testObject.setCharValue(undefined);"); + assertEquals('\u0000', mTestObject.waitForCharValue()); + + executeJavaScript("testObject.setShortValue(undefined);"); + assertEquals(0, mTestObject.waitForShortValue()); + + executeJavaScript("testObject.setIntValue(undefined);"); + assertEquals(0, mTestObject.waitForIntValue()); + + executeJavaScript("testObject.setLongValue(undefined);"); + assertEquals(0L, mTestObject.waitForLongValue()); + + executeJavaScript("testObject.setFloatValue(undefined);"); + assertEquals(0.0f, mTestObject.waitForFloatValue()); + + executeJavaScript("testObject.setDoubleValue(undefined);"); + assertEquals(0.0, mTestObject.waitForDoubleValue()); + + executeJavaScript("testObject.setBooleanValue(undefined);"); + assertFalse(mTestObject.waitForBooleanValue()); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java new file mode 100644 index 0000000..0ccd175 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeFieldsTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Part of the test suite for the WebView's Java Bridge. This test tests the + * use of fields. + * + * To run this test ... + * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeFieldsTest \ + * com.android.webviewtests/android.test.InstrumentationTestRunner + */ + +package com.android.webviewtests; + +public class JavaBridgeFieldsTest extends JavaBridgeTestBase { + private class TestObject extends Controller { + private String mStringValue; + + // These methods are used to control the test. + public synchronized void setStringValue(String x) { + mStringValue = x; + notifyResultIsReady(); + } + public synchronized String waitForStringValue() { + waitForResult(); + return mStringValue; + } + + public boolean booleanField = true; + public byte byteField = 42; + public char charField = '\u002A'; + public short shortField = 42; + public int intField = 42; + public long longField = 42L; + public float floatField = 42.0f; + public double doubleField = 42.0; + public String stringField = "foo"; + public Object objectField = new Object(); + public CustomType customTypeField = new CustomType(); + } + + // A custom type used when testing passing objects. + private class CustomType { + } + + TestObject mTestObject; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestObject = new TestObject(); + setUpWebView(mTestObject, "testObject"); + } + + // Note that this requires that we can pass a JavaScript string to Java. + protected String executeJavaScriptAndGetStringResult(String script) throws Throwable { + executeJavaScript("testObject.setStringValue(" + script + ");"); + return mTestObject.waitForStringValue(); + } + + // The Java bridge does not provide access to fields. + // FIXME: Consider providing support for this. See See b/4408210. + public void testFieldTypes() throws Throwable { + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.booleanField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.byteField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.charField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.shortField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.intField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.longField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.floatField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.doubleField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.objectField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.stringField")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.customTypeField")); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java new file mode 100644 index 0000000..44d5cc6 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeReturnValuesTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Part of the test suite for the WebView's Java Bridge. This test checks that + * we correctly convert Java values to JavaScript values when returning them + * from the methods of injected Java objects. + * + * The conversions should follow + * http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS. Places in + * which the implementation differs from the spec are marked with + * LIVECONNECT_COMPLIANCE. + * FIXME: Consider making our implementation more compliant, if it will not + * break backwards-compatibility. See b/4408210. + * + * To run this test ... + * adb shell am instrument -w -e class com.android.webviewtests.JavaBridgeReturnValuesTest \ + * com.android.webviewtests/android.test.InstrumentationTestRunner + */ + +package com.android.webviewtests; + +public class JavaBridgeReturnValuesTest extends JavaBridgeTestBase { + // An instance of this class is injected into the page to test returning + // Java values to JavaScript. + private class TestObject extends Controller { + private String mStringValue; + private boolean mBooleanValue; + + // These four methods are used to control the test. + public synchronized void setStringValue(String x) { + mStringValue = x; + notifyResultIsReady(); + } + public synchronized String waitForStringValue() { + waitForResult(); + return mStringValue; + } + public synchronized void setBooleanValue(boolean x) { + mBooleanValue = x; + notifyResultIsReady(); + } + public synchronized boolean waitForBooleanValue() { + waitForResult(); + return mBooleanValue; + } + + public boolean getBooleanValue() { + return true; + } + public byte getByteValue() { + return 42; + } + public char getCharValue() { + return '\u002A'; + } + public short getShortValue() { + return 42; + } + public int getIntValue() { + return 42; + } + public long getLongValue() { + return 42L; + } + public float getFloatValue() { + return 42.1f; + } + public float getFloatValueNoDecimal() { + return 42.0f; + } + public double getDoubleValue() { + return 42.1; + } + public double getDoubleValueNoDecimal() { + return 42.0; + } + public String getStringValue() { + return "foo"; + } + public String getEmptyStringValue() { + return ""; + } + public String getNullStringValue() { + return null; + } + public Object getObjectValue() { + return new Object(); + } + public Object getNullObjectValue() { + return null; + } + public CustomType getCustomTypeValue() { + return new CustomType(); + } + public void getVoidValue() { + } + } + + // A custom type used when testing passing objects. + private class CustomType { + } + + TestObject mTestObject; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mTestObject = new TestObject(); + setUpWebView(mTestObject, "testObject"); + } + + // Note that this requires that we can pass a JavaScript string to Java. + protected String executeJavaScriptAndGetStringResult(String script) throws Throwable { + executeJavaScript("testObject.setStringValue(" + script + ");"); + return mTestObject.waitForStringValue(); + } + + // Note that this requires that we can pass a JavaScript boolean to Java. + private boolean executeJavaScriptAndGetBooleanResult(String script) throws Throwable { + executeJavaScript("testObject.setBooleanValue(" + script + ");"); + return mTestObject.waitForBooleanValue(); + } + + public void testMethodReturnTypes() throws Throwable { + assertEquals("boolean", + executeJavaScriptAndGetStringResult("typeof testObject.getBooleanValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getByteValue()")); + // char values are returned to JavaScript as numbers. + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getCharValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getShortValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getIntValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getLongValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getFloatValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getFloatValueNoDecimal()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValue()")); + assertEquals("number", + executeJavaScriptAndGetStringResult("typeof testObject.getDoubleValueNoDecimal()")); + assertEquals("string", + executeJavaScriptAndGetStringResult("typeof testObject.getStringValue()")); + assertEquals("string", + executeJavaScriptAndGetStringResult("typeof testObject.getEmptyStringValue()")); + // LIVECONNECT_COMPLIANCE: This should have type object. + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.getNullStringValue()")); + assertEquals("object", + executeJavaScriptAndGetStringResult("typeof testObject.getObjectValue()")); + assertEquals("object", + executeJavaScriptAndGetStringResult("typeof testObject.getNullObjectValue()")); + assertEquals("object", + executeJavaScriptAndGetStringResult("typeof testObject.getCustomTypeValue()")); + assertEquals("undefined", + executeJavaScriptAndGetStringResult("typeof testObject.getVoidValue()")); + } + + public void testMethodReturnValues() throws Throwable { + // We do the string comparison in JavaScript, to avoid relying on the + // coercion algorithm from JavaScript to Java. + assertTrue(executeJavaScriptAndGetBooleanResult("testObject.getBooleanValue()")); + assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getByteValue()")); + // char values are returned to JavaScript as numbers. + assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getCharValue()")); + assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getShortValue()")); + assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getIntValue()")); + assertTrue(executeJavaScriptAndGetBooleanResult("42 === testObject.getLongValue()")); + assertTrue(executeJavaScriptAndGetBooleanResult( + "Math.abs(42.1 - testObject.getFloatValue()) < 0.001")); + assertTrue(executeJavaScriptAndGetBooleanResult( + "42.0 === testObject.getFloatValueNoDecimal()")); + assertTrue(executeJavaScriptAndGetBooleanResult( + "Math.abs(42.1 - testObject.getDoubleValue()) < 0.001")); + assertTrue(executeJavaScriptAndGetBooleanResult( + "42.0 === testObject.getDoubleValueNoDecimal()")); + assertEquals("foo", executeJavaScriptAndGetStringResult("testObject.getStringValue()")); + assertEquals("", executeJavaScriptAndGetStringResult("testObject.getEmptyStringValue()")); + assertTrue(executeJavaScriptAndGetBooleanResult("undefined === testObject.getVoidValue()")); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java new file mode 100644 index 0000000..1af3f63 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/JavaBridgeTestBase.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 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. + */ + +/** + * Common functionality for testing the WebView's Java Bridge. + */ + +package com.android.webviewtests; + +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import junit.framework.Assert; + +public class JavaBridgeTestBase extends ActivityInstrumentationTestCase2<WebViewStubActivity> { + protected class TestWebViewClient extends WebViewClient { + private boolean mIsPageFinished; + @Override + public synchronized void onPageFinished(WebView webView, String url) { + mIsPageFinished = true; + notify(); + } + public synchronized void waitForOnPageFinished() throws RuntimeException { + while (!mIsPageFinished) { + try { + wait(5000); + } catch (Exception e) { + continue; + } + if (!mIsPageFinished) { + throw new RuntimeException("Timed out waiting for onPageFinished()"); + } + } + mIsPageFinished = false; + } + } + + protected class Controller { + private boolean mIsResultReady; + + protected synchronized void notifyResultIsReady() { + mIsResultReady = true; + notify(); + } + protected synchronized void waitForResult() { + while (!mIsResultReady) { + try { + wait(5000); + } catch (Exception e) { + continue; + } + if (!mIsResultReady) { + Assert.fail("Wait timed out"); + } + } + mIsResultReady = false; + } + } + + protected TestWebViewClient mWebViewClient; + + public JavaBridgeTestBase() { + super(WebViewStubActivity.class); + } + + // Sets up the WebView and injects the supplied object. Intended to be called from setUp(). + protected void setUpWebView(final Object object, final String name) throws Exception { + mWebViewClient = new TestWebViewClient(); + // This starts the activity, so must be called on the test thread. + final WebViewStubActivity activity = getActivity(); + // On the UI thread, load an empty page and wait for it to finish + // loading so that the Java object is injected. + try { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + WebView webView = activity.getWebView(); + webView.addJavascriptInterface(object, name); + webView.getSettings().setJavaScriptEnabled(true); + webView.setWebViewClient(mWebViewClient); + webView.loadData("<!DOCTYPE html><title></title>", "text/html", null); + } + }); + mWebViewClient.waitForOnPageFinished(); + } catch (Throwable e) { + throw new RuntimeException("Failed to set up WebView: " + Log.getStackTraceString(e)); + } + } + + protected void executeJavaScript(final String script) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + getWebView().loadUrl("javascript:" + script); + } + }); + } + + protected WebView getWebView() { + return getActivity().getWebView(); + } +} diff --git a/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java b/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java new file mode 100644 index 0000000..ccfd3d5 --- /dev/null +++ b/tests/WebViewTests/src/com/android/webviewtests/WebViewStubActivity.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 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.webviewtests; + +import com.android.webviewtests.R; + +import android.app.Activity; +import android.os.Bundle; +import android.webkit.WebView; + +public class WebViewStubActivity extends Activity { + private WebView mWebView; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.webview_layout); + mWebView = (WebView) findViewById(R.id.web_page); + } + + public WebView getWebView() { + return mWebView; + } +} diff --git a/tests/touchlag/Android.mk b/tests/touchlag/Android.mk new file mode 100644 index 0000000..4f8aa1e --- /dev/null +++ b/tests/touchlag/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + touchlag.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils libutils \ + +LOCAL_MODULE:= test-touchlag + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_EXECUTABLE) diff --git a/tests/touchlag/touchlag.cpp b/tests/touchlag/touchlag.cpp new file mode 100644 index 0000000..df4befb --- /dev/null +++ b/tests/touchlag/touchlag.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <linux/input.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <cutils/memory.h> +#include <asm-generic/mman.h> +#include <sys/mman.h> +#include <utils/threads.h> +#include <unistd.h> +#include <math.h> + +using namespace android; + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#endif + +struct Buffer { + size_t w; + size_t h; + size_t s; + union { + void* addr; + uint32_t* pixels; + }; +}; + +void clearBuffer(Buffer* buf, uint32_t pixel) { + android_memset32(buf->pixels, pixel, buf->s * buf->h * 4); +} + +void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) { + if (y>0 && y<ssize_t(buf->h)) { + uint32_t* bits = buf->pixels + y * buf->s; + if (x>=0 && x<buf->w) { + bits[x] = pixel; + } + ssize_t W(w); + if ((x+W)>=0 && (x+W)<buf->w) { + bits[x+W] = pixel; + } + } +} + +void drawHLine(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) { + if (y>0 && y<ssize_t(buf->h)) { + ssize_t W(w); + if (x<0) { + W += x; + x = 0; + } + if (x+w > buf->w) { + W = buf->w - x; + } + if (W>0) { + uint32_t* bits = buf->pixels + y * buf->s + x; + android_memset32(bits, pixel, W*4); + } + } +} + +void drawRect(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w, size_t h) { + ssize_t W(w), H(h); + if (x<0) { + w += x; + x = 0; + } + if (y<0) { + h += y; + y = 0; + } + if (x+w > buf->w) W = buf->w - x; + if (y+h > buf->h) H = buf->h - y; + if (W>0 && H>0) { + uint32_t* bits = buf->pixels + y * buf->s + x; + for (ssize_t i=0 ; i<H ; i++) { + android_memset32(bits, pixel, W*4); + bits += buf->s; + } + } +} + +void drawCircle(Buffer* buf, uint32_t pixel, + size_t x0, size_t y0, size_t radius, bool filled = false) { + ssize_t f = 1 - radius; + ssize_t ddF_x = 1; + ssize_t ddF_y = -2 * radius; + ssize_t x = 0; + ssize_t y = radius; + if (filled) { + drawHLine(buf, pixel, x0-radius, y0, 2*radius); + } else { + drawTwoPixels(buf, pixel, x0-radius, y0, 2*radius); + } + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (filled) { + drawHLine(buf, pixel, x0-x, y0+y, 2*x); + drawHLine(buf, pixel, x0-x, y0-y, 2*x); + drawHLine(buf, pixel, x0-y, y0+x, 2*y); + drawHLine(buf, pixel, x0-y, y0-x, 2*y); + } else { + drawTwoPixels(buf, pixel, x0-x, y0+y, 2*x); + drawTwoPixels(buf, pixel, x0-x, y0-y, 2*x); + drawTwoPixels(buf, pixel, x0-y, y0+x, 2*y); + drawTwoPixels(buf, pixel, x0-y, y0-x, 2*y); + } + } +} + +class TouchEvents { + class EventThread : public Thread { + int fd; + + virtual bool threadLoop() { + input_event event; + int first_down = 0; + do { + read(fd, &event, sizeof(event)); + if (event.type == EV_ABS) { + if (event.code == ABS_MT_TRACKING_ID) { + down = event.value == -1 ? 0 : 1; + first_down = down; + } + if (event.code == ABS_MT_POSITION_X) { + x = event.value; + } + if (event.code == ABS_MT_POSITION_Y) { + y = event.value; + } + } + } while (event.type == EV_SYN); + return true; + } + + public: + int x, y, down; + EventThread() : Thread(false), + x(0), y(0), down(0) + { + fd = open("/dev/input/event1", O_RDONLY); + } +}; + sp<EventThread> thread; + +public: + TouchEvents() { + thread = new EventThread(); + thread->run("EventThread", PRIORITY_URGENT_DISPLAY); + } + + int getMostRecentPosition(int* x, int* y) { + *x = thread->x; + *y = thread->y; + return thread->down; + } +}; + + +struct Queue { + struct position { + int x, y; + }; + int index; + position q[16]; + Queue() : index(0) { } + void push(int x, int y) { + index++; + index &= 0xF; + q[index].x = x; + q[index].y = y; + } + void get(int lag, int* x, int* y) { + const int i = (index - lag) & 0xF; + *x = q[i].x; + *y = q[i].y; + } +}; + +extern char *optarg; +extern int optind; +extern int optopt; +extern int opterr; +extern int optreset; + +void usage(const char* name) { + printf("\nusage: %s [-h] [-l lag]\n", name); +} + +int main(int argc, char** argv) { + fb_var_screeninfo vi; + fb_fix_screeninfo fi; + + int lag = 0; + int fd = open("/dev/graphics/fb0", O_RDWR); + ioctl(fd, FBIOGET_VSCREENINFO, &vi); + ioctl(fd, FBIOGET_FSCREENINFO, &fi); + void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + Buffer framebuffer; + framebuffer.w = vi.xres; + framebuffer.h = vi.yres; + framebuffer.s = fi.line_length / (vi.bits_per_pixel >> 3); + framebuffer.addr = bits; + + int ch; + while ((ch = getopt(argc, argv, "hl:")) != -1) { + switch (ch) { + case 'l': + lag = atoi(optarg); + break; + case 'h': + default: + usage(argv[0]); + exit(0); + } + } + argc -= optind; + argv += optind; + + + TouchEvents touch; + Queue queue; + + + int x=0, y=0, down=0; + int lag_x=0, lag_y=0; + + clearBuffer(&framebuffer, 0); + while (true) { + uint32_t crt = 0; + int err = ioctl(fd, FBIO_WAITFORVSYNC, &crt); + + // draw beam marker + drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h); + // erase screen + if (lag) { + drawCircle(&framebuffer, 0, lag_x, lag_y, 100); + drawHLine(&framebuffer, 0, 0, lag_y, 32); + } + drawCircle(&framebuffer, 0, x, y, 100, true); + drawHLine(&framebuffer, 0, 0, y, 32); + + // draw a line at y=1000 + drawHLine(&framebuffer, 0x808080, 0, 1000, framebuffer.w); + + // get touch events + touch.getMostRecentPosition(&x, &y); + queue.push(x, y); + queue.get(lag, &lag_x, &lag_y); + + if (lag) { + drawCircle(&framebuffer, 0x00FF00, lag_x, lag_y, 100); + drawHLine(&framebuffer, 0x00FF00, 0, lag_y, 32); + } + + drawCircle(&framebuffer, 0xFFFFFF, x, y, 100, true); + drawHLine(&framebuffer, 0xFFFFFF, 0, y, 32); + + // draw end of frame beam marker + drawRect(&framebuffer, 0x004000, framebuffer.w-2, 0, 2, framebuffer.h); + } + + close(fd); + return 0; +} |