diff options
| author | Jean-Baptiste Queru <jbq@google.com> | 2009-11-12 18:45:17 -0800 |
|---|---|---|
| committer | Jean-Baptiste Queru <jbq@google.com> | 2009-11-13 15:09:24 -0800 |
| commit | 2c8ead32c7ebf08db568e2e9d5dbb3738ac69797 (patch) | |
| tree | a4b9a0b6b9a125c492e6584d48a15b3b62b327d7 /samples | |
| parent | 50992e805e758e2231f28ec2127b57a1a9fd0ddc (diff) | |
| download | android_development-2c8ead32c7ebf08db568e2e9d5dbb3738ac69797.tar.gz android_development-2c8ead32c7ebf08db568e2e9d5dbb3738ac69797.tar.bz2 android_development-2c8ead32c7ebf08db568e2e9d5dbb3738ac69797.zip | |
eclair snapshot
Diffstat (limited to 'samples')
172 files changed, 6856 insertions, 108 deletions
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml index 032f5c273..5eb8ccb22 100644 --- a/samples/ApiDemos/AndroidManifest.xml +++ b/samples/ApiDemos/AndroidManifest.xml @@ -24,15 +24,24 @@ <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> - <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> + <!-- We will request access to the camera, saying we require a camera + of some sort but not one with autofocus capability. --> + <uses-permission android:name="android.permission.CAMERA" /> + <uses-feature android:name="android.hardware.camera" /> + <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> + <application android:name="ApiDemosApplication" android:label="@string/activity_sample_code" android:icon="@drawable/app_sample_code" > + <!-- This is how we can request a library but still allow the app + to be installed if it doesn't exist. --> + <uses-library android:name="com.example.will.never.exist" android:required="false" /> + <activity android:name="ApiDemos"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -72,6 +81,15 @@ </intent-filter> </activity> + <activity android:name=".app.WallpaperActivity" + android:label="@string/activity_wallpaper" + android:theme="@style/Theme.Wallpaper"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.SAMPLE_CODE" /> + </intent-filter> + </activity> + <activity android:name=".app.TranslucentActivity" android:label="@string/activity_translucent" android:theme="@style/Theme.Translucent"> @@ -90,6 +108,13 @@ </intent-filter> </activity> + <activity android:name=".app.Animation" android:label="@string/activity_animation"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.SAMPLE_CODE" /> + </intent-filter> + </activity> + <activity android:name=".app.SaveRestoreState" android:label="@string/activity_save_restore" android:windowSoftInputMode="stateVisible|adjustResize"> @@ -1562,6 +1587,13 @@ </intent-filter> </activity> + <activity android:name=".graphics.ColorFilters" android:label="Graphics/ColorFilters"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.SAMPLE_CODE" /> + </intent-filter> + </activity> + <activity android:name=".graphics.CreateBitmap" android:label="Graphics/CreateBitmap"> <intent-filter> <action android:name="android.intent.action.MAIN" /> diff --git a/samples/ApiDemos/default.properties b/samples/ApiDemos/default.properties deleted file mode 100644 index 9d79b12c7..000000000 --- a/samples/ApiDemos/default.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# Project target. -target=android-4 diff --git a/samples/ApiDemos/res/anim/fade.xml b/samples/ApiDemos/res/anim/fade.xml index 78b193d53..617c5f253 100644 --- a/samples/ApiDemos/res/anim/fade.xml +++ b/samples/ApiDemos/res/anim/fade.xml @@ -16,4 +16,5 @@ <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator" - android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="100" /> + android:fromAlpha="0.0" android:toAlpha="1.0" + android:duration="@android:integer/config_longAnimTime" /> diff --git a/samples/ApiDemos/res/anim/hold.xml b/samples/ApiDemos/res/anim/hold.xml new file mode 100644 index 000000000..65fbacfc6 --- /dev/null +++ b/samples/ApiDemos/res/anim/hold.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<translate xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/accelerate_interpolator" + android:fromXDelta="0" android:toXDelta="0" + android:duration="@android:integer/config_longAnimTime" /> diff --git a/samples/ApiDemos/res/anim/slide_left.xml b/samples/ApiDemos/res/anim/slide_left.xml index 87604919f..0a591b05a 100644 --- a/samples/ApiDemos/res/anim/slide_left.xml +++ b/samples/ApiDemos/res/anim/slide_left.xml @@ -15,5 +15,6 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"> - <translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="150" /> + <translate android:fromXDelta="100%p" android:toXDelta="0" + android:duration="@android:integer/config_shortAnimTime" /> </set> diff --git a/samples/ApiDemos/res/anim/slide_right.xml b/samples/ApiDemos/res/anim/slide_right.xml index 7aaacdb0a..edeed2472 100644 --- a/samples/ApiDemos/res/anim/slide_right.xml +++ b/samples/ApiDemos/res/anim/slide_right.xml @@ -15,5 +15,6 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator"> - <translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="150" /> + <translate android:fromXDelta="-100%p" android:toXDelta="0" + android:duration="@android:integer/config_shortAnimTime" /> </set> diff --git a/samples/ApiDemos/res/anim/zoom_enter.xml b/samples/ApiDemos/res/anim/zoom_enter.xml new file mode 100644 index 000000000..7c29852a8 --- /dev/null +++ b/samples/ApiDemos/res/anim/zoom_enter.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +*/ +--> + +<!-- Special window zoom animation: this is the element that enters the screen, + it starts at 200% and scales down. Goes with zoom_exit.xml. --> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/decelerate_interpolator"> + <scale android:fromXScale="2.0" android:toXScale="1.0" + android:fromYScale="2.0" android:toYScale="1.0" + android:pivotX="50%p" android:pivotY="50%p" + android:duration="@android:integer/config_mediumAnimTime" /> +</set> diff --git a/samples/ApiDemos/res/anim/zoom_exit.xml b/samples/ApiDemos/res/anim/zoom_exit.xml new file mode 100644 index 000000000..29dfe99a6 --- /dev/null +++ b/samples/ApiDemos/res/anim/zoom_exit.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +*/ +--> + +<!-- Special window zoom animation: this is the element that exits the + screen, it is forced above the entering element and starts at its + normal size (filling the screen) and scales down while fading out. + This goes with zoom_enter.xml. --> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/decelerate_interpolator" + android:zAdjustment="top"> + <scale android:fromXScale="1.0" android:toXScale=".5" + android:fromYScale="1.0" android:toYScale=".5" + android:pivotX="50%p" android:pivotY="50%p" + android:duration="@android:integer/config_mediumAnimTime" /> + <alpha android:fromAlpha="1.0" android:toAlpha="0" + android:duration="@android:integer/config_mediumAnimTime"/> +</set> diff --git a/samples/ApiDemos/res/drawable-hdpi/alert_dialog_icon.png b/samples/ApiDemos/res/drawable-hdpi/alert_dialog_icon.png Binary files differnew file mode 100755 index 000000000..fe54477c9 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/alert_dialog_icon.png diff --git a/samples/ApiDemos/res/drawable-hdpi/app_sample_code.png b/samples/ApiDemos/res/drawable-hdpi/app_sample_code.png Binary files differnew file mode 100755 index 000000000..66a198496 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/app_sample_code.png diff --git a/samples/ApiDemos/res/drawable-hdpi/arrow_down_float.png b/samples/ApiDemos/res/drawable-hdpi/arrow_down_float.png Binary files differnew file mode 100755 index 000000000..923d330fa --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/arrow_down_float.png diff --git a/samples/ApiDemos/res/drawable-hdpi/arrow_up_float.png b/samples/ApiDemos/res/drawable-hdpi/arrow_up_float.png Binary files differnew file mode 100755 index 000000000..eda5faf84 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/arrow_up_float.png diff --git a/samples/ApiDemos/res/drawable-hdpi/btn_check_off.png b/samples/ApiDemos/res/drawable-hdpi/btn_check_off.png Binary files differnew file mode 100755 index 000000000..0cf1f04a2 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/btn_check_off.png diff --git a/samples/ApiDemos/res/drawable-hdpi/btn_check_on.png b/samples/ApiDemos/res/drawable-hdpi/btn_check_on.png Binary files differnew file mode 100755 index 000000000..fc791c45d --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/btn_check_on.png diff --git a/samples/ApiDemos/res/drawable-hdpi/btn_circle_normal.png b/samples/ApiDemos/res/drawable-hdpi/btn_circle_normal.png Binary files differnew file mode 100755 index 000000000..bf3fb5a05 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/btn_circle_normal.png diff --git a/samples/ApiDemos/res/drawable-hdpi/btn_default_normal.9.png b/samples/ApiDemos/res/drawable-hdpi/btn_default_normal.9.png Binary files differnew file mode 100755 index 000000000..5d3d73302 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/btn_default_normal.9.png diff --git a/samples/ApiDemos/res/drawable-hdpi/button.9.png b/samples/ApiDemos/res/drawable-hdpi/button.9.png Binary files differnew file mode 100755 index 000000000..6995e609f --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/button.9.png diff --git a/samples/ApiDemos/res/drawable-hdpi/ic_popup_reminder.png b/samples/ApiDemos/res/drawable-hdpi/ic_popup_reminder.png Binary files differnew file mode 100755 index 000000000..9652ddeb3 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/ic_popup_reminder.png diff --git a/samples/ApiDemos/res/drawable-hdpi/icon48x48_2.png b/samples/ApiDemos/res/drawable-hdpi/icon48x48_2.png Binary files differnew file mode 100755 index 000000000..1e256e683 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/icon48x48_2.png diff --git a/samples/ApiDemos/res/drawable-hdpi/progress_circular_background.png b/samples/ApiDemos/res/drawable-hdpi/progress_circular_background.png Binary files differnew file mode 100755 index 000000000..c4ecd1f4e --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/progress_circular_background.png diff --git a/samples/ApiDemos/res/drawable-hdpi/progress_particle.png b/samples/ApiDemos/res/drawable-hdpi/progress_particle.png Binary files differnew file mode 100755 index 000000000..3e72fb419 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/progress_particle.png diff --git a/samples/ApiDemos/res/drawable-hdpi/robot.png b/samples/ApiDemos/res/drawable-hdpi/robot.png Binary files differnew file mode 100755 index 000000000..3e4fd2143 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/robot.png diff --git a/samples/ApiDemos/res/drawable-hdpi/scrollbar_state2.png b/samples/ApiDemos/res/drawable-hdpi/scrollbar_state2.png Binary files differnew file mode 100755 index 000000000..41ed5b7fa --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/scrollbar_state2.png diff --git a/samples/ApiDemos/res/drawable-hdpi/star_big_on.png b/samples/ApiDemos/res/drawable-hdpi/star_big_on.png Binary files differnew file mode 100755 index 000000000..944918eb0 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/star_big_on.png diff --git a/samples/ApiDemos/res/drawable-hdpi/stat_happy.png b/samples/ApiDemos/res/drawable-hdpi/stat_happy.png Binary files differnew file mode 100755 index 000000000..27f5bb74e --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/stat_happy.png diff --git a/samples/ApiDemos/res/drawable-hdpi/stat_neutral.png b/samples/ApiDemos/res/drawable-hdpi/stat_neutral.png Binary files differnew file mode 100755 index 000000000..34073ffb0 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/stat_neutral.png diff --git a/samples/ApiDemos/res/drawable-hdpi/stat_sad.png b/samples/ApiDemos/res/drawable-hdpi/stat_sad.png Binary files differnew file mode 100755 index 000000000..25004cd8e --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/stat_sad.png diff --git a/samples/ApiDemos/res/drawable-hdpi/stat_sample.png b/samples/ApiDemos/res/drawable-hdpi/stat_sample.png Binary files differnew file mode 100755 index 000000000..6c9ba0a97 --- /dev/null +++ b/samples/ApiDemos/res/drawable-hdpi/stat_sample.png diff --git a/samples/ApiDemos/res/drawable/alert_dialog_icon.png b/samples/ApiDemos/res/drawable-mdpi/alert_dialog_icon.png Binary files differindex 0a7de0476..0a7de0476 100644 --- a/samples/ApiDemos/res/drawable/alert_dialog_icon.png +++ b/samples/ApiDemos/res/drawable-mdpi/alert_dialog_icon.png diff --git a/samples/ApiDemos/res/drawable/app_sample_code.png b/samples/ApiDemos/res/drawable-mdpi/app_sample_code.png Binary files differindex 5ae7701a8..5ae7701a8 100644 --- a/samples/ApiDemos/res/drawable/app_sample_code.png +++ b/samples/ApiDemos/res/drawable-mdpi/app_sample_code.png diff --git a/samples/ApiDemos/res/drawable/arrow_down_float.png b/samples/ApiDemos/res/drawable-mdpi/arrow_down_float.png Binary files differindex bfe0ce67c..bfe0ce67c 100644 --- a/samples/ApiDemos/res/drawable/arrow_down_float.png +++ b/samples/ApiDemos/res/drawable-mdpi/arrow_down_float.png diff --git a/samples/ApiDemos/res/drawable/arrow_up_float.png b/samples/ApiDemos/res/drawable-mdpi/arrow_up_float.png Binary files differindex 77673ef2b..77673ef2b 100644 --- a/samples/ApiDemos/res/drawable/arrow_up_float.png +++ b/samples/ApiDemos/res/drawable-mdpi/arrow_up_float.png diff --git a/samples/ApiDemos/res/drawable-mdpi/btn_check_off.png b/samples/ApiDemos/res/drawable-mdpi/btn_check_off.png Binary files differnew file mode 100644 index 000000000..56d386154 --- /dev/null +++ b/samples/ApiDemos/res/drawable-mdpi/btn_check_off.png diff --git a/samples/ApiDemos/res/drawable-mdpi/btn_check_on.png b/samples/ApiDemos/res/drawable-mdpi/btn_check_on.png Binary files differnew file mode 100644 index 000000000..791ac1d92 --- /dev/null +++ b/samples/ApiDemos/res/drawable-mdpi/btn_check_on.png diff --git a/samples/ApiDemos/res/drawable-mdpi/btn_circle_normal.png b/samples/ApiDemos/res/drawable-mdpi/btn_circle_normal.png Binary files differnew file mode 100644 index 000000000..fc5af1c9f --- /dev/null +++ b/samples/ApiDemos/res/drawable-mdpi/btn_circle_normal.png diff --git a/samples/ApiDemos/res/drawable-mdpi/btn_default_normal.9.png b/samples/ApiDemos/res/drawable-mdpi/btn_default_normal.9.png Binary files differnew file mode 100644 index 000000000..a2d5ccd20 --- /dev/null +++ b/samples/ApiDemos/res/drawable-mdpi/btn_default_normal.9.png diff --git a/samples/ApiDemos/res/drawable/button.9.png b/samples/ApiDemos/res/drawable-mdpi/button.9.png Binary files differindex f6da7e5ab..f6da7e5ab 100644 --- a/samples/ApiDemos/res/drawable/button.9.png +++ b/samples/ApiDemos/res/drawable-mdpi/button.9.png diff --git a/samples/ApiDemos/res/drawable/ic_popup_reminder.png b/samples/ApiDemos/res/drawable-mdpi/ic_popup_reminder.png Binary files differindex 4f2b82ce5..4f2b82ce5 100755 --- a/samples/ApiDemos/res/drawable/ic_popup_reminder.png +++ b/samples/ApiDemos/res/drawable-mdpi/ic_popup_reminder.png diff --git a/samples/ApiDemos/res/drawable/icon48x48_2.png b/samples/ApiDemos/res/drawable-mdpi/icon48x48_2.png Binary files differindex 84af2a2f1..84af2a2f1 100755 --- a/samples/ApiDemos/res/drawable/icon48x48_2.png +++ b/samples/ApiDemos/res/drawable-mdpi/icon48x48_2.png diff --git a/samples/ApiDemos/res/drawable/progress_circular_background.png b/samples/ApiDemos/res/drawable-mdpi/progress_circular_background.png Binary files differindex 7c637fd60..7c637fd60 100644 --- a/samples/ApiDemos/res/drawable/progress_circular_background.png +++ b/samples/ApiDemos/res/drawable-mdpi/progress_circular_background.png diff --git a/samples/ApiDemos/res/drawable/progress_particle.png b/samples/ApiDemos/res/drawable-mdpi/progress_particle.png Binary files differindex 916010869..916010869 100644 --- a/samples/ApiDemos/res/drawable/progress_particle.png +++ b/samples/ApiDemos/res/drawable-mdpi/progress_particle.png diff --git a/samples/ApiDemos/res/drawable/robot.png b/samples/ApiDemos/res/drawable-mdpi/robot.png Binary files differindex 8a9e6984b..8a9e6984b 100644 --- a/samples/ApiDemos/res/drawable/robot.png +++ b/samples/ApiDemos/res/drawable-mdpi/robot.png diff --git a/samples/ApiDemos/res/drawable/scrollbar_state2.png b/samples/ApiDemos/res/drawable-mdpi/scrollbar_state2.png Binary files differindex 012f737d5..012f737d5 100755 --- a/samples/ApiDemos/res/drawable/scrollbar_state2.png +++ b/samples/ApiDemos/res/drawable-mdpi/scrollbar_state2.png diff --git a/samples/ApiDemos/res/drawable/star_big_on.png b/samples/ApiDemos/res/drawable-mdpi/star_big_on.png Binary files differindex 510c8b227..510c8b227 100644 --- a/samples/ApiDemos/res/drawable/star_big_on.png +++ b/samples/ApiDemos/res/drawable-mdpi/star_big_on.png diff --git a/samples/ApiDemos/res/drawable/stat_happy.png b/samples/ApiDemos/res/drawable-mdpi/stat_happy.png Binary files differindex 3a8791bab..3a8791bab 100644 --- a/samples/ApiDemos/res/drawable/stat_happy.png +++ b/samples/ApiDemos/res/drawable-mdpi/stat_happy.png diff --git a/samples/ApiDemos/res/drawable/stat_neutral.png b/samples/ApiDemos/res/drawable-mdpi/stat_neutral.png Binary files differindex 1dc059444..1dc059444 100644 --- a/samples/ApiDemos/res/drawable/stat_neutral.png +++ b/samples/ApiDemos/res/drawable-mdpi/stat_neutral.png diff --git a/samples/ApiDemos/res/drawable/stat_sad.png b/samples/ApiDemos/res/drawable-mdpi/stat_sad.png Binary files differindex 17d26deb9..17d26deb9 100644 --- a/samples/ApiDemos/res/drawable/stat_sad.png +++ b/samples/ApiDemos/res/drawable-mdpi/stat_sad.png diff --git a/samples/ApiDemos/res/drawable/stat_sample.png b/samples/ApiDemos/res/drawable-mdpi/stat_sample.png Binary files differindex 1733042c9..1733042c9 100644 --- a/samples/ApiDemos/res/drawable/stat_sample.png +++ b/samples/ApiDemos/res/drawable-mdpi/stat_sample.png diff --git a/samples/ApiDemos/res/layout/activity_animation.xml b/samples/ApiDemos/res/layout/activity_animation.xml new file mode 100644 index 000000000..446f73585 --- /dev/null +++ b/samples/ApiDemos/res/layout/activity_animation.xml @@ -0,0 +1,42 @@ +<?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. +--> + +<!-- Demonstrates starting and stopping a local service. + See corresponding Java code com.android.sdk.app.LocalSerice.java. --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip" + android:gravity="center_horizontal" + android:layout_width="fill_parent" android:layout_height="fill_parent"> + + <TextView + android:layout_width="fill_parent" android:layout_height="wrap_content" + android:layout_weight="0" + android:paddingBottom="4dip" + android:text="@string/activity_animation_msg"/> + + <Button android:id="@+id/fade_animation" + android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@string/activity_animation_fade"> + <requestFocus /> + </Button> + + <Button android:id="@+id/zoom_animation" + android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@string/activity_animation_zoom"> + </Button> + +</LinearLayout> + diff --git a/samples/ApiDemos/res/layout/service_start_arguments_controller.xml b/samples/ApiDemos/res/layout/service_start_arguments_controller.xml index f10a2c396..19b749802 100644 --- a/samples/ApiDemos/res/layout/service_start_arguments_controller.xml +++ b/samples/ApiDemos/res/layout/service_start_arguments_controller.xml @@ -43,5 +43,15 @@ android:text="@string/start3_service"> </Button> + <Button android:id="@+id/startfail" + android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@string/startfail_service"> + </Button> + + <Button android:id="@+id/kill" + android:layout_width="wrap_content" android:layout_height="wrap_content" + android:text="@string/kill_process"> + </Button> + </LinearLayout> diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml index c2c98295b..2800bff53 100644 --- a/samples/ApiDemos/res/values/strings.xml +++ b/samples/ApiDemos/res/values/strings.xml @@ -38,6 +38,8 @@ custom Theme.Dialog theme to make an activity that looks like a customized dialog, here with an ugly frame.</string> + <string name="activity_wallpaper">App/Activity/Wallpaper</string> + <string name="activity_translucent">App/Activity/Translucent</string> <string name="translucent_background">Example of how you can make an activity have a translucent background, compositing over @@ -45,6 +47,11 @@ <string name="activity_translucent_blur">App/Activity/Translucent Blur</string> + <string name="activity_animation">App/Activity/Animation</string> + <string name="activity_animation_msg">Press a button to launch an activity with a custom animation.</string> + <string name="activity_animation_fade">Fade in</string> + <string name="activity_animation_zoom">Zoom in</string> + <string name="activity_save_restore">App/Activity/Save & Restore State</string> <string name="save_restore_msg">Demonstration of saving and restoring activity state in onSaveInstanceState() and onCreate().</string> <string name="saves_state">This text field saves its state:</string> @@ -115,9 +122,6 @@ <string name="remote_service_disconnected">Disconnected from remote service</string> <string name="remote_call_failed">Failure calling remote service</string> - <string name="service_arguments_started">"Started with arguments: "</string> - <string name="service_arguments_stopped">Finished arguments, - stopping.</string> <string name="service_start_arguments_label">Sample Service Start Arguments </string> @@ -128,10 +132,13 @@ service can be started with arguments, and run until all arguments are processed. </string> - <string name="start1_service">Start with \"One\"</string> - <string name="start2_service">Start with \"Two\"</string> - <string name="start3_service">Start with \"Three\"</string> - + <string name="start1_service">Start \"One\" no redeliver</string> + <string name="start2_service">Start \"Two\" no redeliver</string> + <string name="start3_service">Start \"Three\" w/redeliver</string> + <string name="startfail_service">Start failed delivery</string> + <string name="service_created">Service created.</string> + <string name="service_destroyed">Service destroyed.</string> + <string name="one_shot_received">The one-shot alarm has gone off</string> <string name="repeating_received">The repeating alarm has gone off</string> @@ -362,8 +369,8 @@ <string name="summary_my_preference">This is a custom counter preference</string> <string name="title_advanced_toggle_preference">Haunted preference</string> - <string name="summary_on_advanced_toggle_preference">I'm on! :)</string> - <string name="summary_off_advanced_toggle_preference">I'm off! :(</string> + <string name="summary_on_advanced_toggle_preference">I\'m on! :)</string> + <string name="summary_off_advanced_toggle_preference">I\'m off! :(</string> <string name="title_parent_preference">Parent toggle</string> <string name="summary_parent_preference">This is visually a parent</string> @@ -632,13 +639,13 @@ using the Java programming language and run on Dalvik, a custom virtual machine designed for embedded use which runs on top of a Linux kernel. - If you want to know how to develop applications for Android, you're in the + If you want to know how to develop applications for Android, you\'re in the right place. This site provides a variety of documentation that will help you learn about Android and develop mobile applications for the platform. An early look at the the Android SDK is also available. It includes sample projects with source code, development tools, an emulator, and of course all - the libraries you'll need to build an Android application. What would it take + the libraries you\'ll need to build an Android application. What would it take to build a better mobile phone? </string> <string name="spinner_1_color">Color:</string> diff --git a/samples/ApiDemos/res/values/styles.xml b/samples/ApiDemos/res/values/styles.xml index 3c9c68185..8cc831287 100644 --- a/samples/ApiDemos/res/values/styles.xml +++ b/samples/ApiDemos/res/values/styles.xml @@ -37,9 +37,16 @@ <item name="android:windowBackground">@drawable/filled_box</item> </style> + <!-- A theme that has a wallpaper background. Here we explicitly specify + that this theme is to inherit from the system's wallpaper theme, + which sets up various attributes correctly. --> + <style name="Theme.Wallpaper" parent="android:style/Theme.Wallpaper"> + <item name="android:colorForeground">#fff</item> + </style> + <!-- A theme that has a translucent background. Here we explicitly specify that this theme is to inherit from the system's translucent theme, - which sets up various attributes correctly.. --> + which sets up various attributes correctly. --> <style name="Theme.Translucent" parent="android:style/Theme.Translucent"> <item name="android:windowBackground">@drawable/translucent_background</item> <item name="android:windowNoTitle">true</item> diff --git a/samples/ApiDemos/src/com/example/android/apis/app/Animation.java b/samples/ApiDemos/src/com/example/android/apis/app/Animation.java new file mode 100644 index 000000000..90831f5d5 --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/app/Animation.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package com.example.android.apis.app; + +// Need the following import to get access to the app resources, since this +// class is in a sub-package. +import com.example.android.apis.R; +import com.example.android.apis.view.Controls1; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; + + +/** + * <p>Example of explicitly starting and stopping the {@link LocalService}. + * This demonstrates the implementation of a service that runs in the same + * process as the rest of the application, which is explicitly started and stopped + * as desired.</p> + */ +public class Animation extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_animation); + + // Watch for button clicks. + Button button = (Button)findViewById(R.id.fade_animation); + button.setOnClickListener(mFadeListener); + button = (Button)findViewById(R.id.zoom_animation); + button.setOnClickListener(mZoomListener); + } + + private OnClickListener mFadeListener = new OnClickListener() { + public void onClick(View v) { + // Request the next activity transition (here starting a new one). + startActivity(new Intent(Animation.this, Controls1.class)); + // Supply a custom animation. This one will just fade the new + // activity on top. Note that we need to also supply an animation + // (here just doing nothing for the same amount of time) for the + // old activity to prevent it from going away too soon. + overridePendingTransition(R.anim.fade, R.anim.hold); + } + }; + + private OnClickListener mZoomListener = new OnClickListener() { + public void onClick(View v) { + // Request the next activity transition (here starting a new one). + startActivity(new Intent(Animation.this, Controls1.class)); + // This is a more complicated animation, involving transformations + // on both this (exit) and the new (enter) activity. Note how for + // the duration of the animation we force the exiting activity + // to be Z-ordered on top (even though it really isn't) to achieve + // the effect we want. + overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit); + } + }; +} + diff --git a/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java b/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java index 87915784b..79324a43c 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; +import android.util.Log; import android.widget.Toast; // Need the following import to get access to the app resources, since this @@ -64,6 +65,14 @@ public class LocalService extends Service { } @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.i("LocalService", "Received start id " + startId + ": " + intent); + // We want this service to continue running until it is explicitly + // stopped, so return sticky. + return START_STICKY; + } + + @Override public void onDestroy() { // Cancel the persistent notification. mNM.cancel(R.string.local_service_started); diff --git a/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.java b/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.java index 5e1615876..f4f9af1fb 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.java @@ -27,6 +27,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.util.Log; import android.widget.Toast; @@ -41,9 +42,12 @@ import com.example.android.apis.R; * happen in the service. This is generally how background services should * interact with the user, rather than doing something more disruptive such as * calling startActivity(). + * + * <p>For applications targeting Android 1.5 or beyond, you may want consider + * using the android.app.IntentService class, which takes care of all the + * work of creating the extra thread and dispatching commands to it. */ -public class ServiceStartArguments extends Service -{ +public class ServiceStartArguments extends Service { private NotificationManager mNM; private Intent mInvokeIntent; private volatile Looper mServiceLooper; @@ -58,16 +62,22 @@ public class ServiceStartArguments extends Service public void handleMessage(Message msg) { Bundle arguments = (Bundle)msg.obj; - String txt = getResources() - .getString(R.string.service_arguments_started); - txt = txt + arguments.getString("name"); - Log.i("ServiceStartArguments", "Message: " + msg + ", " + txt); + String txt = arguments.getString("name"); + + Log.i("ServiceStartArguments", "Message: " + msg + ", " + + arguments.getString("name")); - showNotification(); + if ((msg.arg2&Service.START_FLAG_REDELIVERY) == 0) { + txt = "New cmd #" + msg.arg1 + ": " + txt; + } else { + txt = "Re-delivered #" + msg.arg1 + ": " + txt; + } + + showNotification(txt); - // Normally we would do some work here... for our sample, we will - // just sleep for 10 seconds. + // Normally we would do some work here... for our sample, we will + // just sleep for 5 seconds. long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { @@ -78,6 +88,8 @@ public class ServiceStartArguments extends Service } } + hideNotification(); + Log.i("ServiceStartArguments", "Done with #" + msg.arg1); stopSelf(msg.arg1); } @@ -88,14 +100,19 @@ public class ServiceStartArguments extends Service public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + Toast.makeText(this, R.string.service_created, + Toast.LENGTH_SHORT).show(); + // This is who should be launched if the user selects our persistent // notification. mInvokeIntent = new Intent(this, ServiceStartArgumentsController.class); // Start up the thread running the service. Note that we create a // separate thread because the service normally runs in the process's - // main thread, which we don't want to block. - HandlerThread thread = new HandlerThread("ServiceStartArguments"); + // main thread, which we don't want to block. We also make it + // background priority so CPU-intensive work will not disrupt our UI. + HandlerThread thread = new HandlerThread("ServiceStartArguments", + Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mServiceLooper = thread.getLooper(); @@ -103,25 +120,45 @@ public class ServiceStartArguments extends Service } @Override - public void onStart(Intent intent, int startId) { + public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ServiceStartArguments", "Starting #" + startId + ": " + intent.getExtras()); Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; + msg.arg2 = flags; msg.obj = intent.getExtras(); mServiceHandler.sendMessage(msg); Log.i("ServiceStartArguments", "Sending: " + msg); + + // For the start fail button, we will simulate the process dying + // for some reason in onStartCommand(). + if (intent.getBooleanExtra("fail", false)) { + // Don't do this if we are in a retry... the system will + // eventually give up if we keep crashing. + if ((flags&START_FLAG_RETRY) == 0) { + // Since the process hasn't finished handling the command, + // it will be restarted with the command again, regardless of + // whether we return START_REDELIVER_INTENT. + Process.killProcess(Process.myPid()); + } + } + + // Normally we would consistently return one kind of result... + // however, here we will select between these two, so you can see + // how they impact the behavior. Try killing the process while it + // is in the middle of executing the different commands. + return intent.getBooleanExtra("redeliver", false) + ? START_REDELIVER_INTENT : START_NOT_STICKY; } @Override public void onDestroy() { mServiceLooper.quit(); - // Cancel the persistent notification. - mNM.cancel(R.string.service_arguments_started); + hideNotification(); // Tell the user we stopped. - Toast.makeText(ServiceStartArguments.this, R.string.service_arguments_stopped, + Toast.makeText(ServiceStartArguments.this, R.string.service_destroyed, Toast.LENGTH_SHORT).show(); } @@ -133,10 +170,7 @@ public class ServiceStartArguments extends Service /** * Show a notification while this service is running. */ - private void showNotification() { - // In this sample, we'll use the same text for the ticker and the expanded notification - CharSequence text = getText(R.string.service_arguments_started); - + private void showNotification(String text) { // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis()); @@ -149,9 +183,16 @@ public class ServiceStartArguments extends Service notification.setLatestEventInfo(this, getText(R.string.service_start_arguments_label), text, contentIntent); + // We show this for as long as our service is processing a command. + notification.flags |= Notification.FLAG_ONGOING_EVENT; + // Send the notification. // We use a string id because it is a unique number. We use it later to cancel. - mNM.notify(R.string.service_arguments_started, notification); + mNM.notify(R.string.service_created, notification); + } + + private void hideNotification() { + mNM.cancel(R.string.service_created); } } diff --git a/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArgumentsController.java b/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArgumentsController.java index 2c53ff4f4..9d79e2e05 100644 --- a/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArgumentsController.java +++ b/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArgumentsController.java @@ -21,14 +21,13 @@ package com.example.android.apis.app; import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.os.Process; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.example.android.apis.R; -import java.util.HashMap; - /** * Example of explicitly starting the {@link ServiceStartArguments}. */ @@ -46,26 +45,51 @@ public class ServiceStartArgumentsController extends Activity { button.setOnClickListener(mStart2Listener); button = (Button)findViewById(R.id.start3); button.setOnClickListener(mStart3Listener); + button = (Button)findViewById(R.id.startfail); + button.setOnClickListener(mStartFailListener); + button = (Button)findViewById(R.id.kill); + button.setOnClickListener(mKillListener); } private OnClickListener mStart1Listener = new OnClickListener() { public void onClick(View v) { startService(new Intent(ServiceStartArgumentsController.this, - ServiceStartArguments.class).putExtra("name", "One")); + ServiceStartArguments.class) + .putExtra("name", "One")); } }; private OnClickListener mStart2Listener = new OnClickListener() { public void onClick(View v) { startService(new Intent(ServiceStartArgumentsController.this, - ServiceStartArguments.class).putExtra("name", "Two")); + ServiceStartArguments.class) + .putExtra("name", "Two")); } }; private OnClickListener mStart3Listener = new OnClickListener() { public void onClick(View v) { startService(new Intent(ServiceStartArgumentsController.this, - ServiceStartArguments.class).putExtra("name", "Three")); + ServiceStartArguments.class) + .putExtra("name", "Three") + .putExtra("redeliver", true)); + } + }; + + private OnClickListener mStartFailListener = new OnClickListener() { + public void onClick(View v) { + startService(new Intent(ServiceStartArgumentsController.this, + ServiceStartArguments.class) + .putExtra("name", "Failure") + .putExtra("fail", true)); + } + }; + + private OnClickListener mKillListener = new OnClickListener() { + public void onClick(View v) { + // This is to simulate the service being killed while it is + // running in the background. + Process.killProcess(Process.myPid()); } }; } diff --git a/samples/ApiDemos/src/com/example/android/apis/app/WallpaperActivity.java b/samples/ApiDemos/src/com/example/android/apis/app/WallpaperActivity.java new file mode 100644 index 000000000..8d7f5a1b4 --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/app/WallpaperActivity.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007 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.example.android.apis.app; + +// Need the following import to get access to the app resources, since this +// class is in a sub-package. +import com.example.android.apis.R; + +import android.app.Activity; +import android.os.Bundle; +import android.view.WindowManager; + +/** + * <h3>Wallpaper Activity</h3> + * + * <p>This demonstrates the how to write an activity that has the system + * wallpaper behind it.</p> + */ +public class WallpaperActivity extends Activity { + /** + * Initialization of the Activity after it is first created. Must at least + * call {@link android.app.Activity#setContentView setContentView()} to + * describe what is to be displayed in the screen. + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + // Be sure to call the super class. + super.onCreate(savedInstanceState); + + // See assets/res/any/layout/translucent_background.xml for this + // view layout definition, which is being set here as + // the content of our screen. + setContentView(R.layout.translucent_background); + } +} diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/ColorFilters.java b/samples/ApiDemos/src/com/example/android/apis/graphics/ColorFilters.java new file mode 100644 index 000000000..92d18ba4a --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/ColorFilters.java @@ -0,0 +1,184 @@ +/* + * 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. + */ + +package com.example.android.apis.graphics; + +import com.example.android.apis.R; + +import android.app.Activity; +import android.content.Context; +import android.graphics.*; +import android.graphics.drawable.*; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.*; + +public class ColorFilters extends GraphicsActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(new SampleView(this)); + + } + + private static class SampleView extends View { + private Activity mActivity; + private Drawable mDrawable; + private Drawable[] mDrawables; + private Paint mPaint; + private Paint mPaint2; + private float mPaintTextOffset; + private int[] mColors; + private PorterDuff.Mode[] mModes; + private int mModeIndex; + + private static void addToTheRight(Drawable curr, Drawable prev) { + Rect r = prev.getBounds(); + int x = r.right + 12; + int center = (r.top + r.bottom) >> 1; + int h = curr.getIntrinsicHeight(); + int y = center - (h >> 1); + + curr.setBounds(x, y, x + curr.getIntrinsicWidth(), y + h); + } + + public SampleView(Activity activity) { + super(activity); + mActivity = activity; + Context context = activity; + setFocusable(true); + + mDrawable = context.getResources().getDrawable(R.drawable.btn_default_normal); + mDrawable.setBounds(0, 0, 150, 48); + mDrawable.setDither(true); + + int[] resIDs = new int[] { + R.drawable.btn_circle_normal, + R.drawable.btn_check_off, + R.drawable.btn_check_on + }; + mDrawables = new Drawable[resIDs.length]; + Drawable prev = mDrawable; + for (int i = 0; i < resIDs.length; i++) { + mDrawables[i] = context.getResources().getDrawable(resIDs[i]); + mDrawables[i].setDither(true); + addToTheRight(mDrawables[i], prev); + prev = mDrawables[i]; + } + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(16); + mPaint.setTextAlign(Paint.Align.CENTER); + + mPaint2 = new Paint(mPaint); + mPaint2.setAlpha(64); + + Paint.FontMetrics fm = mPaint.getFontMetrics(); + mPaintTextOffset = (fm.descent + fm.ascent) * 0.5f; + + mColors = new int[] { + 0, + 0xCC0000FF, + 0x880000FF, + 0x440000FF, + 0xFFCCCCFF, + 0xFF8888FF, + 0xFF4444FF, + }; + + mModes = new PorterDuff.Mode[] { + PorterDuff.Mode.SRC_ATOP, + PorterDuff.Mode.MULTIPLY, + }; + mModeIndex = 0; + + updateTitle(); + } + + private void swapPaintColors() { + if (mPaint.getColor() == 0xFF000000) { + mPaint.setColor(0xFFFFFFFF); + mPaint2.setColor(0xFF000000); + } else { + mPaint.setColor(0xFF000000); + mPaint2.setColor(0xFFFFFFFF); + } + mPaint2.setAlpha(64); + } + + private void updateTitle() { + mActivity.setTitle(mModes[mModeIndex].toString()); + } + + private void drawSample(Canvas canvas, ColorFilter filter) { + Rect r = mDrawable.getBounds(); + float x = (r.left + r.right) * 0.5f; + float y = (r.top + r.bottom) * 0.5f - mPaintTextOffset; + + mDrawable.setColorFilter(filter); + mDrawable.draw(canvas); + canvas.drawText("Label", x+1, y+1, mPaint2); + canvas.drawText("Label", x, y, mPaint); + + for (Drawable dr : mDrawables) { + dr.setColorFilter(filter); + dr.draw(canvas); + } + } + + @Override protected void onDraw(Canvas canvas) { + canvas.drawColor(0xFFCCCCCC); + + canvas.translate(8, 12); + for (int color : mColors) { + ColorFilter filter; + if (color == 0) { + filter = null; + } else { + filter = new PorterDuffColorFilter(color, + mModes[mModeIndex]); + } + drawSample(canvas, filter); + canvas.translate(0, 55); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + break; + case MotionEvent.ACTION_MOVE: + break; + case MotionEvent.ACTION_UP: + // update mode every other time we change paint colors + if (mPaint.getColor() == 0xFFFFFFFF) { + mModeIndex = (mModeIndex + 1) % mModes.length; + updateTitle(); + } + swapPaintColors(); + invalidate(); + break; + } + return true; + } + } +} + diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/CubeRenderer.java b/samples/ApiDemos/src/com/example/android/apis/graphics/CubeRenderer.java index 527e2bc04..0f15f9131 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/CubeRenderer.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/CubeRenderer.java @@ -64,29 +64,6 @@ class CubeRenderer implements GLSurfaceView.Renderer { mAngle += 1.2f; } - public int[] getConfigSpec() { - if (mTranslucentBackground) { - // We want a depth buffer and an alpha buffer - int[] configSpec = { - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_ALPHA_SIZE, 8, - EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_NONE - }; - return configSpec; - } else { - // We want a depth buffer, don't care about the - // details of the color buffer. - int[] configSpec = { - EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_NONE - }; - return configSpec; - } - } - public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchRotateActivity.java b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchRotateActivity.java index 09d369441..c0f32a71a 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchRotateActivity.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchRotateActivity.java @@ -134,16 +134,6 @@ class TouchSurfaceView extends GLSurfaceView { mCube.draw(gl); } - public int[] getConfigSpec() { - // We want a depth buffer, don't care about the - // details of the color buffer. - int[] configSpec = { - EGL10.EGL_DEPTH_SIZE, 16, - EGL10.EGL_NONE - }; - return configSpec; - } - public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextRenderer.java b/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextRenderer.java index b9369cd7c..223300a8d 100644 --- a/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextRenderer.java +++ b/samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/SpriteTextRenderer.java @@ -50,16 +50,6 @@ public class SpriteTextRenderer implements GLSurfaceView.Renderer{ mLabelPaint.setARGB(0xff, 0x00, 0x00, 0x00); } - public int[] getConfigSpec() { - // We don't need a depth buffer, and don't care about our - // color depth. - int[] configSpec = { - EGL10.EGL_DEPTH_SIZE, 0, - EGL10.EGL_NONE - }; - return configSpec; - } - public void onSurfaceCreated(GL10 gl, EGLConfig config) { /* * By default, OpenGL enables features that improve quality diff --git a/samples/ApiDemos/tests/build.properties b/samples/ApiDemos/tests/build.properties new file mode 100644 index 000000000..8ae22a371 --- /dev/null +++ b/samples/ApiDemos/tests/build.properties @@ -0,0 +1 @@ +tested.project.dir=..
\ No newline at end of file diff --git a/samples/BrowserPlugin/Android.mk b/samples/BrowserPlugin/Android.mk new file mode 100644 index 000000000..16047d595 --- /dev/null +++ b/samples/BrowserPlugin/Android.mk @@ -0,0 +1,36 @@ +# 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. +# + +TOP_LOCAL_PATH:= $(call my-dir) + +# Build application + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := SampleBrowserPlugin + +LOCAL_JNI_SHARED_LIBRARIES := libsampleplugin + +include $(BUILD_PACKAGE) + +# ============================================================ + +# Also build all of the sub-targets under this one: the shared library. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/samples/BrowserPlugin/AndroidManifest.xml b/samples/BrowserPlugin/AndroidManifest.xml new file mode 100644 index 000000000..ae6b5dbe7 --- /dev/null +++ b/samples/BrowserPlugin/AndroidManifest.xml @@ -0,0 +1,35 @@ +<?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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sampleplugin" + android:versionCode="1" + android:versionName="1.0"> + + <uses-permission android:name="android.webkit.permission.PLUGIN"/> + + <uses-sdk android:minSdkVersion="3" /> + + <application android:icon="@drawable/sample_browser_plugin" + android:label="@string/sample_browser_plugin"> + <service android:name="SamplePlugin"> + <intent-filter> + <action android:name="android.webkit.PLUGIN" /> + </intent-filter> + </service> + </application> + +</manifest> diff --git a/samples/BrowserPlugin/MODULE_LICENSE_APACHE2 b/samples/BrowserPlugin/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/samples/BrowserPlugin/MODULE_LICENSE_APACHE2 diff --git a/samples/BrowserPlugin/NOTICE b/samples/BrowserPlugin/NOTICE new file mode 100644 index 000000000..c5b1efa7a --- /dev/null +++ b/samples/BrowserPlugin/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/samples/BrowserPlugin/README b/samples/BrowserPlugin/README new file mode 100644 index 000000000..08b04a517 --- /dev/null +++ b/samples/BrowserPlugin/README @@ -0,0 +1,173 @@ +# 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. +# + +############################## +######### CONTENTS ########### +A. INTRODUCTION +B. PLUGIN STRUCTURE +C. HOW TO DEPLOY +D. SUB-PLUGINS + 1. ANIMATION + 2. AUDIO + 3. BACKGROUND + 4. FORM + 5. PAINT + + +############################## +## (A) INTRODUCTION ########## + +The sample plugin is intended to give plugin developers a point of reference to +see how an android browser plugin is created and how to use the available APIs. +A plugin is packaged like a standard apk and can be installed either via the +market or adb. The sample plugin attempts to exercise as many of the APIs as +possible but unfortunately not all are covered. + +Trying to have a single plugin demonstrate all possible API interactions on one +screen was not practical. On the other hand we also didn't want a separate +plugin for each interction, as that would result in many separate apk's that +would need to be maintained. To solve this problem we developed the idea to use +"sub-plugins". With a sub-plugin only one specific feature of the plugin would +be active at a time, but they would all share as much common code as possible. +A detailed description of each sub-plugin and its function can be found in the +sub-plugins section. + +############################## +## (B) PLUGIN STRUCTURE ###### + +The sample plugin is packaged as one plugin but contains many unique sub-plugins +(e.g. audio and paint). The package consists of two pieces: (1) Java code +containing the config; (2) C++ shared library containing the brower/plugin +bindings and the sub-plugin classes. + +~~~~ (1) JAVA ~~~~~ +Android.mk: specifies the name of the APK (SampleBrowserPlugin) as well as which + shared libraries to include. + +AndroidManifest.xml: similar to a standard android manifest file, except that it + must contain the "uses-permission" and "intent-filter" + elements that are plugin specific. + +src/*: location of the java files which in our case is just an empty service + +res/*: location of the static resources (e.g. an icon for the plugin) + +~~~~ (2) C++ ~~~~~ +jni/Android.mk: specifies the build parameters for the shared library that is to + be included with the apk. The library contains all the bindings + between the plugin and the browser. + +jni/main.*: this code is the binding point between the plugin and the browser. + It supports all of the functions required for a standard netscape + style plugin as well as all the android specific APIs. The initial + starting point for the plugin is the NP_Initialize function. The + NPP_New function is responsible for reading the input args and + selecting the appropriate sub-plugin to instantiate. Most other + functions either return fixed values or pass their inputs to the + sub-plugin for processing. + +jni/PluginObject.*: The pluginObject provides a convenient container in which to + store variables (the plugin's state). This objects two main + responsibilities are (1) to construct and store the NPClass + object (done using code provided by Apple) and (2) provide + the abstract class for the sub-plugin objects and a place to + store the sub-plugin after it is instantiated. + +jni/*/*: Each of the sub-plugins has a folder that contains its class definition + and logic. The sub-plugin receives events from the browser and it can + also communicate with the browser using the netscape plugin functions + as well as the specialized android interfaces. + + +############################## +## (C) HOW TO DEPLOY ######### + +To compile and install a plugin on a device/emulator simply... + +1. run "make SampleBrowserPlugin" (compiles libsampleplugin.so and builds the apk) +2. the previous command produces an apk file so record its location +3. run "adb install [apk_file]" to install it on a device/emulator +4. the browser will auto recognize the plugin is available + +Now that the plugin is installed you can manage it just like you would any other +application via Settings -> Applications -> Manage applications. To execute the +plugin you need to include an html snippet (similar to the one found below) in +a document that is accessible by the browser. The mime-type cannot change but +you can change the width, height, and parameters. The parameters are used to +notify the plugin which sub-plugin to execute and which drawing model to use. + +<object type="application/x-testbrowserplugin" height=50 width=250> + <param name="DrawingModel" value="Surface" /> + <param name="PluginType" value="Background" /> +</object> + + +############################## +## (D) SUB-PLUGINS ########### + +Each sub-plugin corresponds to exactly one plugin type and can support one or +more drawing models. In the subsections below there are descriptions of each of +the sub-plugins as well as the information required to create the html snippets. + +####################### +## (D1) ANIMATION ##### + +PLUGIN TYPE: Animation +DRAWING MODEL: Bitmap + +This plugin draws a ball bouncing around the screen. If the plugin is not entirely +on the screen and it it touched, then it will attempt to center itself on screen. + +####################### +## (D2) AUDIO ######### + +PLUGIN TYPE: Audio +DRAWING MODEL: Bitmap + +This plugin plays a raw audio file located at /sdcard/sample.raw (need to supply +your own). It uses touch to trigger the play, pause, and stop buttons. + +####################### +## (D3) BACKGROUND #### + +PLUGIN TYPE: Background +DRAWING MODEL: Surface + +This plugin has minimal visual components but mainly runs API tests in the +background. The plugin handles scaling its own bitmap on zoom which in this +case is a simple string of text. The output of this plugin is found in the logs +as it prints errors if it detects any API failures. Some of the API's tested are +timers, javascript access, and bitmap formatting. + +####################### +## (D4) FORM ########## + +PLUGIN TYPE: Form +DRAWING MODEL: Bitmap + +This plugin mimics a simple username/password form. You can select a textbox by +either touching it or using the navigation keys. Once selected the box will +highlight and the keyboard will appear. If the textbox selected is not fully +in view then the plugin will ensure it is centered on the screen. + +####################### +## (D5) PAINT ######### + +PLUGIN TYPE: Paint +DRAWING MODEL: Surface + +This plugin provides a surface that the user can "paint" on. The inputs method +can be toggled between mouse (dots) and touch (lines). This plugin has a fixed +surface and allows the browser to scale the surface when zooming. diff --git a/samples/BrowserPlugin/jni/Android.mk b/samples/BrowserPlugin/jni/Android.mk new file mode 100644 index 000000000..cbd8a157d --- /dev/null +++ b/samples/BrowserPlugin/jni/Android.mk @@ -0,0 +1,64 @@ +## +## +## Copyright 2008, The Android Open Source Project +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR +## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +## + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + main.cpp \ + PluginObject.cpp \ + animation/AnimationPlugin.cpp \ + audio/AudioPlugin.cpp \ + background/BackgroundPlugin.cpp \ + form/FormPlugin.cpp \ + paint/PaintPlugin.cpp \ + jni-bridge.cpp \ + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/animation \ + $(LOCAL_PATH)/audio \ + $(LOCAL_PATH)/background \ + $(LOCAL_PATH)/form \ + $(LOCAL_PATH)/paint \ + external/webkit/WebCore/bridge \ + external/webkit/WebCore/plugins \ + external/webkit/WebCore/platform/android/JavaVM \ + external/webkit/WebKit/android/plugins + +LOCAL_SHARED_LIBRARIES := \ + libnativehelper + +LOCAL_CFLAGS += -fvisibility=hidden +LOCAL_PRELINK_MODULE:=false + +LOCAL_MODULE:= libsampleplugin + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + diff --git a/samples/BrowserPlugin/jni/PluginObject.cpp b/samples/BrowserPlugin/jni/PluginObject.cpp new file mode 100644 index 000000000..80f5e7cd7 --- /dev/null +++ b/samples/BrowserPlugin/jni/PluginObject.cpp @@ -0,0 +1,177 @@ +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation, + modification or redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in + this original Apple software (the "Apple Software"), to use, reproduce, modify and + redistribute the Apple Software, with or without modifications, in source and/or binary + forms; provided that if you redistribute the Apple Software in its entirety and without + modifications, you must retain this notice and the following text and disclaimers in all + such redistributions of the Apple Software. Neither the name, trademarks, service marks + or logos of Apple Computer, Inc. may be used to endorse or promote products derived from + the Apple Software without specific prior written permission from Apple. Except as expressly + stated in this notice, no other rights or licenses, express or implied, are granted by Apple + herein, including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include "main.h" +#include "PluginObject.h" + +static void pluginInvalidate(NPObject *obj); +static bool pluginHasProperty(NPObject *obj, NPIdentifier name); +static bool pluginHasMethod(NPObject *obj, NPIdentifier name); +static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant); +static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant); +static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); +static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +static NPObject *pluginAllocate(NPP npp, NPClass *theClass); +static void pluginDeallocate(NPObject *obj); +static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name); +static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count); + + + +static NPClass pluginClass = { + NP_CLASS_STRUCT_VERSION, + pluginAllocate, + pluginDeallocate, + pluginInvalidate, + pluginHasMethod, + pluginInvoke, + pluginInvokeDefault, + pluginHasProperty, + pluginGetProperty, + pluginSetProperty, + pluginRemoveProperty, + pluginEnumerate +}; + +NPClass *getPluginClass(void) +{ + return &pluginClass; +} + +static bool identifiersInitialized = false; + +#define ID_TESTFILE_PROPERTY 0 +#define NUM_PROPERTY_IDENTIFIERS 1 + +static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS]; +static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { + "testfile" +}; + +#define ID_GETTESTFILE_METHOD 0 +#define NUM_METHOD_IDENTIFIERS 1 + +static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; +static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { + "getTestFile" +}; + +static void initializeIdentifiers(void) +{ + browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers); + browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers); +} + +static bool pluginHasProperty(NPObject *obj, NPIdentifier name) +{ + int i; + for (i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) + if (name == pluginPropertyIdentifiers[i]) + return true; + return false; +} + +static bool pluginHasMethod(NPObject *obj, NPIdentifier name) +{ + int i; + for (i = 0; i < NUM_METHOD_IDENTIFIERS; i++) + if (name == pluginMethodIdentifiers[i]) + return true; + return false; +} + +static bool pluginGetProperty(NPObject *obj, NPIdentifier name, NPVariant *variant) +{ + PluginObject *plugin = (PluginObject *)obj; + if (name == pluginPropertyIdentifiers[ID_TESTFILE_PROPERTY]) { + BOOLEAN_TO_NPVARIANT(true, *variant); + return true; + } + return false; +} + +static bool pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant) +{ + return false; +} + +static bool pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + PluginObject *plugin = (PluginObject *)obj; + if (name == pluginMethodIdentifiers[ID_GETTESTFILE_METHOD]) { + return true; + } + return false; +} + +static bool pluginInvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return false; +} + +static void pluginInvalidate(NPObject *obj) +{ + // Release any remaining references to JavaScript objects. +} + +static NPObject *pluginAllocate(NPP npp, NPClass *theClass) +{ + PluginObject *newInstance = (PluginObject*) malloc(sizeof(PluginObject)); + newInstance->header._class = theClass; + newInstance->header.referenceCount = 1; + + if (!identifiersInitialized) { + identifiersInitialized = true; + initializeIdentifiers(); + } + + newInstance->npp = npp; + + return &newInstance->header; +} + +static void pluginDeallocate(NPObject *obj) +{ + free(obj); +} + +static bool pluginRemoveProperty(NPObject *npobj, NPIdentifier name) +{ + return false; +} + +static bool pluginEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + return false; +} diff --git a/samples/BrowserPlugin/jni/PluginObject.h b/samples/BrowserPlugin/jni/PluginObject.h new file mode 100644 index 000000000..61486d599 --- /dev/null +++ b/samples/BrowserPlugin/jni/PluginObject.h @@ -0,0 +1,85 @@ +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation, + modification or redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in + this original Apple software (the "Apple Software"), to use, reproduce, modify and + redistribute the Apple Software, with or without modifications, in source and/or binary + forms; provided that if you redistribute the Apple Software in its entirety and without + modifications, you must retain this notice and the following text and disclaimers in all + such redistributions of the Apple Software. Neither the name, trademarks, service marks + or logos of Apple Computer, Inc. may be used to endorse or promote products derived from + the Apple Software without specific prior written permission from Apple. Except as expressly + stated in this notice, no other rights or licenses, express or implied, are granted by Apple + herein, including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PluginObject__DEFINED +#define PluginObject__DEFINED + +#include "main.h" +#include <jni.h> + +class SubPlugin { +public: + SubPlugin(NPP inst) : m_inst(inst) {} + virtual ~SubPlugin() {} + virtual int16 handleEvent(const ANPEvent* evt) = 0; + virtual bool supportsDrawingModel(ANPDrawingModel) = 0; + + NPP inst() const { return m_inst; } + +private: + NPP m_inst; +}; + +class SurfaceSubPlugin : public SubPlugin { +public: + SurfaceSubPlugin(NPP inst) : SubPlugin(inst) {} + virtual ~SurfaceSubPlugin() {} + virtual bool isFixedSurface() = 0; + virtual void surfaceCreated(JNIEnv*, jobject) = 0; + virtual void surfaceChanged(int format, int width, int height) = 0; + virtual void surfaceDestroyed() = 0; +}; + +enum PluginTypes { + kAnimation_PluginType = 1, + kAudio_PluginType = 2, + kBackground_PluginType = 3, + kForm_PluginType = 4, + kText_PluginType = 5, + kPaint_PluginType = 6, +}; +typedef uint32_t PluginType; + +typedef struct PluginObject { + NPObject header; + NPP npp; + NPWindow* window; + + PluginType pluginType; + SubPlugin* activePlugin; + +} PluginObject; + +NPClass *getPluginClass(void); + +#endif // PluginObject__DEFINED diff --git a/samples/BrowserPlugin/jni/animation/AnimationPlugin.cpp b/samples/BrowserPlugin/jni/animation/AnimationPlugin.cpp new file mode 100644 index 000000000..b6175c161 --- /dev/null +++ b/samples/BrowserPlugin/jni/animation/AnimationPlugin.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AnimationPlugin.h" + +#include <math.h> +#include <string.h> + +extern NPNetscapeFuncs* browser; +extern ANPLogInterfaceV0 gLogI; +extern ANPCanvasInterfaceV0 gCanvasI; +extern ANPPaintInterfaceV0 gPaintI; +extern ANPPathInterfaceV0 gPathI; +extern ANPWindowInterfaceV0 gWindowI; + +static uint16 rnd16(float x, int inset) { + int ix = (int)roundf(x) + inset; + if (ix < 0) { + ix = 0; + } + return static_cast<uint16>(ix); +} + +static void inval(NPP instance, const ANPRectF& r, bool doAA) { + const int inset = doAA ? -1 : 0; + + NPRect inval; + inval.left = rnd16(r.left, inset); + inval.top = rnd16(r.top, inset); + inval.right = rnd16(r.right, -inset); + inval.bottom = rnd16(r.bottom, -inset); + browser->invalidaterect(instance, &inval); +} + +static void bounce(float* x, float* dx, const float max) { + *x += *dx; + if (*x < 0) { + *x = 0; + if (*dx < 0) { + *dx = -*dx; + } + } else if (*x > max) { + *x = max; + if (*dx > 0) { + *dx = -*dx; + } + } +} +/////////////////////////////////////////////////////////////////////////////// + +BallAnimation::BallAnimation(NPP inst) : SubPlugin(inst) { + m_x = m_y = 0; + m_dx = 7 * SCALE; + m_dy = 5 * SCALE; + + memset(&m_oval, 0, sizeof(m_oval)); + + m_paint = gPaintI.newPaint(); + gPaintI.setFlags(m_paint, gPaintI.getFlags(m_paint) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paint, 0xFFFF0000); + + //register for touch events + ANPEventFlags flags = kTouch_ANPEventFlag; + NPError err = browser->setvalue(inst, kAcceptEvents_ANPSetValue, &flags); + if (err != NPERR_NO_ERROR) { + gLogI.log(inst, kError_ANPLogType, "Error selecting input events."); + } +} + +BallAnimation::~BallAnimation() { + gPaintI.deletePaint(m_paint); +} + +bool BallAnimation::supportsDrawingModel(ANPDrawingModel model) { + return (model == kBitmap_ANPDrawingModel); +} + +void BallAnimation::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) { + + // create a canvas + ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); + + // clip the canvas + ANPRectF clipR; + clipR.left = clip.left; + clipR.top = clip.top; + clipR.right = clip.right; + clipR.bottom = clip.bottom; + gCanvasI.clipRect(canvas, &clipR); + + // setup variables + PluginObject *obj = (PluginObject*) inst()->pdata; + const float OW = 20; + const float OH = 20; + const int W = obj->window->width; + const int H = obj->window->height; + + // paint the canvas (using the path API) + gCanvasI.drawColor(canvas, 0xFFFFFFFF); + { + ANPPath* path = gPathI.newPath(); + + float cx = W * 0.5f; + float cy = H * 0.5f; + gPathI.moveTo(path, 0, 0); + gPathI.quadTo(path, cx, cy, W, 0); + gPathI.quadTo(path, cx, cy, W, H); + gPathI.quadTo(path, cx, cy, 0, H); + gPathI.quadTo(path, cx, cy, 0, 0); + + gPaintI.setColor(m_paint, 0xFF0000FF); + gCanvasI.drawPath(canvas, path, m_paint); + + ANPRectF bounds; + memset(&bounds, 0, sizeof(bounds)); + gPathI.getBounds(path, &bounds); + gPathI.deletePath(path); + } + + // draw the oval + inval(inst(), m_oval, true); // inval the old + m_oval.left = m_x; + m_oval.top = m_y; + m_oval.right = m_x + OW; + m_oval.bottom = m_y + OH; + inval(inst(), m_oval, true); // inval the new + gPaintI.setColor(m_paint, 0xFFFF0000); + gCanvasI.drawOval(canvas, &m_oval, m_paint); + + // update the coordinates of the oval + bounce(&m_x, &m_dx, obj->window->width - OW); + bounce(&m_y, &m_dy, obj->window->height - OH); + + // delete the canvas + gCanvasI.deleteCanvas(canvas); +} + +void BallAnimation::showEntirePluginOnScreen() { + NPP instance = this->inst(); + PluginObject *obj = (PluginObject*) instance->pdata; + NPWindow *window = obj->window; + + ANPRectI visibleRects[1]; + + visibleRects[0].left = 0; + visibleRects[0].top = 0; + visibleRects[0].right = window->width; + visibleRects[0].bottom = window->height; + + gWindowI.setVisibleRects(instance, visibleRects, 1); + gWindowI.clearVisibleRects(instance); +} + +int16 BallAnimation::handleEvent(const ANPEvent* evt) { + NPP instance = this->inst(); + + switch (evt->eventType) { + case kDraw_ANPEventType: + switch (evt->data.draw.model) { + case kBitmap_ANPDrawingModel: + drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip); + return 1; + default: + break; // unknown drawing model + } + case kTouch_ANPEventType: + if (kDown_ANPTouchAction == evt->data.touch.action) { + showEntirePluginOnScreen(); + } + return 1; + default: + break; + } + return 0; // unknown or unhandled event +} diff --git a/samples/BrowserPlugin/jni/animation/AnimationPlugin.h b/samples/BrowserPlugin/jni/animation/AnimationPlugin.h new file mode 100644 index 000000000..ef2a3f540 --- /dev/null +++ b/samples/BrowserPlugin/jni/animation/AnimationPlugin.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PluginObject.h" + +#ifndef pluginGraphics__DEFINED +#define pluginGraphics__DEFINED + +class BallAnimation : public SubPlugin { +public: + BallAnimation(NPP inst); + virtual ~BallAnimation(); + virtual bool supportsDrawingModel(ANPDrawingModel); + virtual int16 handleEvent(const ANPEvent* evt); +private: + void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip); + void showEntirePluginOnScreen(); + + float m_x; + float m_y; + float m_dx; + float m_dy; + + ANPRectF m_oval; + ANPPaint* m_paint; + + static const float SCALE = 0.1; +}; + +#endif // pluginGraphics__DEFINED diff --git a/samples/BrowserPlugin/jni/audio/AudioPlugin.cpp b/samples/BrowserPlugin/jni/audio/AudioPlugin.cpp new file mode 100644 index 000000000..58d340cb3 --- /dev/null +++ b/samples/BrowserPlugin/jni/audio/AudioPlugin.cpp @@ -0,0 +1,382 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "AudioPlugin.h" + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <time.h> +#include <math.h> +#include <string.h> + +extern NPNetscapeFuncs* browser; +extern ANPLogInterfaceV0 gLogI; +extern ANPCanvasInterfaceV0 gCanvasI; +extern ANPPaintInterfaceV0 gPaintI; +extern ANPAudioTrackInterfaceV0 gSoundI; +extern ANPTypefaceInterfaceV0 gTypefaceI; + + +static void inval(NPP instance) { + browser->invalidaterect(instance, NULL); +} + +static uint16 rnd16(float x, int inset) { + int ix = (int)roundf(x) + inset; + if (ix < 0) { + ix = 0; + } + return static_cast<uint16>(ix); +} + +static void inval(NPP instance, const ANPRectF& r, bool doAA) { + const int inset = doAA ? -1 : 0; + + PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); + NPRect inval; + inval.left = rnd16(r.left, inset); + inval.top = rnd16(r.top, inset); + inval.right = rnd16(r.right, -inset); + inval.bottom = rnd16(r.bottom, -inset); + browser->invalidaterect(instance, &inval); +} + +static void audioCallback(ANPAudioEvent evt, void* user, ANPAudioBuffer* buffer) { + switch (evt) { + case kMoreData_ANPAudioEvent: { + SoundPlay* play = reinterpret_cast<SoundPlay*>(user); + size_t amount = fread(buffer->bufferData, 1, buffer->size, play->file); + buffer->size = amount; + if (amount == 0) { + gSoundI.stop(play->track); + fclose(play->file); + play->file = NULL; + // TODO need to notify our main thread to delete the track now + } + + if (play->fileSize > 0) { + // TODO we need to properly update the progress value + play->progress = 1; + inval(play->instance); + } + + + break; + } + default: + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +AudioPlugin::AudioPlugin(NPP inst) : SubPlugin(inst) { + + const char path[] = "/sdcard/sample.raw"; + + // open a file stream + FILE* f = fopen(path, "r"); + gLogI.log(inst, kDebug_ANPLogType, "--- path %s FILE %p", path, f); + + // setup our private audio struct's default values + m_soundPlay = new SoundPlay; + m_soundPlay->instance = inst; + m_soundPlay->progress = 0; + m_soundPlay->fileSize = 0; + m_soundPlay->file = f; + m_soundPlay->track = NULL; + + // create the audio track + if (f) { + m_soundPlay->track = gSoundI.newTrack(44100, kPCM16Bit_ANPSampleFormat, 2, audioCallback, m_soundPlay); + if (!m_soundPlay->track) { + fclose(f); + m_soundPlay->file = NULL; + } + } + + // get the audio file's size + int fileDescriptor = open(path, O_RDONLY); + struct stat fileStatus; + + if(fileDescriptor <= 0) { + gLogI.log(inst, kError_ANPLogType, "fopen error"); + } + else if (fstat(fileDescriptor, &fileStatus) != 0) { + gLogI.log(inst, kDebug_ANPLogType, "File Size: %d", fileStatus.st_size); + m_soundPlay->fileSize = fileStatus.st_size; + } else { + gLogI.log(inst, kError_ANPLogType, "fstat error"); + } + + // configure the UI elements + m_activeTouch = false; + + memset(&m_trackRect, 0, sizeof(m_trackRect)); + memset(&m_playRect, 0, sizeof(m_playRect)); + memset(&m_pauseRect, 0, sizeof(m_pauseRect)); + memset(&m_stopRect, 0, sizeof(m_stopRect)); + + m_paintTrack = gPaintI.newPaint(); + gPaintI.setFlags(m_paintTrack, gPaintI.getFlags(m_paintTrack) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintTrack, 0xFFC0C0C0); + + m_paintRect = gPaintI.newPaint(); + gPaintI.setFlags(m_paintRect, gPaintI.getFlags(m_paintRect) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintRect, 0xFFA8A8A8); + + m_paintText = gPaintI.newPaint(); + gPaintI.setFlags(m_paintText, gPaintI.getFlags(m_paintText) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintText, 0xFF2F4F4F); + gPaintI.setTextSize(m_paintText, 18); + + m_paintTrackProgress = gPaintI.newPaint(); + gPaintI.setFlags(m_paintTrackProgress, gPaintI.getFlags(m_paintTrackProgress) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintTrackProgress, 0xFF545454); + + m_paintActiveRect = gPaintI.newPaint(); + gPaintI.setFlags(m_paintActiveRect, gPaintI.getFlags(m_paintActiveRect) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintActiveRect, 0xFF545454); + + ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle); + gPaintI.setTypeface(m_paintText, tf); + gTypefaceI.unref(tf); + + //register for touch events + ANPEventFlags flags = kTouch_ANPEventFlag; + NPError err = browser->setvalue(inst, kAcceptEvents_ANPSetValue, &flags); + if (err != NPERR_NO_ERROR) { + gLogI.log(inst, kError_ANPLogType, "Error selecting input events."); + } +} + +AudioPlugin::~AudioPlugin() { + gPaintI.deletePaint(m_paintTrack); + gPaintI.deletePaint(m_paintRect); + gPaintI.deletePaint(m_paintText); + gPaintI.deletePaint(m_paintTrackProgress); + gPaintI.deletePaint(m_paintActiveRect); + if(m_soundPlay->track) + gSoundI.deleteTrack(m_soundPlay->track); + delete m_soundPlay; +} + +bool AudioPlugin::supportsDrawingModel(ANPDrawingModel model) { + return (model == kBitmap_ANPDrawingModel); +} + +void AudioPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) { + ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); + + ANPRectF clipR; + clipR.left = clip.left; + clipR.top = clip.top; + clipR.right = clip.right; + clipR.bottom = clip.bottom; + gCanvasI.clipRect(canvas, &clipR); + + draw(canvas); + gCanvasI.deleteCanvas(canvas); +} + +void AudioPlugin::draw(ANPCanvas* canvas) { + NPP instance = this->inst(); + PluginObject *obj = (PluginObject*) instance->pdata; + + gLogI.log(instance, kError_ANPLogType, "Drawing"); + + const float trackHeight = 30; + const float buttonWidth = 60; + const float buttonHeight = 30; + const int W = obj->window->width; + const int H = obj->window->height; + + // color the plugin canvas + gCanvasI.drawColor(canvas, 0xFFCDCDCD); + + // get font metrics + ANPFontMetrics fontMetrics; + gPaintI.getFontMetrics(m_paintText, &fontMetrics); + + // draw the track box (1 px from the edge) + m_trackRect.left = 1; + m_trackRect.top = 1; + m_trackRect.right = W - 2; + m_trackRect.bottom = 1 + trackHeight; + gCanvasI.drawRect(canvas, &m_trackRect, m_paintTrack); + + // draw the progress bar + if (m_soundPlay->progress > 0) { + // TODO need to draw progress bar to cover the proper percentage of the track bar + gCanvasI.drawRect(canvas, &m_trackRect, m_paintTrackProgress); + } + + // draw the play box (under track box) + m_playRect.left = m_trackRect.left + 5; + m_playRect.top = m_trackRect.bottom + 10; + m_playRect.right = m_playRect.left + buttonWidth; + m_playRect.bottom = m_playRect.top + buttonHeight; + gCanvasI.drawRect(canvas, &m_playRect, getPaint(&m_playRect)); + // draw the play box (under track box) + const char playText[] = "Play"; + gCanvasI.drawText(canvas, playText, sizeof(playText)-1, m_playRect.left + 5, + m_playRect.top - fontMetrics.fTop, m_paintText); + + // draw the pause box (under track box) + m_pauseRect.left = m_playRect.right + 20; + m_pauseRect.top = m_trackRect.bottom + 10; + m_pauseRect.right = m_pauseRect.left + buttonWidth; + m_pauseRect.bottom = m_pauseRect.top + buttonHeight; + gCanvasI.drawRect(canvas, &m_pauseRect, getPaint(&m_pauseRect)); + // draw the text in the pause box + const char pauseText[] = "Pause"; + gCanvasI.drawText(canvas, pauseText, sizeof(pauseText)-1, m_pauseRect.left + 5, + m_pauseRect.top - fontMetrics.fTop, m_paintText); + + // draw the stop box (under track box) + m_stopRect.left = m_pauseRect.right + 20; + m_stopRect.top = m_trackRect.bottom + 10; + m_stopRect.right = m_stopRect.left + buttonWidth; + m_stopRect.bottom = m_stopRect.top + buttonHeight; + gCanvasI.drawRect(canvas, &m_stopRect, getPaint(&m_stopRect)); + // draw the text in the pause box + const char stopText[] = "Stop"; + gCanvasI.drawText(canvas, stopText, sizeof(stopText)-1, m_stopRect.left + 5, + m_stopRect.top - fontMetrics.fTop, m_paintText); +} + +ANPPaint* AudioPlugin::getPaint(ANPRectF* input) { + return (input == m_activeRect) ? m_paintActiveRect : m_paintRect; +} + +int16 AudioPlugin::handleEvent(const ANPEvent* evt) { + NPP instance = this->inst(); + + switch (evt->eventType) { + case kDraw_ANPEventType: + switch (evt->data.draw.model) { + case kBitmap_ANPDrawingModel: + drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip); + return 1; + default: + break; // unknown drawing model + } + + case kTouch_ANPEventType: { + int x = evt->data.touch.x; + int y = evt->data.touch.y; + if (kDown_ANPTouchAction == evt->data.touch.action) { + + m_activeTouchRect = validTouch(x,y); + if(m_activeTouchRect) { + m_activeTouch = true; + return 1; + } + + } else if (kUp_ANPTouchAction == evt->data.touch.action && m_activeTouch) { + handleTouch(x, y); + m_activeTouch = false; + return 1; + } else if (kCancel_ANPTouchAction == evt->data.touch.action) { + m_activeTouch = false; + } + break; + } + default: + break; + } + return 0; // unknown or unhandled event +} + +void AudioPlugin::invalActiveRect() { + +} + +ANPRectF* AudioPlugin::validTouch(int x, int y) { + + if (m_playRect.left && x < m_playRect.right && y > m_playRect.top && y < m_playRect.bottom) + return &m_playRect; + else if (m_pauseRect.left && x < m_pauseRect.right && y > m_pauseRect.top && y < m_pauseRect.bottom) + return &m_pauseRect; + else if (x > m_stopRect.left && x < m_stopRect.right && y > m_stopRect.top && y < m_stopRect.bottom) + return &m_stopRect; + else + return NULL; +} + +void AudioPlugin::handleTouch(int x, int y) { + NPP instance = this->inst(); + + // if the track is null then return + if (NULL == m_soundPlay->track) { + gLogI.log(instance, kError_ANPLogType, "---- %p unable to create track", + instance); + return; + } + + // check to make sure the currentRect matches the activeRect + ANPRectF* currentRect = validTouch(x,y); + if (m_activeTouchRect != currentRect) + return; + + if (currentRect == &m_playRect) { + + gLogI.log(instance, kDebug_ANPLogType, "---- %p starting track (%d)", + m_soundPlay->track, gSoundI.isStopped(m_soundPlay->track)); + + if (gSoundI.isStopped(m_soundPlay->track)) { + gSoundI.start(m_soundPlay->track); + } + } + else if (currentRect == &m_pauseRect) { + + gLogI.log(instance, kDebug_ANPLogType, "---- %p pausing track (%d)", + m_soundPlay->track, gSoundI.isStopped(m_soundPlay->track)); + + if (!gSoundI.isStopped(m_soundPlay->track)) { + gSoundI.pause(m_soundPlay->track); + } + } + else if (currentRect == &m_stopRect) { + + gLogI.log(instance, kDebug_ANPLogType, "---- %p stopping track (%d)", + m_soundPlay->track, gSoundI.isStopped(m_soundPlay->track)); + + if (!gSoundI.isStopped(m_soundPlay->track)) { + gSoundI.stop(m_soundPlay->track); + } + if (m_soundPlay->file) { + fseek(m_soundPlay->file, 0, SEEK_SET); + } + } + else { + return; + } + + // set the currentRect to be the activeRect + m_activeRect = currentRect; + inval(instance); +} diff --git a/samples/BrowserPlugin/jni/audio/AudioPlugin.h b/samples/BrowserPlugin/jni/audio/AudioPlugin.h new file mode 100644 index 000000000..129d33a78 --- /dev/null +++ b/samples/BrowserPlugin/jni/audio/AudioPlugin.h @@ -0,0 +1,74 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PluginObject.h" +#include <stdio.h> + +#ifndef audioPlugin__DEFINED +#define audioPlugin__DEFINED + +struct SoundPlay { + NPP instance; + ANPAudioTrack* track; + FILE* file; + int fileSize; + int progress; // value between 0 and 100 +}; + +class AudioPlugin : public SubPlugin { +public: + AudioPlugin(NPP inst); + virtual ~AudioPlugin(); + virtual bool supportsDrawingModel(ANPDrawingModel); + virtual int16 handleEvent(const ANPEvent* evt); +private: + void draw(ANPCanvas*); + void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip); + + void handleTouch(int x, int y); + void invalActiveRect(); + ANPPaint* getPaint(ANPRectF*); + ANPRectF* validTouch(int x, int y); + + ANPRectF m_trackRect; + ANPRectF m_playRect; + ANPRectF m_pauseRect; + ANPRectF m_stopRect; + + ANPPaint* m_paintTrack; + ANPPaint* m_paintRect; + ANPPaint* m_paintText; + + ANPPaint* m_paintTrackProgress; + ANPPaint* m_paintActiveRect; + + SoundPlay* m_soundPlay; + + bool m_activeTouch; + ANPRectF* m_activeTouchRect; + ANPRectF* m_activeRect; +}; + +#endif // audioPlugin__DEFINED diff --git a/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp b/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp new file mode 100644 index 000000000..2a65b4f60 --- /dev/null +++ b/samples/BrowserPlugin/jni/background/BackgroundPlugin.cpp @@ -0,0 +1,423 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BackgroundPlugin.h" +#include "android_npapi.h" + +#include <stdio.h> +#include <sys/time.h> +#include <time.h> +#include <math.h> +#include <string.h> + +extern NPNetscapeFuncs* browser; +extern ANPBitmapInterfaceV0 gBitmapI; +extern ANPCanvasInterfaceV0 gCanvasI; +extern ANPLogInterfaceV0 gLogI; +extern ANPPaintInterfaceV0 gPaintI; +extern ANPSurfaceInterfaceV0 gSurfaceI; +extern ANPTypefaceInterfaceV0 gTypefaceI; + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) + +static uint32_t getMSecs() { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint32_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds +} + +/////////////////////////////////////////////////////////////////////////////// + +BackgroundPlugin::BackgroundPlugin(NPP inst) : SurfaceSubPlugin(inst) { + + // initialize the drawing surface + m_surface = NULL; + m_vm = NULL; + + //initialize bitmap transparency variables + mFinishedStageOne = false; + mFinishedStageTwo = false; + mFinishedStageThree = false; + + // test basic plugin functionality + test_logging(); // android logging + test_timers(); // plugin timers + test_bitmaps(); // android bitmaps + test_domAccess(); + test_javascript(); +} + +BackgroundPlugin::~BackgroundPlugin() { } + +bool BackgroundPlugin::supportsDrawingModel(ANPDrawingModel model) { + return (model == kSurface_ANPDrawingModel); +} + +bool BackgroundPlugin::isFixedSurface() { + return false; +} + +void BackgroundPlugin::surfaceCreated(JNIEnv* env, jobject surface) { + env->GetJavaVM(&m_vm); + m_surface = env->NewGlobalRef(surface); +} + +void BackgroundPlugin::surfaceChanged(int format, int width, int height) { + drawPlugin(width, height); +} + +void BackgroundPlugin::surfaceDestroyed() { + JNIEnv* env = NULL; + if (m_surface && m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) { + env->DeleteGlobalRef(m_surface); + m_surface = NULL; + } +} + +void BackgroundPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) { + + // get the plugin's dimensions according to the DOM + PluginObject *obj = (PluginObject*) inst()->pdata; + const int W = obj->window->width; + const int H = obj->window->height; + + // compute the current zoom level + const float zoomFactorW = static_cast<float>(surfaceWidth) / W; + const float zoomFactorH = static_cast<float>(surfaceHeight) / H; + + // check to make sure the zoom level is uniform + if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH) + gLogI.log(inst(), kError_ANPLogType, " ------ %p zoom is out of sync (%f,%f)", + inst(), zoomFactorW, zoomFactorH); + + // scale the variables based on the zoom level + const int fontSize = (int)(zoomFactorW * 16); + const int leftMargin = (int)(zoomFactorW * 10); + + // lock the surface + ANPBitmap bitmap; + JNIEnv* env = NULL; + if (!m_surface || m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK || + !gSurfaceI.lock(env, m_surface, &bitmap, NULL)) { + gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst()); + return; + } + + // create a canvas + ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); + gCanvasI.drawColor(canvas, 0xFFFFFFFF); + + ANPPaint* paint = gPaintI.newPaint(); + gPaintI.setFlags(paint, gPaintI.getFlags(paint) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(paint, 0xFFFF0000); + gPaintI.setTextSize(paint, fontSize); + + ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle); + gPaintI.setTypeface(paint, tf); + gTypefaceI.unref(tf); + + ANPFontMetrics fm; + gPaintI.getFontMetrics(paint, &fm); + + gPaintI.setColor(paint, 0xFF0000FF); + const char c[] = "This is a background plugin."; + gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint); + + // clean up variables and unlock the surface + gPaintI.deletePaint(paint); + gCanvasI.deleteCanvas(canvas); + gSurfaceI.unlock(env, m_surface); +} + +int16 BackgroundPlugin::handleEvent(const ANPEvent* evt) { + switch (evt->eventType) { + case kDraw_ANPEventType: + gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst()); + break; + case kLifecycle_ANPEventType: + if (evt->data.lifecycle.action == kOnLoad_ANPLifecycleAction) { + gLogI.log(inst(), kDebug_ANPLogType, " ------ %p the plugin received an onLoad event", inst()); + return 1; + } + break; + case kTouch_ANPEventType: + gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request touch events", inst()); + break; + case kKey_ANPEventType: + gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request key events", inst()); + break; + default: + break; + } + return 0; // unknown or unhandled event +} + +/////////////////////////////////////////////////////////////////////////////// +// LOGGING TESTS +/////////////////////////////////////////////////////////////////////////////// + + +void BackgroundPlugin::test_logging() { + NPP instance = this->inst(); + + //LOG_ERROR(instance, " ------ %p Testing Log Error", instance); + gLogI.log(instance, kError_ANPLogType, " ------ %p Testing Log Error", instance); + gLogI.log(instance, kWarning_ANPLogType, " ------ %p Testing Log Warning", instance); + gLogI.log(instance, kDebug_ANPLogType, " ------ %p Testing Log Debug", instance); +} + +/////////////////////////////////////////////////////////////////////////////// +// TIMER TESTS +/////////////////////////////////////////////////////////////////////////////// + +#define TIMER_INTERVAL 50 +static void timer_oneshot(NPP instance, uint32 timerID); +static void timer_repeat(NPP instance, uint32 timerID); +static void timer_neverfires(NPP instance, uint32 timerID); +static void timer_latency(NPP instance, uint32 timerID); + +void BackgroundPlugin::test_timers() { + NPP instance = this->inst(); + + //Setup the testing counters + mTimerRepeatCount = 5; + mTimerLatencyCount = 5; + + // test for bogus timerID + browser->unscheduletimer(instance, 999999); + // test one-shot + browser->scheduletimer(instance, 100, false, timer_oneshot); + // test repeat + browser->scheduletimer(instance, 50, true, timer_repeat); + // test timer latency + browser->scheduletimer(instance, TIMER_INTERVAL, true, timer_latency); + mStartTime = mPrevTime = getMSecs(); + // test unschedule immediately + uint32 id = browser->scheduletimer(instance, 100, false, timer_neverfires); + browser->unscheduletimer(instance, id); + // test double unschedule (should be no-op) + browser->unscheduletimer(instance, id); + +} + +static void timer_oneshot(NPP instance, uint32 timerID) { + gLogI.log(instance, kDebug_ANPLogType, "-------- oneshot timer\n"); +} + +static void timer_repeat(NPP instance, uint32 timerID) { + BackgroundPlugin *obj = ((BackgroundPlugin*) ((PluginObject*) instance->pdata)->activePlugin); + + gLogI.log(instance, kDebug_ANPLogType, "-------- repeat timer %d\n", + obj->mTimerRepeatCount); + if (--obj->mTimerRepeatCount == 0) { + browser->unscheduletimer(instance, timerID); + } +} + +static void timer_neverfires(NPP instance, uint32 timerID) { + gLogI.log(instance, kError_ANPLogType, "-------- timer_neverfires!!!\n"); +} + +static void timer_latency(NPP instance, uint32 timerID) { + BackgroundPlugin *obj = ((BackgroundPlugin*) ((PluginObject*) instance->pdata)->activePlugin); + + obj->mTimerLatencyCurrentCount += 1; + + uint32_t now = getMSecs(); + uint32_t interval = now - obj->mPrevTime; + uint32_t dur = now - obj->mStartTime; + uint32_t expectedDur = obj->mTimerLatencyCurrentCount * TIMER_INTERVAL; + int32_t drift = dur - expectedDur; + int32_t avgDrift = drift / obj->mTimerLatencyCurrentCount; + + obj->mPrevTime = now; + + gLogI.log(instance, kDebug_ANPLogType, + "-------- latency test: [%3d] interval %d expected %d, total %d expected %d, drift %d avg %d\n", + obj->mTimerLatencyCurrentCount, interval, TIMER_INTERVAL, dur, + expectedDur, drift, avgDrift); + + if (--obj->mTimerLatencyCount == 0) { + browser->unscheduletimer(instance, timerID); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// BITMAP TESTS +/////////////////////////////////////////////////////////////////////////////// + +static void test_formats(NPP instance); + +void BackgroundPlugin::test_bitmaps() { + test_formats(this->inst()); +} + +static void test_formats(NPP instance) { + + // TODO pull names from enum in npapi instead of hardcoding them + static const struct { + ANPBitmapFormat fFormat; + const char* fName; + } gRecs[] = { + { kUnknown_ANPBitmapFormat, "unknown" }, + { kRGBA_8888_ANPBitmapFormat, "8888" }, + { kRGB_565_ANPBitmapFormat, "565" }, + }; + + ANPPixelPacking packing; + for (size_t i = 0; i < ARRAY_COUNT(gRecs); i++) { + if (gBitmapI.getPixelPacking(gRecs[i].fFormat, &packing)) { + gLogI.log(instance, kDebug_ANPLogType, + "pixel format [%d] %s has packing ARGB [%d %d] [%d %d] [%d %d] [%d %d]\n", + gRecs[i].fFormat, gRecs[i].fName, + packing.AShift, packing.ABits, + packing.RShift, packing.RBits, + packing.GShift, packing.GBits, + packing.BShift, packing.BBits); + } else { + gLogI.log(instance, kDebug_ANPLogType, + "pixel format [%d] %s has no packing\n", + gRecs[i].fFormat, gRecs[i].fName); + } + } +} + +void BackgroundPlugin::test_bitmap_transparency(const ANPEvent* evt) { + NPP instance = this->inst(); + + // check default & set transparent + if (!mFinishedStageOne) { + + gLogI.log(instance, kDebug_ANPLogType, "BEGIN: testing bitmap transparency"); + + //check to make sure it is not transparent + if (evt->data.draw.data.bitmap.format == kRGBA_8888_ANPBitmapFormat) { + gLogI.log(instance, kError_ANPLogType, "bitmap default format is transparent"); + } + + //make it transparent (any non-null value will set it to true) + bool value = true; + NPError err = browser->setvalue(instance, NPPVpluginTransparentBool, &value); + if (err != NPERR_NO_ERROR) { + gLogI.log(instance, kError_ANPLogType, "Error setting transparency."); + } + + mFinishedStageOne = true; + browser->invalidaterect(instance, NULL); + } + // check transparent & set opaque + else if (!mFinishedStageTwo) { + + //check to make sure it is transparent + if (evt->data.draw.data.bitmap.format != kRGBA_8888_ANPBitmapFormat) { + gLogI.log(instance, kError_ANPLogType, "bitmap did not change to transparent format"); + } + + //make it opaque + NPError err = browser->setvalue(instance, NPPVpluginTransparentBool, NULL); + if (err != NPERR_NO_ERROR) { + gLogI.log(instance, kError_ANPLogType, "Error setting transparency."); + } + + mFinishedStageTwo = true; + } + // check opaque + else if (!mFinishedStageThree) { + + //check to make sure it is not transparent + if (evt->data.draw.data.bitmap.format == kRGBA_8888_ANPBitmapFormat) { + gLogI.log(instance, kError_ANPLogType, "bitmap default format is transparent"); + } + + gLogI.log(instance, kDebug_ANPLogType, "END: testing bitmap transparency"); + + mFinishedStageThree = true; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// DOM TESTS +/////////////////////////////////////////////////////////////////////////////// + +void BackgroundPlugin::test_domAccess() { + NPP instance = this->inst(); + + gLogI.log(instance, kDebug_ANPLogType, " ------ %p Testing DOM Access", instance); + + // Get the plugin's DOM object + NPObject* windowObject = NULL; + browser->getvalue(instance, NPNVWindowNPObject, &windowObject); + + if (!windowObject) + gLogI.log(instance, kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", instance); + + // Retrieve a property from the plugin's DOM object + NPIdentifier topIdentifier = browser->getstringidentifier("top"); + NPVariant topObjectVariant; + browser->getproperty(instance, windowObject, topIdentifier, &topObjectVariant); + + if (topObjectVariant.type != NPVariantType_Object) + gLogI.log(instance, kError_ANPLogType, " ------ %p Invalid Variant type for DOM Property: %d,%d", instance, topObjectVariant.type, NPVariantType_Object); +} + + +/////////////////////////////////////////////////////////////////////////////// +// JAVASCRIPT TESTS +/////////////////////////////////////////////////////////////////////////////// + + +void BackgroundPlugin::test_javascript() { + NPP instance = this->inst(); + + gLogI.log(instance, kDebug_ANPLogType, " ------ %p Testing JavaScript Access", instance); + + // Get the plugin's DOM object + NPObject* windowObject = NULL; + browser->getvalue(instance, NPNVWindowNPObject, &windowObject); + + if (!windowObject) + gLogI.log(instance, kError_ANPLogType, " ------ %p Unable to retrieve DOM Window", instance); + + // create a string (JS code) that is stored in memory allocated by the browser + const char* jsString = "1200 + 34"; + void* stringMem = browser->memalloc(strlen(jsString)); + memcpy(stringMem, jsString, strlen(jsString)); + + // execute the javascript in the plugin's DOM object + NPString script = { (char*)stringMem, strlen(jsString) }; + NPVariant scriptVariant; + if (!browser->evaluate(instance, windowObject, &script, &scriptVariant)) + gLogI.log(instance, kError_ANPLogType, " ------ %p Unable to eval the JS.", instance); + + if (scriptVariant.type == NPVariantType_Int32) { + if (scriptVariant.value.intValue != 1234) + gLogI.log(instance, kError_ANPLogType, " ------ %p Invalid Value for JS Return: %d,1234", instance, scriptVariant.value.intValue); + } else { + gLogI.log(instance, kError_ANPLogType, " ------ %p Invalid Variant type for JS Return: %d,%d", instance, scriptVariant.type, NPVariantType_Int32); + } + + // free the memory allocated within the browser + browser->memfree(stringMem); +} diff --git a/samples/BrowserPlugin/jni/background/BackgroundPlugin.h b/samples/BrowserPlugin/jni/background/BackgroundPlugin.h new file mode 100644 index 000000000..3b9c7baff --- /dev/null +++ b/samples/BrowserPlugin/jni/background/BackgroundPlugin.h @@ -0,0 +1,69 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PluginObject.h" + +#ifndef backgroundPlugin__DEFINED +#define backgroundPlugin__DEFINED + +class BackgroundPlugin : public SurfaceSubPlugin { +public: + BackgroundPlugin(NPP inst); + virtual ~BackgroundPlugin(); + virtual bool supportsDrawingModel(ANPDrawingModel); + virtual int16 handleEvent(const ANPEvent* evt); + virtual void surfaceCreated(JNIEnv* env, jobject surface); + virtual void surfaceChanged(int format, int width, int height); + virtual void surfaceDestroyed(); + virtual bool isFixedSurface(); + + // Timer Testing Variables + uint32_t mStartTime; + uint32_t mPrevTime; + int mTimerRepeatCount; + int mTimerLatencyCount; + int mTimerLatencyCurrentCount; + + // Bitmap Transparency Variables + bool mFinishedStageOne; // check default & set transparent + bool mFinishedStageTwo; // check transparent & set opaque + bool mFinishedStageThree; // check opaque + +private: + void drawPlugin(int surfaceWidth, int surfaceHeight); + + jobject m_surface; + JavaVM* m_vm; + + void test_logging(); + void test_timers(); + void test_bitmaps(); + void test_bitmap_transparency(const ANPEvent* evt); + void test_domAccess(); + void test_javascript(); + +}; + +#endif // backgroundPlugin__DEFINED diff --git a/samples/BrowserPlugin/jni/form/FormPlugin.cpp b/samples/BrowserPlugin/jni/form/FormPlugin.cpp new file mode 100644 index 000000000..a92d447a2 --- /dev/null +++ b/samples/BrowserPlugin/jni/form/FormPlugin.cpp @@ -0,0 +1,381 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "FormPlugin.h" + +#include <stdio.h> +#include <sys/time.h> +#include <time.h> +#include <math.h> +#include <string.h> + +extern NPNetscapeFuncs* browser; +extern ANPLogInterfaceV0 gLogI; +extern ANPCanvasInterfaceV0 gCanvasI; +extern ANPPaintInterfaceV0 gPaintI; +extern ANPTypefaceInterfaceV0 gTypefaceI; +extern ANPWindowInterfaceV0 gWindowI; + + +static void inval(NPP instance) { + browser->invalidaterect(instance, NULL); +} + +static uint16 rnd16(float x, int inset) { + int ix = (int)roundf(x) + inset; + if (ix < 0) { + ix = 0; + } + return static_cast<uint16>(ix); +} + +static void inval(NPP instance, const ANPRectF& r, bool doAA) { + const int inset = doAA ? -1 : 0; + + PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); + NPRect inval; + inval.left = rnd16(r.left, inset); + inval.top = rnd16(r.top, inset); + inval.right = rnd16(r.right, -inset); + inval.bottom = rnd16(r.bottom, -inset); + browser->invalidaterect(instance, &inval); +} + +/////////////////////////////////////////////////////////////////////////////// + +FormPlugin::FormPlugin(NPP inst) : SubPlugin(inst) { + + m_hasFocus = false; + m_activeInput = NULL; + + memset(&m_usernameInput, 0, sizeof(m_usernameInput)); + memset(&m_passwordInput, 0, sizeof(m_passwordInput)); + + m_usernameInput.text[0] = '\0'; + m_usernameInput.charPtr = 0; + + m_passwordInput.text[0] = '\0'; + m_passwordInput.charPtr = 0; + + m_paintInput = gPaintI.newPaint(); + gPaintI.setFlags(m_paintInput, gPaintI.getFlags(m_paintInput) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintInput, 0xFFFFFFFF); + + m_paintActive = gPaintI.newPaint(); + gPaintI.setFlags(m_paintActive, gPaintI.getFlags(m_paintActive) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintActive, 0xFFFFFF00); + + m_paintText = gPaintI.newPaint(); + gPaintI.setFlags(m_paintText, gPaintI.getFlags(m_paintText) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintText, 0xFF000000); + gPaintI.setTextSize(m_paintText, 18); + + ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle); + gPaintI.setTypeface(m_paintText, tf); + gTypefaceI.unref(tf); + + //register for key and visibleRect events + ANPEventFlags flags = kKey_ANPEventFlag; + NPError err = browser->setvalue(inst, kAcceptEvents_ANPSetValue, &flags); + if (err != NPERR_NO_ERROR) { + gLogI.log(inst, kError_ANPLogType, "Error selecting input events."); + } +} + +FormPlugin::~FormPlugin() { + gPaintI.deletePaint(m_paintInput); + gPaintI.deletePaint(m_paintActive); + gPaintI.deletePaint(m_paintText); +} + +bool FormPlugin::supportsDrawingModel(ANPDrawingModel model) { + return (model == kBitmap_ANPDrawingModel); +} + +void FormPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) { + ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); + + ANPRectF clipR; + clipR.left = clip.left; + clipR.top = clip.top; + clipR.right = clip.right; + clipR.bottom = clip.bottom; + gCanvasI.clipRect(canvas, &clipR); + + draw(canvas); + gCanvasI.deleteCanvas(canvas); +} + +void FormPlugin::draw(ANPCanvas* canvas) { + NPP instance = this->inst(); + PluginObject *obj = (PluginObject*) instance->pdata; + + const float inputWidth = 60; + const float inputHeight = 30; + const int W = obj->window->width; + const int H = obj->window->height; + + // color the plugin canvas + gCanvasI.drawColor(canvas, (m_hasFocus) ? 0xFFCDCDCD : 0xFF545454); + + // draw the username box (5 px from the top edge) + m_usernameInput.rect.left = 5; + m_usernameInput.rect.top = 5; + m_usernameInput.rect.right = W - 5; + m_usernameInput.rect.bottom = m_usernameInput.rect.top + inputHeight; + gCanvasI.drawRect(canvas, &m_usernameInput.rect, getPaint(&m_usernameInput)); + drawText(canvas, m_usernameInput); + + // draw the password box (5 px from the bottom edge) + m_passwordInput.rect.left = 5; + m_passwordInput.rect.top = H - (inputHeight + 5); + m_passwordInput.rect.right = W - 5; + m_passwordInput.rect.bottom = m_passwordInput.rect.top + inputHeight; + gCanvasI.drawRect(canvas, &m_passwordInput.rect, getPaint(&m_passwordInput)); + drawPassword(canvas, m_passwordInput); + + //invalidate the canvas + //inval(instance); +} + +ANPPaint* FormPlugin::getPaint(TextInput* input) { + return (input == m_activeInput) ? m_paintActive : m_paintInput; +} + +void FormPlugin::drawText(ANPCanvas* canvas, TextInput textInput) { + + // get font metrics + ANPFontMetrics fontMetrics; + gPaintI.getFontMetrics(m_paintText, &fontMetrics); + + gCanvasI.drawText(canvas, textInput.text, textInput.charPtr, + textInput.rect.left + 5, + textInput.rect.bottom - fontMetrics.fBottom, m_paintText); +} + +void FormPlugin::drawPassword(ANPCanvas* canvas, TextInput passwordInput) { + + // get font metrics + ANPFontMetrics fontMetrics; + gPaintI.getFontMetrics(m_paintText, &fontMetrics); + + // comput the circle dimensions and initial location + float initialX = passwordInput.rect.left + 5; + float ovalBottom = passwordInput.rect.bottom - 2; + float ovalTop = ovalBottom - (fontMetrics.fBottom - fontMetrics.fTop); + float ovalWidth = ovalBottom - ovalTop; + float ovalSpacing = 3; + + // draw circles instead of the actual text + for (uint32_t x = 0; x < passwordInput.charPtr; x++) { + ANPRectF oval; + oval.left = initialX + ((ovalWidth + ovalSpacing) * (float) x); + oval.right = oval.left + ovalWidth; + oval.top = ovalTop; + oval.bottom = ovalBottom; + gCanvasI.drawOval(canvas, &oval, m_paintText); + } +} + +int16 FormPlugin::handleEvent(const ANPEvent* evt) { + NPP instance = this->inst(); + + switch (evt->eventType) { + case kDraw_ANPEventType: + switch (evt->data.draw.model) { + case kBitmap_ANPDrawingModel: + drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip); + return 1; + default: + break; // unknown drawing model + } + break; + + case kLifecycle_ANPEventType: + if (evt->data.lifecycle.action == kLoseFocus_ANPLifecycleAction) { + gLogI.log(instance, kDebug_ANPLogType, "----%p Loosing Focus", instance); + + if (m_activeInput) { + // hide the keyboard + gWindowI.showKeyboard(instance, false); + + //reset the activeInput + m_activeInput = NULL; + } + + m_hasFocus = false; + inval(instance); + return 1; + } + else if (evt->data.lifecycle.action == kGainFocus_ANPLifecycleAction) { + gLogI.log(instance, kDebug_ANPLogType, "----%p Gaining Focus", instance); + m_hasFocus = true; + inval(instance); + return 1; + } + break; + + case kMouse_ANPEventType: { + + int x = evt->data.mouse.x; + int y = evt->data.mouse.y; + if (kDown_ANPMouseAction == evt->data.mouse.action) { + + TextInput* currentInput = validTap(x,y); + + if (currentInput) + gWindowI.showKeyboard(instance, true); + else if (m_activeInput) + gWindowI.showKeyboard(instance, false); + + if (currentInput != m_activeInput) + switchActiveInput(currentInput); + + return 1; + } + break; + } + + case kKey_ANPEventType: + if (evt->data.key.action == kDown_ANPKeyAction) { + + //handle navigation keys + if (evt->data.key.nativeCode >= kDpadUp_ANPKeyCode + && evt->data.key.nativeCode <= kDpadCenter_ANPKeyCode) { + return handleNavigation(evt->data.key.nativeCode) ? 1 : 0; + } + + if (m_activeInput) { + handleTextInput(m_activeInput, evt->data.key.nativeCode, + evt->data.key.unichar); + inval(instance, m_activeInput->rect, true); + } + } + return 1; + + default: + break; + } + return 0; // unknown or unhandled event +} + +void FormPlugin::switchActiveInput(TextInput* newInput) { + NPP instance = this->inst(); + + if (m_activeInput) { + inval(instance, m_activeInput->rect, true); // inval the old + gWindowI.clearVisibleRects(instance); + } + + m_activeInput = newInput; // set the new active input + + if (m_activeInput) { + inval(instance, m_activeInput->rect, true); // inval the new + scrollIntoView(m_activeInput); + } +} + +bool FormPlugin::handleNavigation(ANPKeyCode keyCode) { + NPP instance = this->inst(); + + gLogI.log(instance, kDebug_ANPLogType, "----%p Recvd Nav Key %d", instance, keyCode); + + if (!m_activeInput) { + gWindowI.showKeyboard(instance, true); + switchActiveInput(&m_usernameInput); + } + else if (m_activeInput == &m_usernameInput) { + if (keyCode == kDpadDown_ANPKeyCode) { + switchActiveInput(&m_passwordInput); + } + else if (keyCode == kDpadCenter_ANPKeyCode) + gWindowI.showKeyboard(instance, false); + else if (keyCode == kDpadUp_ANPKeyCode) + return false; + } + else if (m_activeInput == &m_passwordInput) { + if (keyCode == kDpadUp_ANPKeyCode) { + switchActiveInput(&m_usernameInput); + } + else if (keyCode == kDpadCenter_ANPKeyCode) + gWindowI.showKeyboard(instance, false); + else if (keyCode == kDpadDown_ANPKeyCode) + return false; + } + + return true; +} + +void FormPlugin::handleTextInput(TextInput* input, ANPKeyCode keyCode, int32_t unichar) { + NPP instance = this->inst(); + + //make sure the input field is in view + scrollIntoView(input); + + //handle the delete operation + if (keyCode == kDel_ANPKeyCode) { + if (input->charPtr > 0) { + input->charPtr--; + } + return; + } + + //check to see that the input is not full + if (input->charPtr >= (sizeof(input->text) - 1)) + return; + + //add the character + input->text[input->charPtr] = static_cast<char>(unichar); + input->charPtr++; + + gLogI.log(instance, kDebug_ANPLogType, "----%p Text: %c", instance, unichar); +} + +void FormPlugin::scrollIntoView(TextInput* input) { + NPP instance = this->inst(); + PluginObject *obj = (PluginObject*) instance->pdata; + NPWindow *window = obj->window; + + // find the textInput's global rect coordinates + ANPRectI visibleRects[1]; + visibleRects[0].left = input->rect.left; + visibleRects[0].top = input->rect.top; + visibleRects[0].right = input->rect.right; + visibleRects[0].bottom = input->rect.bottom; + + gWindowI.setVisibleRects(instance, visibleRects, 1); +} + +TextInput* FormPlugin::validTap(int x, int y) { + + if (x > m_usernameInput.rect.left && x < m_usernameInput.rect.right && + y > m_usernameInput.rect.top && y < m_usernameInput.rect.bottom) + return &m_usernameInput; + else if (x >m_passwordInput.rect.left && x < m_passwordInput.rect.right && + y > m_passwordInput.rect.top && y < m_passwordInput.rect.bottom) + return &m_passwordInput; + else + return NULL; +} diff --git a/samples/BrowserPlugin/jni/form/FormPlugin.h b/samples/BrowserPlugin/jni/form/FormPlugin.h new file mode 100644 index 000000000..041ffb870 --- /dev/null +++ b/samples/BrowserPlugin/jni/form/FormPlugin.h @@ -0,0 +1,72 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PluginObject.h" + +#ifndef formPlugin__DEFINED +#define formPlugin__DEFINED + +struct TextInput { + ANPRectF rect; + char text[30]; + uint32_t charPtr; +}; + +class FormPlugin : public SubPlugin { +public: + FormPlugin(NPP inst); + virtual ~FormPlugin(); + virtual bool supportsDrawingModel(ANPDrawingModel); + virtual int16 handleEvent(const ANPEvent* evt); +private: + void draw(ANPCanvas*); + void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip); + + bool m_hasFocus; + + TextInput* m_activeInput; + TextInput m_usernameInput; + TextInput m_passwordInput; + + ANPPaint* m_paintInput; + ANPPaint* m_paintActive; + ANPPaint* m_paintText; + + ANPRectI m_visibleRect; + + void drawText(ANPCanvas*, TextInput); + void drawPassword(ANPCanvas*, TextInput); + + bool handleNavigation(ANPKeyCode keyCode); + void handleTextInput(TextInput* input, ANPKeyCode keyCode, int32_t unichar); + void scrollIntoView(TextInput* input); + void switchActiveInput(TextInput* input); + + ANPPaint* getPaint(TextInput*); + TextInput* validTap(int x, int y); + +}; + +#endif // formPlugin__DEFINED diff --git a/samples/BrowserPlugin/jni/hello-jni.cpp b/samples/BrowserPlugin/jni/hello-jni.cpp new file mode 100644 index 000000000..0789b7e18 --- /dev/null +++ b/samples/BrowserPlugin/jni/hello-jni.cpp @@ -0,0 +1,48 @@ +/* + * 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. + * + */ +#include <string.h> +#include <jni.h> +#include <JNIHelp.h> +#include <utils/Log.h> + +#define EXPORT __attribute__((visibility("default"))) + +static jstring stringFromJNI( JNIEnv* env, jobject thiz ) +{ + return env->NewStringUTF("Hello from JNI !"); +} + +/* + * JNI registration. + */ +static JNINativeMethod gJavaSamplePluginStubMethods[] = { + { "nativeStringFromJNI", "()Ljava/lang/String;", (void*) stringFromJNI }, +}; + +EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + + JNIEnv* env = NULL; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + return -1; + } + + jniRegisterNativeMethods(env, "com/android/sampleplugin/SamplePluginStub", + gJavaSamplePluginStubMethods, NELEM(gJavaSamplePluginStubMethods)); + + return JNI_VERSION_1_4; +} diff --git a/samples/BrowserPlugin/jni/jni-bridge.cpp b/samples/BrowserPlugin/jni/jni-bridge.cpp new file mode 100644 index 000000000..45ecd544c --- /dev/null +++ b/samples/BrowserPlugin/jni/jni-bridge.cpp @@ -0,0 +1,85 @@ +/* + * 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. + * + */ +#include <string.h> +#include <jni.h> +#include <JNIHelp.h> +#include <utils/Log.h> + +#include "PluginObject.h" + +#define EXPORT __attribute__((visibility("default"))) + +static SurfaceSubPlugin* getPluginObject(int npp) { + NPP instance = (NPP)npp; + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + if (obj && obj->activePlugin + && obj->activePlugin->supportsDrawingModel(kSurface_ANPDrawingModel)) { + return static_cast<SurfaceSubPlugin*>(obj->activePlugin); + } + return NULL; +} + +static void surfaceCreated(JNIEnv* env, jobject thiz, jint npp, jobject surface) { + SurfaceSubPlugin* obj = getPluginObject(npp); + + //TODO why is this VM different from the one in NP_INIT... + JavaVM* vm = NULL; + env->GetJavaVM(&vm); + + obj->surfaceCreated(env, surface); +} + +static void surfaceChanged(JNIEnv* env, jobject thiz, jint npp, jint format, jint width, jint height) { + SurfaceSubPlugin* obj = getPluginObject(npp); + obj->surfaceChanged(format, width, height); +} + +static void surfaceDestroyed(JNIEnv* env, jobject thiz, jint npp) { + SurfaceSubPlugin* obj = getPluginObject(npp); + if (obj) { + obj->surfaceDestroyed(); + } +} + +static jboolean isFixedSurface(JNIEnv* env, jobject thiz, jint npp) { + SurfaceSubPlugin* obj = getPluginObject(npp); + return obj->isFixedSurface(); +} + +/* + * JNI registration. + */ +static JNINativeMethod gJavaSamplePluginStubMethods[] = { + { "nativeSurfaceCreated", "(ILandroid/view/View;)V", (void*) surfaceCreated }, + { "nativeSurfaceChanged", "(IIII)V", (void*) surfaceChanged }, + { "nativeSurfaceDestroyed", "(I)V", (void*) surfaceDestroyed }, + { "nativeIsFixedSurface", "(I)Z", (void*) isFixedSurface }, +}; + +EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + + JNIEnv* env = NULL; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + return -1; + } + + jniRegisterNativeMethods(env, "com/android/sampleplugin/SamplePluginStub", + gJavaSamplePluginStubMethods, NELEM(gJavaSamplePluginStubMethods)); + + return JNI_VERSION_1_4; +} diff --git a/samples/BrowserPlugin/jni/main.cpp b/samples/BrowserPlugin/jni/main.cpp new file mode 100644 index 000000000..d00091faf --- /dev/null +++ b/samples/BrowserPlugin/jni/main.cpp @@ -0,0 +1,412 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include "main.h" +#include "PluginObject.h" +#include "AnimationPlugin.h" +#include "AudioPlugin.h" +#include "BackgroundPlugin.h" +#include "FormPlugin.h" +#include "PaintPlugin.h" + +NPNetscapeFuncs* browser; +#define EXPORT __attribute__((visibility("default"))) + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, + char* argn[], char* argv[], NPSavedData* saved); +NPError NPP_Destroy(NPP instance, NPSavedData** save); +NPError NPP_SetWindow(NPP instance, NPWindow* window); +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, + NPBool seekable, uint16* stype); +NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason); +int32 NPP_WriteReady(NPP instance, NPStream* stream); +int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, + void* buffer); +void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname); +void NPP_Print(NPP instance, NPPrint* platformPrint); +int16 NPP_HandleEvent(NPP instance, void* event); +void NPP_URLNotify(NPP instance, const char* URL, NPReason reason, + void* notifyData); +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value); +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value); + +extern "C" { +EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context); +EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value); +EXPORT const char* NP_GetMIMEDescription(void); +EXPORT void NP_Shutdown(void); +}; + +ANPAudioTrackInterfaceV0 gSoundI; +ANPBitmapInterfaceV0 gBitmapI; +ANPCanvasInterfaceV0 gCanvasI; +ANPLogInterfaceV0 gLogI; +ANPPaintInterfaceV0 gPaintI; +ANPPathInterfaceV0 gPathI; +ANPSurfaceInterfaceV0 gSurfaceI; +ANPSystemInterfaceV0 gSystemI; +ANPTypefaceInterfaceV0 gTypefaceI; +ANPWindowInterfaceV0 gWindowI; + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) +#define DEBUG_PLUGIN_EVENTS 0 + +NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env, void *application_context) +{ + // Make sure we have a function table equal or larger than we are built against. + if (browserFuncs->size < sizeof(NPNetscapeFuncs)) { + return NPERR_GENERIC_ERROR; + } + + // Copy the function table (structure) + browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs)); + memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs)); + + // Build the plugin function table + pluginFuncs->version = 11; + pluginFuncs->size = sizeof(pluginFuncs); + pluginFuncs->newp = NPP_New; + pluginFuncs->destroy = NPP_Destroy; + pluginFuncs->setwindow = NPP_SetWindow; + pluginFuncs->newstream = NPP_NewStream; + pluginFuncs->destroystream = NPP_DestroyStream; + pluginFuncs->asfile = NPP_StreamAsFile; + pluginFuncs->writeready = NPP_WriteReady; + pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; + pluginFuncs->print = NPP_Print; + pluginFuncs->event = NPP_HandleEvent; + pluginFuncs->urlnotify = NPP_URLNotify; + pluginFuncs->getvalue = NPP_GetValue; + pluginFuncs->setvalue = NPP_SetValue; + + static const struct { + NPNVariable v; + uint32_t size; + ANPInterface* i; + } gPairs[] = { + { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI }, + { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI }, + { kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI }, + { kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI }, + { kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI }, + { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI }, + { kSurfaceInterfaceV0_ANPGetValue, sizeof(gSurfaceI), &gSurfaceI }, + { kSystemInterfaceV0_ANPGetValue, sizeof(gSystemI), &gSystemI }, + { kTypefaceInterfaceV0_ANPGetValue, sizeof(gTypefaceI), &gTypefaceI }, + { kWindowInterfaceV0_ANPGetValue, sizeof(gWindowI), &gWindowI }, + }; + for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) { + gPairs[i].i->inSize = gPairs[i].size; + NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i); + if (err) { + return err; + } + } + + return NPERR_NO_ERROR; +} + +void NP_Shutdown(void) +{ + +} + +const char *NP_GetMIMEDescription(void) +{ + return "application/x-testbrowserplugin:tst:Test plugin mimetype is application/x-testbrowserplugin"; +} + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, + char* argn[], char* argv[], NPSavedData* saved) +{ + + /* BEGIN: STANDARD PLUGIN FRAMEWORK */ + PluginObject *obj = NULL; + + // Scripting functions appeared in NPAPI version 14 + if (browser->version >= 14) { + instance->pdata = browser->createobject (instance, getPluginClass()); + obj = static_cast<PluginObject*>(instance->pdata); + bzero(obj, sizeof(*obj)); + } + /* END: STANDARD PLUGIN FRAMEWORK */ + + // select the drawing model based on user input + ANPDrawingModel model = kBitmap_ANPDrawingModel; + + for (int i = 0; i < argc; i++) { + if (!strcmp(argn[i], "DrawingModel")) { + if (!strcmp(argv[i], "Bitmap")) { + model = kBitmap_ANPDrawingModel; + } + else if (!strcmp(argv[i], "Surface")) { + model = kSurface_ANPDrawingModel; + } + gLogI.log(instance, kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model); + break; + } + } + + // notify the plugin API of the location of the java interface + char* className = "com.android.sampleplugin.SamplePluginStub"; + NPError npErr = browser->setvalue(instance, kSetPluginStubJavaClassName_ANPSetValue, + reinterpret_cast<void*>(className)); + if (npErr) { + gLogI.log(instance, kError_ANPLogType, "set class err %d", npErr); + return npErr; + } + + // notify the plugin API of the drawing model we wish to use. This must be + // done prior to creating certain subPlugin objects (e.g. surfaceViews) + NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue, + reinterpret_cast<void*>(model)); + if (err) { + gLogI.log(instance, kError_ANPLogType, "request model %d err %d", model, err); + return err; + } + + const char* path = gSystemI.getApplicationDataDirectory(); + if (path) { + gLogI.log(instance, kDebug_ANPLogType, "Application data dir is %s", path); + } else { + gLogI.log(instance, kError_ANPLogType, "Can't find Application data dir"); + } + + // select the pluginType + for (int i = 0; i < argc; i++) { + if (!strcmp(argn[i], "PluginType")) { + if (!strcmp(argv[i], "Animation")) { + obj->pluginType = kAnimation_PluginType; + obj->activePlugin = new BallAnimation(instance); + } + else if (!strcmp(argv[i], "Audio")) { + obj->pluginType = kAudio_PluginType; + obj->activePlugin = new AudioPlugin(instance); + } + else if (!strcmp(argv[i], "Background")) { + obj->pluginType = kBackground_PluginType; + obj->activePlugin = new BackgroundPlugin(instance); + } + else if (!strcmp(argv[i], "Form")) { + obj->pluginType = kForm_PluginType; + obj->activePlugin = new FormPlugin(instance); + } + else if (!strcmp(argv[i], "Paint")) { + obj->pluginType = kPaint_PluginType; + obj->activePlugin = new PaintPlugin(instance); + } + gLogI.log(instance, kDebug_ANPLogType, "------ %p PluginType is %d", instance, obj->pluginType); + break; + } + } + + // if no pluginType is specified then default to Animation + if (!obj->pluginType) { + gLogI.log(instance, kError_ANPLogType, "------ %p No PluginType attribute was found", instance); + obj->pluginType = kAnimation_PluginType; + obj->activePlugin = new BallAnimation(instance); + } + + // check to ensure the pluginType supports the model + if (!obj->activePlugin->supportsDrawingModel(model)) { + gLogI.log(instance, kError_ANPLogType, "------ %p Unsupported DrawingModel (%d)", instance, model); + return NPERR_GENERIC_ERROR; + } + + return NPERR_NO_ERROR; +} + +NPError NPP_Destroy(NPP instance, NPSavedData** save) +{ + PluginObject *obj = (PluginObject*) instance->pdata; + delete obj->activePlugin; + + return NPERR_NO_ERROR; +} + +NPError NPP_SetWindow(NPP instance, NPWindow* window) +{ + PluginObject *obj = (PluginObject*) instance->pdata; + + // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject. + if (obj != NULL) { + obj->window = window; + } + + browser->invalidaterect(instance, NULL); + + return NPERR_NO_ERROR; +} + +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) +{ + *stype = NP_ASFILEONLY; + return NPERR_NO_ERROR; +} + +NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) +{ + return NPERR_NO_ERROR; +} + +int32 NPP_WriteReady(NPP instance, NPStream* stream) +{ + return 0; +} + +int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer) +{ + return 0; +} + +void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) +{ +} + +void NPP_Print(NPP instance, NPPrint* platformPrint) +{ +} + +int16 NPP_HandleEvent(NPP instance, void* event) +{ + PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata); + const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event); + +#if DEBUG_PLUGIN_EVENTS + switch (evt->eventType) { + case kDraw_ANPEventType: + + if (evt->data.draw.model == kBitmap_ANPDrawingModel) { + + static ANPBitmapFormat currentFormat = -1; + if (evt->data.draw.data.bitmap.format != currentFormat) { + currentFormat = evt->data.draw.data.bitmap.format; + gLogI.log(instance, kDebug_ANPLogType, "---- %p Draw (bitmap)" + " clip=%d,%d,%d,%d format=%d", instance, + evt->data.draw.clip.left, + evt->data.draw.clip.top, + evt->data.draw.clip.right, + evt->data.draw.clip.bottom, + evt->data.draw.data.bitmap.format); + } + } + break; + + case kKey_ANPEventType: + gLogI.log(instance, kDebug_ANPLogType, "---- %p Key action=%d" + " code=%d vcode=%d unichar=%d repeat=%d mods=%x", instance, + evt->data.key.action, + evt->data.key.nativeCode, + evt->data.key.virtualCode, + evt->data.key.unichar, + evt->data.key.repeatCount, + evt->data.key.modifiers); + break; + + case kLifecycle_ANPEventType: + gLogI.log(instance, kDebug_ANPLogType, "---- %p Lifecycle action=%d", + instance, evt->data.lifecycle.action); + break; + + case kTouch_ANPEventType: + gLogI.log(instance, kDebug_ANPLogType, "---- %p Touch action=%d [%d %d]", + instance, evt->data.touch.action, evt->data.touch.x, + evt->data.touch.y); + break; + + case kMouse_ANPEventType: + gLogI.log(instance, kDebug_ANPLogType, "---- %p Mouse action=%d [%d %d]", + instance, evt->data.mouse.action, evt->data.mouse.x, + evt->data.mouse.y); + break; + + case kVisibleRect_ANPEventType: + gLogI.log(instance, kDebug_ANPLogType, "---- %p VisibleRect [%d %d %d %d]", + instance, evt->data.visibleRect.rect.left, evt->data.visibleRect.rect.top, + evt->data.visibleRect.rect.right, evt->data.visibleRect.rect.bottom); + break; + + default: + gLogI.log(instance, kError_ANPLogType, "---- %p Unknown Event [%d]", + instance, evt->eventType); + break; + } +#endif + + if(!obj->activePlugin) { + gLogI.log(instance, kError_ANPLogType, "the active plugin is null."); + return 0; // unknown or unhandled event + } + else { + return obj->activePlugin->handleEvent(evt); + } +} + +void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) +{ + +} + +EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) { + + if (variable == NPPVpluginNameString) { + const char **str = (const char **)value; + *str = "Test Plugin"; + return NPERR_NO_ERROR; + } + + if (variable == NPPVpluginDescriptionString) { + const char **str = (const char **)value; + *str = "Description of Test Plugin"; + return NPERR_NO_ERROR; + } + + return NPERR_GENERIC_ERROR; +} + +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) +{ + if (variable == NPPVpluginScriptableNPObject) { + void **v = (void **)value; + PluginObject *obj = (PluginObject*) instance->pdata; + + if (obj) + browser->retainobject((NPObject*)obj); + + *v = obj; + return NPERR_NO_ERROR; + } + + return NPERR_GENERIC_ERROR; +} + +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) +{ + return NPERR_GENERIC_ERROR; +} + diff --git a/samples/BrowserPlugin/jni/main.h b/samples/BrowserPlugin/jni/main.h new file mode 100644 index 000000000..8ad2cce9b --- /dev/null +++ b/samples/BrowserPlugin/jni/main.h @@ -0,0 +1,32 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <npapi.h> +#include <npfunctions.h> +#include <npruntime.h> +#include "android_npapi.h" +#include "ANPSurface_npapi.h" + +extern NPNetscapeFuncs* browser; diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp new file mode 100644 index 000000000..5b00dbaed --- /dev/null +++ b/samples/BrowserPlugin/jni/paint/PaintPlugin.cpp @@ -0,0 +1,388 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PaintPlugin.h" + +#include <fcntl.h> +#include <math.h> +#include <string.h> + +extern NPNetscapeFuncs* browser; +extern ANPLogInterfaceV0 gLogI; +extern ANPCanvasInterfaceV0 gCanvasI; +extern ANPPaintInterfaceV0 gPaintI; +extern ANPPathInterfaceV0 gPathI; +extern ANPSurfaceInterfaceV0 gSurfaceI; +extern ANPTypefaceInterfaceV0 gTypefaceI; + +/////////////////////////////////////////////////////////////////////////////// + +PaintPlugin::PaintPlugin(NPP inst) : SurfaceSubPlugin(inst) { + + m_isTouchActive = false; + m_isTouchCurrentInput = true; + m_activePaintColor = s_redColor; + + memset(&m_drawingSurface, 0, sizeof(m_drawingSurface)); + memset(&m_inputToggle, 0, sizeof(m_inputToggle)); + memset(&m_colorToggle, 0, sizeof(m_colorToggle)); + memset(&m_clearSurface, 0, sizeof(m_clearSurface)); + + // initialize the drawing surface + m_surface = NULL; + m_vm = NULL; + + // initialize the path + m_touchPath = gPathI.newPath(); + if(!m_touchPath) + gLogI.log(inst, kError_ANPLogType, "----%p Unable to create the touch path", inst); + + // initialize the paint colors + m_paintSurface = gPaintI.newPaint(); + gPaintI.setFlags(m_paintSurface, gPaintI.getFlags(m_paintSurface) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintSurface, 0xFFC0C0C0); + gPaintI.setTextSize(m_paintSurface, 18); + + m_paintButton = gPaintI.newPaint(); + gPaintI.setFlags(m_paintButton, gPaintI.getFlags(m_paintButton) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(m_paintButton, 0xFFA8A8A8); + + // initialize the typeface (set the colors) + ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle); + gPaintI.setTypeface(m_paintSurface, tf); + gTypefaceI.unref(tf); + + //register for touch events + ANPEventFlags flags = kTouch_ANPEventFlag; + NPError err = browser->setvalue(inst, kAcceptEvents_ANPSetValue, &flags); + if (err != NPERR_NO_ERROR) { + gLogI.log(inst, kError_ANPLogType, "Error selecting input events."); + } +} + +PaintPlugin::~PaintPlugin() { + gPathI.deletePath(m_touchPath); + gPaintI.deletePaint(m_paintSurface); + gPaintI.deletePaint(m_paintButton); + surfaceDestroyed(); +} + +bool PaintPlugin::supportsDrawingModel(ANPDrawingModel model) { + return (model == kSurface_ANPDrawingModel); +} + +ANPCanvas* PaintPlugin::getCanvas(ANPRectI* dirtyRect) { + + ANPBitmap bitmap; + JNIEnv* env = NULL; + if (!m_surface || m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK || + !gSurfaceI.lock(env, m_surface, &bitmap, dirtyRect)) { + return NULL; + } + + ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap); + + // clip the canvas to the dirty rect b/c the surface is only required to + // copy a minimum of the dirty rect and may copy more. The clipped canvas + // however will never write to pixels outside of the clipped area. + if (dirtyRect) { + ANPRectF clipR; + clipR.left = dirtyRect->left; + clipR.top = dirtyRect->top; + clipR.right = dirtyRect->right; + clipR.bottom = dirtyRect->bottom; + gCanvasI.clipRect(canvas, &clipR); + } + + return canvas; +} + +ANPCanvas* PaintPlugin::getCanvas(ANPRectF* dirtyRect) { + + ANPRectI newRect; + newRect.left = (int) dirtyRect->left; + newRect.top = (int) dirtyRect->top; + newRect.right = (int) dirtyRect->right; + newRect.bottom = (int) dirtyRect->bottom; + + return getCanvas(&newRect); +} + +void PaintPlugin::releaseCanvas(ANPCanvas* canvas) { + JNIEnv* env = NULL; + if (m_surface && m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) { + gSurfaceI.unlock(env, m_surface); + } + gCanvasI.deleteCanvas(canvas); +} + +void PaintPlugin::drawCleanPlugin(ANPCanvas* canvas) { + NPP instance = this->inst(); + PluginObject *obj = (PluginObject*) instance->pdata; + + // if no canvas get a locked canvas + if (!canvas) + canvas = getCanvas(); + + if (!canvas) + return; + + const float buttonWidth = 60; + const float buttonHeight = 30; + const int W = obj->window->width; + const int H = obj->window->height; + + // color the plugin canvas + gCanvasI.drawColor(canvas, 0xFFCDCDCD); + + // get font metrics + ANPFontMetrics fontMetrics; + gPaintI.getFontMetrics(m_paintSurface, &fontMetrics); + + // draw the input toggle button + m_inputToggle.left = 5; + m_inputToggle.top = H - buttonHeight - 5; + m_inputToggle.right = m_inputToggle.left + buttonWidth; + m_inputToggle.bottom = m_inputToggle.top + buttonHeight; + gCanvasI.drawRect(canvas, &m_inputToggle, m_paintButton); + const char* inputText = m_isTouchCurrentInput ? "Touch" : "Mouse"; + gCanvasI.drawText(canvas, inputText, strlen(inputText), m_inputToggle.left + 5, + m_inputToggle.top - fontMetrics.fTop, m_paintSurface); + + // draw the color selector button + m_colorToggle.left = (W/2) - (buttonWidth/2); + m_colorToggle.top = H - buttonHeight - 5; + m_colorToggle.right = m_colorToggle.left + buttonWidth; + m_colorToggle.bottom = m_colorToggle.top + buttonHeight; + gCanvasI.drawRect(canvas, &m_colorToggle, m_paintButton); + const char* colorText = getColorText(); + gCanvasI.drawText(canvas, colorText, strlen(colorText), m_colorToggle.left + 5, + m_colorToggle.top - fontMetrics.fTop, m_paintSurface); + + // draw the clear canvas button + m_clearSurface.left = W - buttonWidth - 5; + m_clearSurface.top = H - buttonHeight - 5; + m_clearSurface.right = m_clearSurface.left + buttonWidth; + m_clearSurface.bottom = m_clearSurface.top + buttonHeight; + gCanvasI.drawRect(canvas, &m_clearSurface, m_paintButton); + const char* clearText = "Clear"; + gCanvasI.drawText(canvas, clearText, strlen(clearText), m_clearSurface.left + 5, + m_clearSurface.top - fontMetrics.fTop, m_paintSurface); + + // draw the drawing surface box (5 px from the edge) + m_drawingSurface.left = 5; + m_drawingSurface.top = 5; + m_drawingSurface.right = W - 5; + m_drawingSurface.bottom = m_colorToggle.top - 5; + gCanvasI.drawRect(canvas, &m_drawingSurface, m_paintSurface); + + // release the canvas + releaseCanvas(canvas); +} + +const char* PaintPlugin::getColorText() { + + if (m_activePaintColor == s_blueColor) + return "Blue"; + else if (m_activePaintColor == s_greenColor) + return "Green"; + else + return "Red"; +} + +bool PaintPlugin::isFixedSurface() { + return true; +} + +void PaintPlugin::surfaceCreated(JNIEnv* env, jobject surface) { + env->GetJavaVM(&m_vm); + m_surface = env->NewGlobalRef(surface); + drawCleanPlugin(); +} + +void PaintPlugin::surfaceChanged(int format, int width, int height) { + // get the plugin's dimensions according to the DOM + PluginObject *obj = (PluginObject*) inst()->pdata; + const int pW = obj->window->width; + const int pH = obj->window->height; + // compare to the plugin's surface dimensions + if (pW != width || pH != height) + gLogI.log(inst(), kError_ANPLogType, + "----%p Invalid Surface Dimensions (%d,%d):(%d,%d)", + inst(), pW, pH, width, height); +} +void PaintPlugin::surfaceDestroyed() { + JNIEnv* env = NULL; + if (m_surface && m_vm->GetEnv((void**) &env, JNI_VERSION_1_4) == JNI_OK) { + env->DeleteGlobalRef(m_surface); + m_surface = NULL; + } +} + +int16 PaintPlugin::handleEvent(const ANPEvent* evt) { + switch (evt->eventType) { + case kTouch_ANPEventType: { + float x = (float) evt->data.touch.x; + float y = (float) evt->data.touch.y; + if (kDown_ANPTouchAction == evt->data.touch.action && m_isTouchCurrentInput) { + + ANPRectF* rect = validTouch(evt->data.touch.x, evt->data.touch.y); + if(rect == &m_drawingSurface) { + m_isTouchActive = true; + gPathI.moveTo(m_touchPath, x, y); + paintTouch(); + return 1; + } + + } else if (kMove_ANPTouchAction == evt->data.touch.action && m_isTouchActive) { + gPathI.lineTo(m_touchPath, x, y); + paintTouch(); + return 1; + } else if (kUp_ANPTouchAction == evt->data.touch.action && m_isTouchActive) { + gPathI.lineTo(m_touchPath, x, y); + paintTouch(); + m_isTouchActive = false; + gPathI.reset(m_touchPath); + return 1; + } else if (kCancel_ANPTouchAction == evt->data.touch.action) { + m_isTouchActive = false; + gPathI.reset(m_touchPath); + return 1; + } + + break; + } + case kMouse_ANPEventType: { + + if (m_isTouchActive) + gLogI.log(inst(), kError_ANPLogType, "----%p Received unintended mouse event", inst()); + + if (kDown_ANPMouseAction == evt->data.mouse.action) { + ANPRectF* rect = validTouch(evt->data.mouse.x, evt->data.mouse.y); + if (rect == &m_drawingSurface) + paintMouse(evt->data.mouse.x, evt->data.mouse.y); + else if (rect == &m_inputToggle) + toggleInputMethod(); + else if (rect == &m_colorToggle) + togglePaintColor(); + else if (rect == &m_clearSurface) + drawCleanPlugin(); + } + return 1; + } + default: + break; + } + return 0; // unknown or unhandled event +} + +ANPRectF* PaintPlugin::validTouch(int x, int y) { + + //convert to float + float fx = (int) x; + float fy = (int) y; + + if (fx > m_drawingSurface.left && fx < m_drawingSurface.right && fy > m_drawingSurface.top && fy < m_drawingSurface.bottom) + return &m_drawingSurface; + else if (fx > m_inputToggle.left && fx < m_inputToggle.right && fy > m_inputToggle.top && fy < m_inputToggle.bottom) + return &m_inputToggle; + else if (fx > m_colorToggle.left && fx < m_colorToggle.right && fy > m_colorToggle.top && fy < m_colorToggle.bottom) + return &m_colorToggle; + else if (fx > m_clearSurface.left && fx < m_clearSurface.right && fy > m_clearSurface.top && fy < m_clearSurface.bottom) + return &m_clearSurface; + else + return NULL; +} + +void PaintPlugin::toggleInputMethod() { + m_isTouchCurrentInput = !m_isTouchCurrentInput; + + // lock only the input toggle and redraw the canvas + ANPCanvas* lockedCanvas = getCanvas(&m_inputToggle); + drawCleanPlugin(lockedCanvas); +} + +void PaintPlugin::togglePaintColor() { + if (m_activePaintColor == s_blueColor) + m_activePaintColor = s_redColor; + else if (m_activePaintColor == s_greenColor) + m_activePaintColor = s_blueColor; + else + m_activePaintColor = s_greenColor; + + // lock only the color toggle and redraw the canvas + ANPCanvas* lockedCanvas = getCanvas(&m_colorToggle); + drawCleanPlugin(lockedCanvas); +} + +void PaintPlugin::paintMouse(int x, int y) { + //TODO do not paint outside the drawing surface + + //create the paint color + ANPPaint* fillPaint = gPaintI.newPaint(); + gPaintI.setFlags(fillPaint, gPaintI.getFlags(fillPaint) | kAntiAlias_ANPPaintFlag); + gPaintI.setStyle(fillPaint, kFill_ANPPaintStyle); + gPaintI.setColor(fillPaint, m_activePaintColor); + + // handle the simple "mouse" paint (draw a point) + ANPRectF point; + point.left = (float) x-3; + point.top = (float) y-3; + point.right = (float) x+3; + point.bottom = (float) y+3; + + // get a canvas that is only locked around the point and draw it + ANPCanvas* canvas = getCanvas(&point); + gCanvasI.drawOval(canvas, &point, fillPaint); + + // clean up + releaseCanvas(canvas); + gPaintI.deletePaint(fillPaint); +} + +void PaintPlugin::paintTouch() { + //TODO do not paint outside the drawing surface + + //create the paint color + ANPPaint* strokePaint = gPaintI.newPaint(); + gPaintI.setFlags(strokePaint, gPaintI.getFlags(strokePaint) | kAntiAlias_ANPPaintFlag); + gPaintI.setColor(strokePaint, m_activePaintColor); + gPaintI.setStyle(strokePaint, kStroke_ANPPaintStyle); + gPaintI.setStrokeWidth(strokePaint, 6.0); + gPaintI.setStrokeCap(strokePaint, kRound_ANPPaintCap); + gPaintI.setStrokeJoin(strokePaint, kRound_ANPPaintJoin); + + // handle the complex "touch" paint (draw a line) + ANPRectF bounds; + gPathI.getBounds(m_touchPath, &bounds); + + // get a canvas that is only locked around the point and draw the path + ANPCanvas* canvas = getCanvas(&bounds); + gCanvasI.drawPath(canvas, m_touchPath, strokePaint); + + // clean up + releaseCanvas(canvas); + gPaintI.deletePaint(strokePaint); +} diff --git a/samples/BrowserPlugin/jni/paint/PaintPlugin.h b/samples/BrowserPlugin/jni/paint/PaintPlugin.h new file mode 100644 index 000000000..8ff561c49 --- /dev/null +++ b/samples/BrowserPlugin/jni/paint/PaintPlugin.h @@ -0,0 +1,76 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "PluginObject.h" +#include <stdio.h> + +#ifndef paintPlugin__DEFINED +#define paintPlugin__DEFINED + +class PaintPlugin : public SurfaceSubPlugin { +public: + PaintPlugin(NPP inst); + virtual ~PaintPlugin(); + virtual bool supportsDrawingModel(ANPDrawingModel); + virtual int16 handleEvent(const ANPEvent* evt); + virtual void surfaceCreated(JNIEnv* env, jobject surface); + virtual void surfaceChanged(int format, int width, int height); + virtual void surfaceDestroyed(); + virtual bool isFixedSurface(); + +private: + void drawCleanPlugin(ANPCanvas* canvas = NULL); + ANPCanvas* getCanvas(ANPRectI* dirtyRect = NULL); + ANPCanvas* getCanvas(ANPRectF* dirtyRect); + const char* getColorText(); + void paintMouse(int x, int y); + void paintTouch(); + void releaseCanvas(ANPCanvas*); + void toggleInputMethod(); + void togglePaintColor(); + ANPRectF* validTouch(int x, int y); + + bool m_isTouchActive; + bool m_isTouchCurrentInput; + + JavaVM* m_vm; + jobject m_surface; + ANPPath* m_touchPath; + + ANPRectF m_drawingSurface; + ANPRectF m_inputToggle; + ANPRectF m_colorToggle; + ANPRectF m_clearSurface; + + ANPPaint* m_paintSurface; + ANPPaint* m_paintButton; + + ANPColor m_activePaintColor; + static const ANPColor s_redColor = 0xFFFF0000; + static const ANPColor s_greenColor = 0xFF00FF00; + static const ANPColor s_blueColor = 0xFF0000FF; +}; + +#endif // paintPlugin__DEFINED diff --git a/samples/BrowserPlugin/res/drawable-hdpi/sample_browser_plugin.png b/samples/BrowserPlugin/res/drawable-hdpi/sample_browser_plugin.png Binary files differnew file mode 100755 index 000000000..4d9d559d4 --- /dev/null +++ b/samples/BrowserPlugin/res/drawable-hdpi/sample_browser_plugin.png diff --git a/samples/BrowserPlugin/res/drawable-mdpi/sample_browser_plugin.png b/samples/BrowserPlugin/res/drawable-mdpi/sample_browser_plugin.png Binary files differnew file mode 100755 index 000000000..47c79d1c1 --- /dev/null +++ b/samples/BrowserPlugin/res/drawable-mdpi/sample_browser_plugin.png diff --git a/samples/BrowserPlugin/res/values/strings.xml b/samples/BrowserPlugin/res/values/strings.xml new file mode 100644 index 000000000..1f8dd4946 --- /dev/null +++ b/samples/BrowserPlugin/res/values/strings.xml @@ -0,0 +1,19 @@ +<?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. +--> +<resources> + <string name="sample_browser_plugin">Sample Browser Plugin</string> +</resources> diff --git a/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePlugin.java b/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePlugin.java new file mode 100644 index 000000000..9b8ce955e --- /dev/null +++ b/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePlugin.java @@ -0,0 +1,15 @@ +package com.android.sampleplugin; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class SamplePlugin extends Service { + + @Override + public IBinder onBind(Intent intent) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java b/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java new file mode 100644 index 000000000..3c0a0c70c --- /dev/null +++ b/samples/BrowserPlugin/src/com/android/sampleplugin/SamplePluginStub.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package com.android.sampleplugin; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.opengl.GLSurfaceView; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.WindowManager; +import android.view.SurfaceHolder.Callback; +import android.view.ViewGroup.LayoutParams; +import android.webkit.PluginStub; +import android.widget.FrameLayout; +import android.widget.MediaController; +import android.widget.VideoView; +import com.android.sampleplugin.graphics.CubeRenderer; + +public class SamplePluginStub implements PluginStub { + + static { + //needed for jni calls + System.loadLibrary("sampleplugin"); + } + + public View getEmbeddedView(final int npp, Context context) { + + final SurfaceView view = new SurfaceView(context); + + /* You can do all sorts of interesting operations on the surface view + * here. We illustrate a few of the important operations below. + */ + + //TODO get pixel format from the subplugin (via jni) + view.getHolder().setFormat(PixelFormat.RGBA_8888); + view.getHolder().addCallback(new Callback() { + + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + nativeSurfaceChanged(npp, format, width, height); + } + + public void surfaceCreated(SurfaceHolder holder) { + nativeSurfaceCreated(npp, view); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + nativeSurfaceDestroyed(npp); + } + + }); + + if (nativeIsFixedSurface(npp)) { + //TODO get the fixed dimensions from the plugin + //view.getHolder().setFixedSize(width, height); + } + + return view; + } + + public View getFullScreenView(int npp, Context context) { + + /* TODO make this aware of the plugin instance and get the video file + * from the plugin. + */ + + FrameLayout layout = new FrameLayout(context); + LayoutParams fp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + layout.setLayoutParams(fp); + + VideoView video = new VideoView(context); + LayoutParams vp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + layout.setLayoutParams(vp); + + GLSurfaceView gl = new GLSurfaceView(context); + LayoutParams gp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + layout.setLayoutParams(gp); + + layout.addView(video); + layout.addView(gl); + + // We want an 8888 pixel format because that's required for a translucent + // window. And we want a depth buffer. + gl.setEGLConfigChooser(8, 8, 8, 8, 16, 0); + // Tell the cube renderer that we want to render a translucent version + // of the cube: + gl.setRenderer(new CubeRenderer(true)); + // Use a surface format with an Alpha channel: + gl.getHolder().setFormat(PixelFormat.TRANSLUCENT); + gl.setWindowType(WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY); + + + video.setVideoPath("/sdcard/test_video.3gp"); + video.setMediaController(new MediaController(context)); + video.requestFocus(); + + return layout; + } + + private native void nativeSurfaceCreated(int npp, View surfaceView); + private native void nativeSurfaceChanged(int npp, int format, int width, int height); + private native void nativeSurfaceDestroyed(int npp); + private native boolean nativeIsFixedSurface(int npp); +} diff --git a/samples/BrowserPlugin/src/com/android/sampleplugin/graphics/Cube.java b/samples/BrowserPlugin/src/com/android/sampleplugin/graphics/Cube.java new file mode 100644 index 000000000..9ad1410ea --- /dev/null +++ b/samples/BrowserPlugin/src/com/android/sampleplugin/graphics/Cube.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package com.android.sampleplugin.graphics; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + +import javax.microedition.khronos.opengles.GL10; + +/** + * A vertex shaded cube. + */ +class Cube +{ + public Cube() + { + int one = 0x10000; + int vertices[] = { + -one, -one, -one, + one, -one, -one, + one, one, -one, + -one, one, -one, + -one, -one, one, + one, -one, one, + one, one, one, + -one, one, one, + }; + + int colors[] = { + 0, 0, 0, one, + one, 0, 0, one, + one, one, 0, one, + 0, one, 0, one, + 0, 0, one, one, + one, 0, one, one, + one, one, one, one, + 0, one, one, one, + }; + + byte indices[] = { + 0, 4, 5, 0, 5, 1, + 1, 5, 6, 1, 6, 2, + 2, 6, 7, 2, 7, 3, + 3, 7, 4, 3, 4, 0, + 4, 7, 6, 4, 6, 5, + 3, 0, 1, 3, 1, 2 + }; + + // Buffers to be passed to gl*Pointer() functions + // must be direct, i.e., they must be placed on the + // native heap where the garbage collector cannot + // move them. + // + // Buffers with multi-byte datatypes (e.g., short, int, float) + // must have their byte order set to native order + + ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4); + vbb.order(ByteOrder.nativeOrder()); + mVertexBuffer = vbb.asIntBuffer(); + mVertexBuffer.put(vertices); + mVertexBuffer.position(0); + + ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4); + cbb.order(ByteOrder.nativeOrder()); + mColorBuffer = cbb.asIntBuffer(); + mColorBuffer.put(colors); + mColorBuffer.position(0); + + mIndexBuffer = ByteBuffer.allocateDirect(indices.length); + mIndexBuffer.put(indices); + mIndexBuffer.position(0); + } + + public void draw(GL10 gl) + { + gl.glFrontFace(gl.GL_CW); + gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer); + gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer); + gl.glDrawElements(gl.GL_TRIANGLES, 36, gl.GL_UNSIGNED_BYTE, mIndexBuffer); + } + + private IntBuffer mVertexBuffer; + private IntBuffer mColorBuffer; + private ByteBuffer mIndexBuffer; +} diff --git a/samples/BrowserPlugin/src/com/android/sampleplugin/graphics/CubeRenderer.java b/samples/BrowserPlugin/src/com/android/sampleplugin/graphics/CubeRenderer.java new file mode 100644 index 000000000..246ac15a0 --- /dev/null +++ b/samples/BrowserPlugin/src/com/android/sampleplugin/graphics/CubeRenderer.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package com.android.sampleplugin.graphics; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +import android.opengl.GLSurfaceView; + +/** + * Render a pair of tumbling cubes. + */ + +public class CubeRenderer implements GLSurfaceView.Renderer { + public CubeRenderer(boolean useTranslucentBackground) { + mTranslucentBackground = useTranslucentBackground; + mCube = new Cube(); + } + + public void onDrawFrame(GL10 gl) { + /* + * Usually, the first thing one might want to do is to clear + * the screen. The most efficient way of doing this is to use + * glClear(). + */ + + gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); + + /* + * Now we're ready to draw some 3D objects + */ + + gl.glMatrixMode(GL10.GL_MODELVIEW); + gl.glLoadIdentity(); + gl.glTranslatef(0, 0, -3.0f); + gl.glRotatef(mAngle, 0, 1, 0); + gl.glRotatef(mAngle*0.25f, 1, 0, 0); + + gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); + gl.glEnableClientState(GL10.GL_COLOR_ARRAY); + + mCube.draw(gl); + + gl.glRotatef(mAngle*2.0f, 0, 1, 1); + gl.glTranslatef(0.5f, 0.5f, 0.5f); + + mCube.draw(gl); + + mAngle += 1.2f; + } + + public void onSurfaceChanged(GL10 gl, int width, int height) { + gl.glViewport(0, 0, width, height); + + /* + * Set our projection matrix. This doesn't have to be done + * each time we draw, but usually a new projection needs to + * be set when the viewport is resized. + */ + + float ratio = (float) width / height; + gl.glMatrixMode(GL10.GL_PROJECTION); + gl.glLoadIdentity(); + gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); + } + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + /* + * By default, OpenGL enables features that improve quality + * but reduce performance. One might want to tweak that + * especially on software renderer. + */ + gl.glDisable(GL10.GL_DITHER); + + /* + * Some one-time OpenGL initialization can be made here + * probably based on features of this particular context + */ + gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, + GL10.GL_FASTEST); + + if (mTranslucentBackground) { + gl.glClearColor(0,0,0,0); + } else { + gl.glClearColor(1,1,1,1); + } + gl.glEnable(GL10.GL_CULL_FACE); + gl.glShadeModel(GL10.GL_SMOOTH); + gl.glEnable(GL10.GL_DEPTH_TEST); + } + private boolean mTranslucentBackground; + private Cube mCube; + private float mAngle; +} diff --git a/samples/BusinessCard/Android.mk b/samples/BusinessCard/Android.mk new file mode 100644 index 000000000..627cac1d5 --- /dev/null +++ b/samples/BusinessCard/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := samples + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := BusinessCard + +LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) diff --git a/samples/BusinessCard/AndroidManifest.xml b/samples/BusinessCard/AndroidManifest.xml new file mode 100644 index 000000000..186e249a0 --- /dev/null +++ b/samples/BusinessCard/AndroidManifest.xml @@ -0,0 +1,33 @@ +<?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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.businesscard"> + + <!-- IMPORTANT! We want this app to run on Cupcake, Donut, Eclair and beyond --> + <uses-sdk android:minSdkVersion="3"/> + + <uses-permission android:name="android.permission.READ_CONTACTS" /> + + <application android:label="@string/businesscard_app"> + <activity android:name="BusinessCardActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/samples/BusinessCard/res/layout/business_card.xml b/samples/BusinessCard/res/layout/business_card.xml new file mode 100644 index 000000000..c7ce71365 --- /dev/null +++ b/samples/BusinessCard/res/layout/business_card.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <Button + android:id="@+id/pick_contact_button" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_margin="10dip" + android:text="@string/button_pick_contact"/> + <TextView + android:id="@+id/display_name_text_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="true" + android:textAppearance="?android:attr/textAppearanceLarge"/> + <TextView + android:id="@+id/phone_number_text_view" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/display_name_text_view" + android:layout_centerHorizontal="true" + android:textAppearance="?android:attr/textAppearanceMedium"/> +</RelativeLayout> + diff --git a/samples/BusinessCard/res/values/strings.xml b/samples/BusinessCard/res/values/strings.xml new file mode 100644 index 000000000..8668d57d5 --- /dev/null +++ b/samples/BusinessCard/res/values/strings.xml @@ -0,0 +1,24 @@ +<?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. +--> + +<!-- This file contains resource definitions for displayed strings, allowing + them to be changed based on the locale and options. --> + +<resources> + <string name="businesscard_app">Business Card</string> + <string name="button_pick_contact">Pick Contact</string> +</resources> + diff --git a/samples/BusinessCard/src/com/example/android/businesscard/BusinessCardActivity.java b/samples/BusinessCard/src/com/example/android/businesscard/BusinessCardActivity.java new file mode 100644 index 000000000..d8d277e24 --- /dev/null +++ b/samples/BusinessCard/src/com/example/android/businesscard/BusinessCardActivity.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +package com.example.android.businesscard; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.TextView; + +/** + * A simple activity that shows a "Pick Contact" button and two fields: contact's name + * and phone number. The user taps on the Pick Contact button to bring up + * the contact chooser. Once this activity receives the result from contact picker, + * it launches an asynchronous query (queries should always be asynchronous) to load + * contact's name and phone number. When the query completes, the activity displays + * the loaded data. + */ +public class BusinessCardActivity extends Activity { + + // Request code for the contact picker activity + private static final int PICK_CONTACT_REQUEST = 1; + + /** + * An SDK-specific instance of {@link ContactAccessor}. The activity does not need + * to know what SDK it is running in: all idiosyncrasies of different SDKs are + * encapsulated in the implementations of the ContactAccessor class. + */ + private final ContactAccessor mContactAccessor = ContactAccessor.getInstance(); + + /** + * Called with the activity is first created. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.business_card); + + // Install a click handler on the Pick Contact button + Button pickContact = (Button)findViewById(R.id.pick_contact_button); + pickContact.setOnClickListener(new OnClickListener() { + + public void onClick(View v) { + pickContact(); + } + }); + } + + /** + * Click handler for the Pick Contact button. Invokes a contact picker activity. + * The specific intent used to bring up that activity differs between versions + * of the SDK, which is why we delegate the creation of the intent to ContactAccessor. + */ + protected void pickContact() { + startActivityForResult(mContactAccessor.getPickContactIntent(), PICK_CONTACT_REQUEST); + } + + /** + * Invoked when the contact picker activity is finished. The {@code contactUri} parameter + * will contain a reference to the contact selected by the user. We will treat it as + * an opaque URI and allow the SDK-specific ContactAccessor to handle the URI accordingly. + */ + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == PICK_CONTACT_REQUEST && resultCode == RESULT_OK) { + loadContactInfo(data.getData()); + } + } + + /** + * Load contact information on a background thread. + */ + private void loadContactInfo(Uri contactUri) { + + /* + * We should always run database queries on a background thread. The database may be + * locked by some process for a long time. If we locked up the UI thread while waiting + * for the query to come back, we might get an "Application Not Responding" dialog. + */ + AsyncTask<Uri, Void, ContactInfo> task = new AsyncTask<Uri, Void, ContactInfo>() { + + @Override + protected ContactInfo doInBackground(Uri... uris) { + return mContactAccessor.loadContact(getContentResolver(), uris[0]); + } + + @Override + protected void onPostExecute(ContactInfo result) { + bindView(result); + } + }; + + task.execute(contactUri); + } + + /** + * Displays contact information: name and phone number. + */ + protected void bindView(ContactInfo contactInfo) { + TextView displayNameView = (TextView) findViewById(R.id.display_name_text_view); + displayNameView.setText(contactInfo.getDisplayName()); + + TextView phoneNumberView = (TextView) findViewById(R.id.phone_number_text_view); + phoneNumberView.setText(contactInfo.getPhoneNumber()); + } +} diff --git a/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessor.java b/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessor.java new file mode 100644 index 000000000..6a402e9c6 --- /dev/null +++ b/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessor.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package com.example.android.businesscard; + +import android.content.ContentResolver; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; + +/** + * This abstract class defines SDK-independent API for communication with + * Contacts Provider. The actual implementation used by the application depends + * on the level of API available on the device. If the API level is Cupcake or + * Donut, we want to use the {@link ContactAccessorSdk3_4} class. If it is + * Eclair or higher, we want to use {@link ContactAccessorSdk5}. + */ +public abstract class ContactAccessor { + + /** + * Static singleton instance of {@link ContactAccessor} holding the + * SDK-specific implementation of the class. + */ + private static ContactAccessor sInstance; + + public static ContactAccessor getInstance() { + if (sInstance == null) { + String className; + + /* + * Check the version of the SDK we are running on. Choose an + * implementation class designed for that version of the SDK. + * + * Unfortunately we have to use strings to represent the class + * names. If we used the conventional ContactAccessorSdk5.class.getName() + * syntax, we would get a ClassNotFoundException at runtime on pre-Eclair SDKs. + * Using the above syntax would force Dalvik to load the class and try to + * resolve references to all other classes it uses. Since the pre-Eclair + * does not have those classes, the loading of ContactAccessorSdk5 would fail. + */ + @SuppressWarnings("deprecation") + int sdkVersion = Integer.parseInt(Build.VERSION.SDK); // Cupcake style + if (sdkVersion < Build.VERSION_CODES.ECLAIR) { + className = "com.example.android.businesscard.ContactAccessorSdk3_4"; + } else { + className = "com.example.android.businesscard.ContactAccessorSdk5"; + } + + /* + * Find the required class by name and instantiate it. + */ + try { + Class<? extends ContactAccessor> clazz = + Class.forName(className).asSubclass(ContactAccessor.class); + sInstance = clazz.newInstance(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + return sInstance; + } + + /** + * Returns the {@link Intent#ACTION_PICK} intent configured for the right authority: legacy + * or current. + */ + public abstract Intent getPickContactIntent(); + + /** + * Loads contact data for the supplied URI. The actual queries will differ for different APIs + * used, but the result is the same: the {@link #mDisplayName} and {@link #mPhoneNumber} + * fields are populated with correct data. + */ + public abstract ContactInfo loadContact(ContentResolver contentResolver, Uri contactUri); +} diff --git a/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessorSdk3_4.java b/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessorSdk3_4.java new file mode 100644 index 000000000..7fcd3886e --- /dev/null +++ b/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessorSdk3_4.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package com.example.android.businesscard; + +import android.content.AsyncQueryHandler; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.Contacts.People; +import android.provider.Contacts.People.Phones; + +/** + * An implementation of {@link ContactAccessor} that uses legacy Contacts API. + * These APIs are deprecated and should not be used unless we are running on a + * pre-Eclair SDK. + * <p> + * There are several reasons why we wouldn't want to use this class on an Eclair device: + * <ul> + * <li>It would see at most one account, namely the first Google account created on the device. + * <li>It would work through a compatibility layer, which would make it inherently less efficient. + * <li>Not relevant to this particular example, but it would not have access to new kinds + * of data available through current APIs. + * </ul> + */ +@SuppressWarnings("deprecation") +public class ContactAccessorSdk3_4 extends ContactAccessor { + + /** + * Returns a Pick Contact intent using the pre-Eclair "people" URI. + */ + @Override + public Intent getPickContactIntent() { + return new Intent(Intent.ACTION_PICK, People.CONTENT_URI); + } + + /** + * Retrieves the contact information. + */ + @Override + public ContactInfo loadContact(ContentResolver contentResolver, Uri contactUri) { + ContactInfo contactInfo = new ContactInfo(); + Cursor cursor = contentResolver.query(contactUri, + new String[]{People.DISPLAY_NAME}, null, null, null); + try { + if (cursor.moveToFirst()) { + contactInfo.setDisplayName(cursor.getString(0)); + } + } finally { + cursor.close(); + } + + Uri phoneUri = Uri.withAppendedPath(contactUri, Phones.CONTENT_DIRECTORY); + cursor = contentResolver.query(phoneUri, + new String[]{Phones.NUMBER}, null, null, Phones.ISPRIMARY + " DESC"); + + try { + if (cursor.moveToFirst()) { + contactInfo.setPhoneNumber(cursor.getString(0)); + } + } finally { + cursor.close(); + } + + return contactInfo; + } +} diff --git a/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessorSdk5.java b/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessorSdk5.java new file mode 100644 index 000000000..6855597f0 --- /dev/null +++ b/samples/BusinessCard/src/com/example/android/businesscard/ContactAccessorSdk5.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package com.example.android.businesscard; + +import android.content.ContentResolver; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.provider.ContactsContract.Contacts; +import android.provider.ContactsContract.CommonDataKinds.Phone; + +/** + * An implementation of {@link ContactAccessor} that uses current Contacts API. + * This class should be used on Eclair or beyond, but would not work on any earlier + * release of Android. As a matter of fact, it could not even be loaded. + * <p> + * This implementation has several advantages: + * <ul> + * <li>It sees contacts from multiple accounts. + * <li>It works with aggregated contacts. So for example, if the contact is the result + * of aggregation of two raw contacts from different accounts, it may return the name from + * one and the phone number from the other. + * <li>It is efficient because it uses the more efficient current API. + * <li>Not obvious in this particular example, but it has access to new kinds + * of data available exclusively through the new APIs. Exercise for the reader: add support + * for nickname (see {@link android.provider.ContactsContract.CommonDataKinds.Nickname}) or + * social status updates (see {@link android.provider.ContactsContract.StatusUpdates}). + * </ul> + */ +public class ContactAccessorSdk5 extends ContactAccessor { + + /** + * Returns a Pick Contact intent using the Eclair "contacts" URI. + */ + @Override + public Intent getPickContactIntent() { + return new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI); + } + + /** + * Retrieves the contact information. + */ + @Override + public ContactInfo loadContact(ContentResolver contentResolver, Uri contactUri) { + ContactInfo contactInfo = new ContactInfo(); + long contactId = -1; + + // Load the display name for the specified person + Cursor cursor = contentResolver.query(contactUri, + new String[]{Contacts._ID, Contacts.DISPLAY_NAME}, null, null, null); + try { + if (cursor.moveToFirst()) { + contactId = cursor.getLong(0); + contactInfo.setDisplayName(cursor.getString(1)); + } + } finally { + cursor.close(); + } + + // Load the phone number (if any). + cursor = contentResolver.query(Phone.CONTENT_URI, + new String[]{Phone.NUMBER}, + Phone.CONTACT_ID + "=" + contactId, null, Phone.IS_SUPER_PRIMARY + " DESC"); + try { + if (cursor.moveToFirst()) { + contactInfo.setPhoneNumber(cursor.getString(0)); + } + } finally { + cursor.close(); + } + + return contactInfo; + } +} diff --git a/samples/BusinessCard/src/com/example/android/businesscard/ContactInfo.java b/samples/BusinessCard/src/com/example/android/businesscard/ContactInfo.java new file mode 100644 index 000000000..61a6f3b3f --- /dev/null +++ b/samples/BusinessCard/src/com/example/android/businesscard/ContactInfo.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package com.example.android.businesscard; + +/** + * A model object containing contact data. + */ +public class ContactInfo { + + private String mDisplayName; + private String mPhoneNumber; + + public void setDisplayName(String displayName) { + this.mDisplayName = displayName; + } + + public String getDisplayName() { + return mDisplayName; + } + + public void setPhoneNumber(String phoneNumber) { + this.mPhoneNumber = phoneNumber; + } + + public String getPhoneNumber() { + return mPhoneNumber; + } +} diff --git a/samples/CubeLiveWallpaper/Android.mk b/samples/CubeLiveWallpaper/Android.mk new file mode 100644 index 000000000..7227394d3 --- /dev/null +++ b/samples/CubeLiveWallpaper/Android.mk @@ -0,0 +1,27 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# LOCAL_MODULE_TAGS := user + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := CubeLiveWallpapers +LOCAL_CERTIFICATE := shared + +include $(BUILD_PACKAGE) diff --git a/samples/CubeLiveWallpaper/AndroidManifest.xml b/samples/CubeLiveWallpaper/AndroidManifest.xml new file mode 100644 index 000000000..8d24c4a60 --- /dev/null +++ b/samples/CubeLiveWallpaper/AndroidManifest.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 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. +*/ +--> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.livecubes"> + + <application + android:label="@string/wallpapers" + android:icon="@drawable/ic_launcher_wallpaper"> + + <service + android:label="@string/wallpaper_cube1" + android:name=".cube1.CubeWallpaper1" + android:permission="android.permission.BIND_WALLPAPER"> + <intent-filter> + <action android:name="android.service.wallpaper.WallpaperService" /> + </intent-filter> + <meta-data android:name="android.service.wallpaper" android:resource="@xml/cube1" /> + </service> + + <service + android:label="@string/wallpaper_cube2" + android:name=".cube2.CubeWallpaper2" + android:permission="android.permission.BIND_WALLPAPER"> + <intent-filter> + <action android:name="android.service.wallpaper.WallpaperService" /> + </intent-filter> + <meta-data android:name="android.service.wallpaper" android:resource="@xml/cube2" /> + </service> + <activity + android:label="@string/cube2_settings" + android:name="com.android.livecubes.cube2.CubeWallpaper2Settings" + android:theme="@android:style/Theme.Light.WallpaperSettings" + android:exported="true"> + </activity> + + <service + android:label="@string/wallpaper_cube3" + android:name=".cube3.CubeWallpaper3" + android:permission="android.permission.BIND_WALLPAPER"> + <intent-filter> + <action android:name="android.service.wallpaper.WallpaperService" /> + </intent-filter> + <meta-data android:name="android.service.wallpaper" android:resource="@xml/cube3" /> + </service> + + </application> + +</manifest> diff --git a/samples/CubeLiveWallpaper/MODULE_LICENSE_APACHE2 b/samples/CubeLiveWallpaper/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/samples/CubeLiveWallpaper/MODULE_LICENSE_APACHE2 diff --git a/samples/CubeLiveWallpaper/NOTICE b/samples/CubeLiveWallpaper/NOTICE new file mode 100644 index 000000000..c5b1efa7a --- /dev/null +++ b/samples/CubeLiveWallpaper/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/samples/CubeLiveWallpaper/res/drawable/ic_launcher_wallpaper.png b/samples/CubeLiveWallpaper/res/drawable/ic_launcher_wallpaper.png Binary files differnew file mode 100644 index 000000000..965fb7143 --- /dev/null +++ b/samples/CubeLiveWallpaper/res/drawable/ic_launcher_wallpaper.png diff --git a/samples/CubeLiveWallpaper/res/raw/cube.rs b/samples/CubeLiveWallpaper/res/raw/cube.rs new file mode 100644 index 000000000..407d63bb4 --- /dev/null +++ b/samples/CubeLiveWallpaper/res/raw/cube.rs @@ -0,0 +1,50 @@ +// 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. + +#pragma version(1) +#pragma stateVertex(PVBackground) + +#define RSID_POINTS 0 + +void dumpState() { + +// debugF("@@@@@ yrot: ", State->yRotation); + +} + +int main(int launchID) { + + int i; + + // Change the model matrix to account for the large model + // and to do the necessary rotations. + float mat1[16]; + float rads = ((float)startTimeMillis()) / 1000; + float xrot = degf(-rads); + float yrot = State->yRotation; + float scale = 1.0/900.0; + matrixLoadScale(mat1, scale, scale, scale); + matrixRotate(mat1, yrot, 0.f, 1.f, 0.f); + matrixRotate(mat1, xrot, 1.f, 0.f, 0.f); + vpLoadModelMatrix(mat1); + + // Draw the cube. The default color will be used, + // but we can also set the color here with the color() + // function, or specify the color(s) as part of + // the vertex data. + uploadToBufferObject(NAMED_PointBuffer); + drawSimpleMesh(NAMED_CubeMesh); + + return 1; +} diff --git a/samples/CubeLiveWallpaper/res/values/shapes.xml b/samples/CubeLiveWallpaper/res/values/shapes.xml new file mode 100644 index 000000000..49bdaf9e8 --- /dev/null +++ b/samples/CubeLiveWallpaper/res/values/shapes.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright (C) 4008 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <string-array name="cube2_shapenames"> + <item>"Cube"</item> + <item>"Dodecahedron"</item> + </string-array> + + <string-array name="cube2_shapeprefix"> + <item>"cube"</item> + <item>"dodecahedron"</item> + </string-array> + + <!-- x,y,z tuples for the points defining the object --> + <!-- stored as strings for easier human readability --> + <string-array name="cubepoints"> + <item>"-400 -400 -400"</item> + <item>"400 -400 -400"</item> + <item>"400 400 -400"</item> + <item>"-400 400 -400"</item> + <item>"-400 -400 400"</item> + <item>"400 -400 400"</item> + <item>"400 400 400"</item> + <item>"-400 400 400"</item> + </string-array> + + <!-- start,end point index tuples of the lines defining the object --> + <string-array name="cubelines"> + <!-- lines forming one face --> + <item>"0 1"</item> + <item>"1 2"</item> + <item>"2 3"</item> + <item>"3 0"</item> + + <!-- lines forming the opposite face --> + <item>"4 5"</item> + <item>"5 6"</item> + <item>"6 7"</item> + <item>"7 4"</item> + + <!-- lines connecting the two faces --> + <item>"0 4"</item> + <item>"1 5"</item> + <item>"2 6"</item> + <item>"3 7"</item> + </string-array> + + <string-array name="dodecahedronpoints"> + <item>"333.850000 0.000000 437.250000"</item> + <item>"103.400000 317.350000 437.250000"</item> + <item>"-270.050000 196.350000 437.250000"</item> + <item>"-270.050000 -196.350000 437.250000"</item> + <item>"103.400000 -317.350000 437.250000"</item> + <item>"540.100000 0.000000 103.400000"</item> + <item>"167.200000 513.700000 103.400000"</item> + <item>"-437.250000 317.350000 103.400000"</item> + <item>"-437.250000 -317.350000 103.400000"</item> + <item>"167.200000 -513.700000 103.400000"</item> + <item>"437.250000 317.350000 -103.400000"</item> + <item>"-167.200000 513.700000 -103.400000"</item> + <item>"-540.100000 0.000000 -103.400000"</item> + <item>"-167.200000 -513.700000 -103.400000"</item> + <item>"437.250000 -317.350000 -103.400000"</item> + <item>"270.050000 196.350000 -437.250000"</item> + <item>"-103.400000 317.350000 -437.250000"</item> + <item>"-333.850000 0.000000 -437.250000"</item> + <item>"-103.400000 -317.350000 -437.250000"</item> + <item>"270.050000 -196.350000 -437.250000"</item> + </string-array> + + <string-array name="dodecahedronlines"> + <item>"0 1"</item> + <item>"0 4"</item> + <item>"0 5"</item> + <item>"1 2"</item> + <item>"1 6"</item> + <item>"2 3"</item> + <item>"2 7"</item> + <item>"3 4"</item> + <item>"3 8"</item> + <item>"4 9"</item> + <item>"5 10"</item> + <item>"5 14"</item> + <item>"6 10"</item> + <item>"6 11"</item> + <item>"7 11"</item> + <item>"7 12"</item> + <item>"8 12"</item> + <item>"8 13"</item> + <item>"9 13"</item> + <item>"9 14"</item> + <item>"10 15"</item> + <item>"11 16"</item> + <item>"12 17"</item> + <item>"13 18"</item> + <item>"14 19"</item> + <item>"15 16"</item> + <item>"15 19"</item> + <item>"16 17"</item> + <item>"17 18"</item> + <item>"18 19"</item> + </string-array> +</resources> diff --git a/samples/CubeLiveWallpaper/res/values/strings.xml b/samples/CubeLiveWallpaper/res/values/strings.xml new file mode 100644 index 000000000..3302058b5 --- /dev/null +++ b/samples/CubeLiveWallpaper/res/values/strings.xml @@ -0,0 +1,38 @@ +<?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. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- General --> + <skip /> + <!-- Application name --> + <string name="wallpapers">Example Wallpapers</string> + + <!-- Wallpaper showing a cube --> + <string name="wallpaper_cube1">Cube</string> + + <!-- Wallpaper showing a cube or dodecahedron, data read from resource --> + <string name="wallpaper_cube2">Cube - resource</string> + + <!-- Wallpaper showing a cube, renderscript version --> + <string name="wallpaper_cube3">Cube - RenderScript</string> + + <string name="cube2_settings">Settings</string> + <string name="cube2_settings_title">Select shape</string> + <string name="cube2_settings_summary">Choose whether to display a cube or a dodecahedron</string> +</resources> diff --git a/samples/CubeLiveWallpaper/res/xml/cube1.xml b/samples/CubeLiveWallpaper/res/xml/cube1.xml new file mode 100644 index 000000000..5c7fca50d --- /dev/null +++ b/samples/CubeLiveWallpaper/res/xml/cube1.xml @@ -0,0 +1,23 @@ +<?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. + */ +--> + +<!-- The attributes in this XML file provide configuration information --> + +<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" +/> diff --git a/samples/CubeLiveWallpaper/res/xml/cube2.xml b/samples/CubeLiveWallpaper/res/xml/cube2.xml new file mode 100644 index 000000000..bf9054c4c --- /dev/null +++ b/samples/CubeLiveWallpaper/res/xml/cube2.xml @@ -0,0 +1,24 @@ +<?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. + */ +--> + +<!-- The attributes in this XML file provide configuration information --> + +<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" + android:settingsActivity="com.android.livecubes.cube2.CubeWallpaper2Settings" +/> diff --git a/samples/CubeLiveWallpaper/res/xml/cube2_settings.xml b/samples/CubeLiveWallpaper/res/xml/cube2_settings.xml new file mode 100644 index 000000000..50a28aea0 --- /dev/null +++ b/samples/CubeLiveWallpaper/res/xml/cube2_settings.xml @@ -0,0 +1,28 @@ +<?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. +--> + +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" + android:title="@string/cube2_settings" + android:key="cube2wallpaper_settings"> + + <ListPreference + android:key="cube2_shape" + android:title="@string/cube2_settings_title" + android:summary="@string/cube2_settings_summary" + android:entries="@array/cube2_shapenames" + android:entryValues="@array/cube2_shapeprefix" /> + +</PreferenceScreen> diff --git a/samples/CubeLiveWallpaper/res/xml/cube3.xml b/samples/CubeLiveWallpaper/res/xml/cube3.xml new file mode 100644 index 000000000..5c7fca50d --- /dev/null +++ b/samples/CubeLiveWallpaper/res/xml/cube3.xml @@ -0,0 +1,23 @@ +<?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. + */ +--> + +<!-- The attributes in this XML file provide configuration information --> + +<wallpaper xmlns:android="http://schemas.android.com/apk/res/android" +/> diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube1/CubeWallpaper1.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube1/CubeWallpaper1.java new file mode 100644 index 000000000..52a708afd --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube1/CubeWallpaper1.java @@ -0,0 +1,241 @@ +/* + * 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. + */ + +package com.android.livecubes.cube1; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Handler; +import android.os.SystemClock; +import android.service.wallpaper.WallpaperService; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceHolder; + +/* + * This animated wallpaper draws a rotating wireframe cube. + */ +public class CubeWallpaper1 extends WallpaperService { + + private final Handler mHandler = new Handler(); + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public Engine onCreateEngine() { + return new CubeEngine(); + } + + class CubeEngine extends Engine { + + private final Paint mPaint = new Paint(); + private float mOffset; + private float mTouchX = -1; + private float mTouchY = -1; + private long mStartTime; + private float mCenterX; + private float mCenterY; + + private final Runnable mDrawCube = new Runnable() { + public void run() { + drawFrame(); + } + }; + private boolean mVisible; + + CubeEngine() { + // Create a Paint to draw the lines for our cube + final Paint paint = mPaint; + paint.setColor(0xffffffff); + paint.setAntiAlias(true); + paint.setStrokeWidth(2); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStyle(Paint.Style.STROKE); + + mStartTime = SystemClock.elapsedRealtime(); + } + + @Override + public void onCreate(SurfaceHolder surfaceHolder) { + super.onCreate(surfaceHolder); + + // By default we don't get touch events, so enable them. + setTouchEventsEnabled(true); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mHandler.removeCallbacks(mDrawCube); + } + + @Override + public void onVisibilityChanged(boolean visible) { + mVisible = visible; + if (visible) { + drawFrame(); + } else { + mHandler.removeCallbacks(mDrawCube); + } + } + + @Override + public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { + super.onSurfaceChanged(holder, format, width, height); + // store the center of the surface, so we can draw the cube in the right spot + mCenterX = width/2.0f; + mCenterY = height/2.0f; + drawFrame(); + } + + @Override + public void onSurfaceCreated(SurfaceHolder holder) { + super.onSurfaceCreated(holder); + } + + @Override + public void onSurfaceDestroyed(SurfaceHolder holder) { + super.onSurfaceDestroyed(holder); + mVisible = false; + mHandler.removeCallbacks(mDrawCube); + } + + @Override + public void onOffsetsChanged(float xOffset, float yOffset, + float xStep, float yStep, int xPixels, int yPixels) { + mOffset = xOffset; + drawFrame(); + } + + /* + * Store the position of the touch event so we can use it for drawing later + */ + @Override + public void onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + mTouchX = event.getX(); + mTouchY = event.getY(); + } else { + mTouchX = -1; + mTouchY = -1; + } + super.onTouchEvent(event); + } + + /* + * Draw one frame of the animation. This method gets called repeatedly + * by posting a delayed Runnable. You can do any drawing you want in + * here. This example draws a wireframe cube. + */ + void drawFrame() { + final SurfaceHolder holder = getSurfaceHolder(); + + Canvas c = null; + try { + c = holder.lockCanvas(); + if (c != null) { + // draw something + drawCube(c); + drawTouchPoint(c); + } + } finally { + if (c != null) holder.unlockCanvasAndPost(c); + } + + // Reschedule the next redraw + mHandler.removeCallbacks(mDrawCube); + if (mVisible) { + mHandler.postDelayed(mDrawCube, 1000 / 25); + } + } + + /* + * Draw a wireframe cube by drawing 12 3 dimensional lines between + * adjacent corners of the cube + */ + void drawCube(Canvas c) { + c.save(); + c.translate(mCenterX, mCenterY); + c.drawColor(0xff000000); + drawLine(c, -400, -400, -400, 400, -400, -400); + drawLine(c, 400, -400, -400, 400, 400, -400); + drawLine(c, 400, 400, -400, -400, 400, -400); + drawLine(c, -400, 400, -400, -400, -400, -400); + + drawLine(c, -400, -400, 400, 400, -400, 400); + drawLine(c, 400, -400, 400, 400, 400, 400); + drawLine(c, 400, 400, 400, -400, 400, 400); + drawLine(c, -400, 400, 400, -400, -400, 400); + + drawLine(c, -400, -400, 400, -400, -400, -400); + drawLine(c, 400, -400, 400, 400, -400, -400); + drawLine(c, 400, 400, 400, 400, 400, -400); + drawLine(c, -400, 400, 400, -400, 400, -400); + c.restore(); + } + + /* + * Draw a 3 dimensional line on to the screen + */ + void drawLine(Canvas c, int x1, int y1, int z1, int x2, int y2, int z2) { + long now = SystemClock.elapsedRealtime(); + float xrot = ((float)(now - mStartTime)) / 1000; + float yrot = (0.5f - mOffset) * 2.0f; + float zrot = 0; + + // 3D transformations + + // rotation around X-axis + float newy1 = (float)(Math.sin(xrot) * z1 + Math.cos(xrot) * y1); + float newy2 = (float)(Math.sin(xrot) * z2 + Math.cos(xrot) * y2); + float newz1 = (float)(Math.cos(xrot) * z1 - Math.sin(xrot) * y1); + float newz2 = (float)(Math.cos(xrot) * z2 - Math.sin(xrot) * y2); + + // rotation around Y-axis + float newx1 = (float)(Math.sin(yrot) * newz1 + Math.cos(yrot) * x1); + float newx2 = (float)(Math.sin(yrot) * newz2 + Math.cos(yrot) * x2); + newz1 = (float)(Math.cos(yrot) * newz1 - Math.sin(yrot) * x1); + newz2 = (float)(Math.cos(yrot) * newz2 - Math.sin(yrot) * x2); + + // 3D-to-2D projection + float startX = newx1 / (4 - newz1 / 400); + float startY = newy1 / (4 - newz1 / 400); + float stopX = newx2 / (4 - newz2 / 400); + float stopY = newy2 / (4 - newz2 / 400); + + c.drawLine(startX, startY, stopX, stopY, mPaint); + } + + /* + * Draw a circle around the current touch point, if any. + */ + void drawTouchPoint(Canvas c) { + if (mTouchX >=0 && mTouchY >= 0) { + c.drawCircle(mTouchX, mTouchY, 80, mPaint); + } + } + + } +} diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube2/CubeWallpaper2.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube2/CubeWallpaper2.java new file mode 100644 index 000000000..0c6d90e52 --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube2/CubeWallpaper2.java @@ -0,0 +1,297 @@ +/* + * 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. + */ + +package com.android.livecubes.cube2; + +import com.android.livecubes.R; + +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Handler; +import android.os.SystemClock; +import android.service.wallpaper.WallpaperService; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceHolder; + +/* + * This animated wallpaper draws a rotating wireframe shape. It is similar to + * example #1, but has a choice of 2 shapes, which are user selectable and + * defined in resources instead of in code. + */ + +public class CubeWallpaper2 extends WallpaperService { + + public static final String SHARED_PREFS_NAME="cube2settings"; + + static class ThreeDPoint { + float x; + float y; + float z; + } + + static class ThreeDLine { + int startPoint; + int endPoint; + } + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public Engine onCreateEngine() { + return new CubeEngine(); + } + + class CubeEngine extends Engine + implements SharedPreferences.OnSharedPreferenceChangeListener { + + private final Handler mHandler = new Handler(); + + ThreeDPoint [] mOriginalPoints; + ThreeDPoint [] mRotatedPoints; + ThreeDLine [] mLines; + private final Paint mPaint = new Paint(); + private float mOffset; + private float mTouchX = -1; + private float mTouchY = -1; + private long mStartTime; + private float mCenterX; + private float mCenterY; + + private final Runnable mDrawCube = new Runnable() { + public void run() { + drawFrame(); + } + }; + private boolean mVisible; + private SharedPreferences mPrefs; + + CubeEngine() { + // Create a Paint to draw the lines for our cube + final Paint paint = mPaint; + paint.setColor(0xffffffff); + paint.setAntiAlias(true); + paint.setStrokeWidth(2); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStyle(Paint.Style.STROKE); + + mStartTime = SystemClock.elapsedRealtime(); + + mPrefs = CubeWallpaper2.this.getSharedPreferences(SHARED_PREFS_NAME, 0); + mPrefs.registerOnSharedPreferenceChangeListener(this); + onSharedPreferenceChanged(mPrefs, null); + } + + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + + String shape = prefs.getString("cube2_shape", "cube"); + + // read the 3D model from the resource + readModel(shape); + } + + private void readModel(String prefix) { + // Read the model definition in from a resource. + + // get the resource identifiers for the arrays for the selected shape + int pid = getResources().getIdentifier(prefix + "points", "array", getPackageName()); + int lid = getResources().getIdentifier(prefix + "lines", "array", getPackageName()); + + String [] p = getResources().getStringArray(pid); + int numpoints = p.length; + mOriginalPoints = new ThreeDPoint[numpoints]; + mRotatedPoints = new ThreeDPoint[numpoints]; + + for (int i = 0; i < numpoints; i++) { + mOriginalPoints[i] = new ThreeDPoint(); + mRotatedPoints[i] = new ThreeDPoint(); + String [] coord = p[i].split(" "); + mOriginalPoints[i].x = Float.valueOf(coord[0]); + mOriginalPoints[i].y = Float.valueOf(coord[1]); + mOriginalPoints[i].z = Float.valueOf(coord[2]); + } + + String [] l = getResources().getStringArray(lid); + int numlines = l.length; + mLines = new ThreeDLine[numlines]; + + for (int i = 0; i < numlines; i++) { + mLines[i] = new ThreeDLine(); + String [] idx = l[i].split(" "); + mLines[i].startPoint = Integer.valueOf(idx[0]); + mLines[i].endPoint = Integer.valueOf(idx[1]); + } + } + + @Override + public void onCreate(SurfaceHolder surfaceHolder) { + super.onCreate(surfaceHolder); + setTouchEventsEnabled(true); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mHandler.removeCallbacks(mDrawCube); + } + + @Override + public void onVisibilityChanged(boolean visible) { + mVisible = visible; + if (visible) { + drawFrame(); + } else { + mHandler.removeCallbacks(mDrawCube); + } + } + + @Override + public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { + super.onSurfaceChanged(holder, format, width, height); + // store the center of the surface, so we can draw the cube in the right spot + mCenterX = width/2.0f; + mCenterY = height/2.0f; + drawFrame(); + } + + @Override + public void onSurfaceCreated(SurfaceHolder holder) { + super.onSurfaceCreated(holder); + } + + @Override + public void onSurfaceDestroyed(SurfaceHolder holder) { + super.onSurfaceDestroyed(holder); + mVisible = false; + mHandler.removeCallbacks(mDrawCube); + } + + @Override + public void onOffsetsChanged(float xOffset, float yOffset, + float xStep, float yStep, int xPixels, int yPixels) { + mOffset = xOffset; + drawFrame(); + } + + /* + * Store the position of the touch event so we can use it for drawing later + */ + @Override + public void onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + mTouchX = event.getX(); + mTouchY = event.getY(); + } else { + mTouchX = -1; + mTouchY = -1; + } + super.onTouchEvent(event); + } + + /* + * Draw one frame of the animation. This method gets called repeatedly + * by posting a delayed Runnable. You can do any drawing you want in + * here. This example draws a wireframe cube. + */ + void drawFrame() { + final SurfaceHolder holder = getSurfaceHolder(); + final Rect frame = holder.getSurfaceFrame(); + final int width = frame.width(); + final int height = frame.height(); + + Canvas c = null; + try { + c = holder.lockCanvas(); + if (c != null) { + // draw something + drawCube(c); + drawTouchPoint(c); + } + } finally { + if (c != null) holder.unlockCanvasAndPost(c); + } + + mHandler.removeCallbacks(mDrawCube); + if (mVisible) { + mHandler.postDelayed(mDrawCube, 1000 / 25); + } + } + + void drawCube(Canvas c) { + c.save(); + c.translate(mCenterX, mCenterY); + c.drawColor(0xff000000); + + long now = SystemClock.elapsedRealtime(); + float xrot = ((float)(now - mStartTime)) / 1000; + float yrot = (0.5f - mOffset) * 2.0f; + rotateAndProjectPoints(xrot, yrot); + drawLines(c); + c.restore(); + } + + void rotateAndProjectPoints(float xrot, float yrot) { + int n = mOriginalPoints.length; + for (int i = 0; i < n; i++) { + // rotation around X-axis + ThreeDPoint p = mOriginalPoints[i]; + float x = p.x; + float y = p.y; + float z = p.z; + float newy = (float)(Math.sin(xrot) * z + Math.cos(xrot) * y); + float newz = (float)(Math.cos(xrot) * z - Math.sin(xrot) * y); + + // rotation around Y-axis + float newx = (float)(Math.sin(yrot) * newz + Math.cos(yrot) * x); + newz = (float)(Math.cos(yrot) * newz - Math.sin(yrot) * x); + + // 3D-to-2D projection + float screenX = newx / (4 - newz / 400); + float screenY = newy / (4 - newz / 400); + + mRotatedPoints[i].x = screenX; + mRotatedPoints[i].y = screenY; + mRotatedPoints[i].z = 0; + } + } + + void drawLines(Canvas c) { + int n = mLines.length; + for (int i = 0; i < n; i++) { + ThreeDLine l = mLines[i]; + ThreeDPoint start = mRotatedPoints[l.startPoint]; + ThreeDPoint end = mRotatedPoints[l.endPoint]; + c.drawLine(start.x, start.y, end.x, end.y, mPaint); + } + } + + void drawTouchPoint(Canvas c) { + if (mTouchX >=0 && mTouchY >= 0) { + c.drawCircle(mTouchX, mTouchY, 80, mPaint); + } + } + } +} diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube2/CubeWallpaper2Settings.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube2/CubeWallpaper2Settings.java new file mode 100644 index 000000000..feeb0bdc2 --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube2/CubeWallpaper2Settings.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * 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.livecubes.cube2; + +import com.android.livecubes.R; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.service.wallpaper.WallpaperSettingsActivity; + +public class CubeWallpaper2Settings extends WallpaperSettingsActivity + implements SharedPreferences.OnSharedPreferenceChangeListener { + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + getPreferenceManager().setSharedPreferencesName( + CubeWallpaper2.SHARED_PREFS_NAME); + addPreferencesFromResource(R.xml.cube2_settings); + getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener( + this); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onDestroy() { + getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( + this); + super.onDestroy(); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + //(new BackupManager(this)).dataChanged(); + } +} diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/Cube3RS.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/Cube3RS.java new file mode 100644 index 000000000..5cfad140f --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/Cube3RS.java @@ -0,0 +1,242 @@ +/* + * 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. + */ + +package com.android.livecubes.cube3; + +import com.android.livecubes.R; +import com.android.livecubes.RenderScriptScene; + +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.Primitive; +import android.renderscript.ProgramRaster; +import android.renderscript.ProgramVertex; +import android.renderscript.ScriptC; +import android.renderscript.SimpleMesh; +import android.renderscript.Type; +import android.renderscript.Element.Builder; + +import java.util.TimeZone; + +/* + * This example draws a shape whose definition is read from resources (though + * it's not user selectable like in example #2), but does the drawing using + * RenderScript. + */ +class Cube3RS extends RenderScriptScene { + + static class ThreeDPoint { + public float x; + public float y; + public float z; + } + + static class ThreeDLine { + int startPoint; + int endPoint; + } + + static class WorldState { + public float yRotation; + public float mCenterX; + public float mCenterY; + } + ThreeDPoint [] mOriginalPoints; + ThreeDLine [] mLines; + + WorldState mWorldState = new WorldState(); + private Type mStateType; + private Allocation mState; + + private SimpleMesh mCubeMesh; + + private Allocation mPointAlloc; + private float [] mPointData; + + private Allocation mLineIdxAlloc; + private short [] mIndexData; + + private ProgramVertex mPVBackground; + private ProgramVertex.MatrixAllocation mPVAlloc; + + private int mWidth; + private int mHeight; + + private static final int RSID_STATE = 0; + private static final int RSID_POINTS = 1; + private static final int RSID_LINES = 2; + private static final int RSID_PROGRAMVERTEX = 3; + + + Cube3RS(int width, int height) { + super(width, height); + mWidth = width; + mHeight = height; + } + + @Override + public void resize(int width, int height) { + super.resize(width, height); + mWidth = width; + mHeight = height; + } + + @Override + protected ScriptC createScript() { + + // Read the model in to our point/line objects + readModel(); + + // Create a renderscript type from a java class. The specified name doesn't + // really matter; the name by which we refer to the object in RenderScript + // will be specified later. + mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState"); + // Create an allocation from the type we just created. + mState = Allocation.createTyped(mRS, mStateType); + // set our java object as the data for the renderscript allocation + mWorldState.yRotation = (-0.5f) * 2 * 180 / (float) Math.PI; + mState.data(mWorldState); + + /* + * Now put our model in to a form that renderscript can work with: + * - create a buffer of floats that are the coordinates for the points that define the cube + * - create a buffer of integers that are the indices of the points that form lines + * - combine the two in to a mesh + */ + + // First set up the coordinate system and such + ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null); + mPVBackground = pvb.create(); + mPVBackground.setName("PVBackground"); + mPVAlloc = new ProgramVertex.MatrixAllocation(mRS); + mPVBackground.bindAllocation(mPVAlloc); + mPVAlloc.setupProjectionNormalized(mWidth, mHeight); + + // Start creating the mesh + final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS); + + // Create the Element for the points + Builder elementBuilder = new Builder(mRS); + // By specifying a prefix, even an empty one, the members will be accessible + // in the renderscript. If we just called addFloatXYZ(), the members would be + // unnamed in the renderscript struct definition. + elementBuilder.addFloatXYZ(""); + final Element vertexElement = elementBuilder.create(); + final int vertexSlot = meshBuilder.addVertexType(vertexElement, mOriginalPoints.length); + // Specify the type and number of indices we need. We'll allocate them later. + meshBuilder.setIndexType(Element.INDEX_16(mRS), mLines.length * 2); + // This will be a line mesh + meshBuilder.setPrimitive(Primitive.LINE); + + // Create the Allocation for the vertices + mCubeMesh = meshBuilder.create(); + mCubeMesh.setName("CubeMesh"); + mPointAlloc = mCubeMesh.createVertexAllocation(vertexSlot); + mPointAlloc.setName("PointBuffer"); + + // Create the Allocation for the indices + mLineIdxAlloc = mCubeMesh.createIndexAllocation(); + + // Bind the allocations to the mesh + mCubeMesh.bindVertexAllocation(mPointAlloc, 0); + mCubeMesh.bindIndexAllocation(mLineIdxAlloc); + + /* + * put the vertex and index data in their respective buffers + */ + // one float each for x, y and z, and the 4th float will hold rgba + mPointData = new float[mOriginalPoints.length * 3]; + for(int i = 0; i < mOriginalPoints.length; i ++) { + mPointData[i*3] = mOriginalPoints[i].x; + mPointData[i*3+1] = mOriginalPoints[i].y; + mPointData[i*3+2] = mOriginalPoints[i].z; + } + mIndexData = new short[mLines.length * 2]; + for(int i = 0; i < mLines.length; i++) { + mIndexData[i * 2] = (short)(mLines[i].startPoint); + mIndexData[i * 2 + 1] = (short)(mLines[i].endPoint); + } + + /* + * upload the vertex and index data + */ + mPointAlloc.data(mPointData); + mPointAlloc.uploadToBufferObject(); + mLineIdxAlloc.data(mIndexData); + mLineIdxAlloc.uploadToBufferObject(); + + // Time to create the script + ScriptC.Builder sb = new ScriptC.Builder(mRS); + // Specify the name by which to refer to the WorldState object in the + // renderscript. + sb.setType(mStateType, "State", RSID_STATE); + sb.setType(mCubeMesh.getVertexType(0), "Points", RSID_POINTS); + // this crashes when uncommented + //sb.setType(mCubeMesh.getIndexType(), "Lines", RSID_LINES); + + // Set the render script that will make use of the objects we defined above + sb.setScript(mResources, R.raw.cube); + sb.setRoot(true); + + ScriptC script = sb.create(); + script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); + script.setTimeZone(TimeZone.getDefault().getID()); + + script.bindAllocation(mState, RSID_STATE); + script.bindAllocation(mPointAlloc, RSID_POINTS); + script.bindAllocation(mLineIdxAlloc, RSID_LINES); + script.bindAllocation(mPVAlloc.mAlloc, RSID_PROGRAMVERTEX); + + return script; + } + + @Override + public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) { + // update our state, then push it to the renderscript + mWorldState.yRotation = (xOffset - 0.5f) * 2 * 180 / (float) Math.PI; + mState.data(mWorldState); + } + + /* + * Read the model definition from the resource. + */ + private void readModel() { + + String [] p = mResources.getStringArray(R.array.cubepoints); + int numpoints = p.length; + mOriginalPoints = new ThreeDPoint[numpoints]; + + for (int i = 0; i < numpoints; i++) { + mOriginalPoints[i] = new ThreeDPoint(); + String [] coord = p[i].split(" "); + mOriginalPoints[i].x = Float.valueOf(coord[0]); + mOriginalPoints[i].y = Float.valueOf(coord[1]); + mOriginalPoints[i].z = Float.valueOf(coord[2]); + } + + String [] l = mResources.getStringArray(R.array.cubelines); + int numlines = l.length; + mLines = new ThreeDLine[numlines]; + + for (int i = 0; i < numlines; i++) { + mLines[i] = new ThreeDLine(); + String [] idx = l[i].split(" "); + mLines[i].startPoint = Integer.valueOf(idx[0]); + mLines[i].endPoint = Integer.valueOf(idx[1]); + } + } + +} diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/CubeWallpaper3.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/CubeWallpaper3.java new file mode 100644 index 000000000..8f09388b3 --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/CubeWallpaper3.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +package com.android.livecubes.cube3; + +import com.android.livecubes.RenderScriptWallpaper; + +public class CubeWallpaper3 extends RenderScriptWallpaper<Cube3RS> { + + @Override + protected Cube3RS createScene(int width, int height) { + return new Cube3RS(width, height); + } +} + diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/RenderScriptScene.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/RenderScriptScene.java new file mode 100644 index 000000000..429e93d01 --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/RenderScriptScene.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + + +package com.android.livecubes; + +import android.content.res.Resources; +import android.renderscript.RenderScript; +import android.renderscript.ScriptC; + +public abstract class RenderScriptScene { + protected int mWidth; + protected int mHeight; + protected boolean mPreview; + protected Resources mResources; + protected RenderScript mRS; + protected ScriptC mScript; + + public RenderScriptScene(int width, int height) { + mWidth = width; + mHeight = height; + } + + public void init(RenderScript rs, Resources res, boolean isPreview) { + mRS = rs; + mResources = res; + mPreview = isPreview; + mScript = createScript(); + } + + public boolean isPreview() { + return mPreview; + } + + public int getWidth() { + return mWidth; + } + + public int getHeight() { + return mHeight; + } + + public Resources getResources() { + return mResources; + } + + public RenderScript getRS() { + return mRS; + } + + public ScriptC getScript() { + return mScript; + } + + protected abstract ScriptC createScript(); + + public void stop() { + mRS.contextBindRootScript(null); + } + + public void start() { + mRS.contextBindRootScript(mScript); + } + + public void resize(int width, int height) { + mWidth = width; + mHeight = height; + } + + @SuppressWarnings({"UnusedDeclaration"}) + public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) { + } +} diff --git a/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/RenderScriptWallpaper.java b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/RenderScriptWallpaper.java new file mode 100644 index 000000000..3fb51484b --- /dev/null +++ b/samples/CubeLiveWallpaper/src/com/android/livecubes/cube3/RenderScriptWallpaper.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + + +package com.android.livecubes; + +import android.service.wallpaper.WallpaperService; +import android.renderscript.RenderScript; +import android.view.SurfaceHolder; +import android.view.Surface; + +public abstract class RenderScriptWallpaper<T extends RenderScriptScene> extends WallpaperService { + public Engine onCreateEngine() { + return new RenderScriptEngine(); + } + + protected abstract T createScene(int width, int height); + + private class RenderScriptEngine extends Engine { + private RenderScript mRs; + private T mRenderer; + + @Override + public void onCreate(SurfaceHolder surfaceHolder) { + super.onCreate(surfaceHolder); + setTouchEventsEnabled(false); + surfaceHolder.setSizeFromLayout(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + destroyRenderer(); + } + + private void destroyRenderer() { + if (mRenderer != null) { + mRenderer.stop(); + mRenderer = null; + } + if (mRs != null) { + mRs.destroy(); + mRs = null; + } + } + + @Override + public void onVisibilityChanged(boolean visible) { + super.onVisibilityChanged(visible); + if (mRenderer != null) { + if (visible) { + mRenderer.start(); + } else { + mRenderer.stop(); + } + } + } + + @Override + public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { + super.onSurfaceChanged(holder, format, width, height); + if (mRenderer == null) { + mRenderer = createScene(width, height); + mRenderer.init(mRs, getResources(), isPreview()); + mRenderer.start(); + } else { + mRenderer.resize(width, height); + } + } + + @Override + public void onOffsetsChanged(float xOffset, float yOffset, + float xStep, float yStep, int xPixels, int yPixels) { + mRenderer.setOffset(xOffset, yOffset, xPixels, yPixels); + } + + @Override + public void onSurfaceCreated(SurfaceHolder holder) { + super.onSurfaceCreated(holder); + + Surface surface = null; + while (surface == null) { + surface = holder.getSurface(); + } + mRs = new RenderScript(surface, false, false); + } + + @Override + public void onSurfaceDestroyed(SurfaceHolder holder) { + super.onSurfaceDestroyed(holder); + destroyRenderer(); + } + } +} diff --git a/samples/FixedGridLayout/Android.mk b/samples/FixedGridLayout/Android.mk new file mode 100644 index 000000000..1562cb95c --- /dev/null +++ b/samples/FixedGridLayout/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := samples + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := FixedGridLayout + +LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) diff --git a/samples/FixedGridLayout/AndroidManifest.xml b/samples/FixedGridLayout/AndroidManifest.xml new file mode 100644 index 000000000..9acd309ab --- /dev/null +++ b/samples/FixedGridLayout/AndroidManifest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.fixedgridlayout" + android:versionCode="1" + android:versionName="1.0"> + <application android:label="@string/app_name"> + <activity android:name=".FixedGridLayoutTest" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/samples/FixedGridLayout/res/drawable-hdpi/bugdroid.png b/samples/FixedGridLayout/res/drawable-hdpi/bugdroid.png Binary files differnew file mode 100755 index 000000000..e64968fc2 --- /dev/null +++ b/samples/FixedGridLayout/res/drawable-hdpi/bugdroid.png diff --git a/samples/FixedGridLayout/res/drawable-mdpi/bugdroid.png b/samples/FixedGridLayout/res/drawable-mdpi/bugdroid.png Binary files differnew file mode 100644 index 000000000..855484a2d --- /dev/null +++ b/samples/FixedGridLayout/res/drawable-mdpi/bugdroid.png diff --git a/samples/FixedGridLayout/res/layout/main.xml b/samples/FixedGridLayout/res/layout/main.xml new file mode 100644 index 000000000..93e2d5e92 --- /dev/null +++ b/samples/FixedGridLayout/res/layout/main.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.example.android.fixedgridlayout.FixedGridLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res/com.example.android.fixedgridlayout" + android:id="@+id/grid" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + app:cellWidth="80dp" + app:cellHeight="100dp" + > + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/bugdroid" + /> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/bugdroid" + /> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/bugdroid" + /> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/bugdroid" + /> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/bugdroid" + /> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/bugdroid" + /> +</com.example.android.fixedgridlayout.FixedGridLayout> + diff --git a/samples/FixedGridLayout/res/values/attrs.xml b/samples/FixedGridLayout/res/values/attrs.xml new file mode 100644 index 000000000..8287d0e02 --- /dev/null +++ b/samples/FixedGridLayout/res/values/attrs.xml @@ -0,0 +1,7 @@ +<resources> + <declare-styleable name="FixedGridLayout"> + <attr name="cellWidth" format="dimension" /> + <attr name="cellHeight" format="dimension" /> + </declare-styleable> +</resources> + diff --git a/samples/FixedGridLayout/res/values/strings.xml b/samples/FixedGridLayout/res/values/strings.xml new file mode 100644 index 000000000..14563c7df --- /dev/null +++ b/samples/FixedGridLayout/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">FixedGridLayoutTest</string> +</resources> diff --git a/samples/FixedGridLayout/src/com/example/android/fixedgridlayout/FixedGridLayout.java b/samples/FixedGridLayout/src/com/example/android/fixedgridlayout/FixedGridLayout.java new file mode 100644 index 000000000..413157f22 --- /dev/null +++ b/samples/FixedGridLayout/src/com/example/android/fixedgridlayout/FixedGridLayout.java @@ -0,0 +1,119 @@ +/* + * 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. + */ + +package com.example.android.fixedgridlayout; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.SparseIntArray; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewDebug; + +/** + * A layout that arranges its children in a grid. The size of the + * cells is set by the {@link #setCellSize} method and the + * android:cell_width and android:cell_height attributes in XML. + * The number of rows and columns is determined at runtime. Each + * cell contains exactly one view, and they flow in the natural + * child order (the order in which they were added, or the index + * in {@link #addViewAt}. Views can not span multiple cells. + */ +public class FixedGridLayout extends ViewGroup { + int mCellWidth; + int mCellHeight; + + public FixedGridLayout(Context context) { + super(context); + } + + public FixedGridLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + // Read the resource attributes. + TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.FixedGridLayout); + mCellWidth = a.getDimensionPixelSize( + R.styleable.FixedGridLayout_cellWidth, -1); + mCellHeight = a.getDimensionPixelSize( + R.styleable.FixedGridLayout_cellHeight, -1); + a.recycle(); + } + + public void setCellWidth(int px) { + mCellWidth = px; + requestLayout(); + } + + public void setCellHeight(int px) { + mCellHeight = px; + requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int cellWidthSpec = MeasureSpec.makeMeasureSpec(mCellWidth, + MeasureSpec.AT_MOST); + int cellHeightSpec = MeasureSpec.makeMeasureSpec(mCellHeight, + MeasureSpec.AT_MOST); + + int count = getChildCount(); + for (int index=0; index<count; index++) { + final View child = getChildAt(index); + child.measure(cellWidthSpec, cellHeightSpec); + } + // Use the size our parents gave us + setMeasuredDimension(resolveSize(mCellWidth*count, widthMeasureSpec), + resolveSize(mCellHeight*count, heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int cellWidth = mCellWidth; + int cellHeight = mCellHeight; + int columns = (r - l) / cellWidth; + if (columns < 0) { + columns = 1; + } + int x = 0; + int y = 0; + int i = 0; + int count = getChildCount(); + for (int index=0; index<count; index++) { + final View child = getChildAt(index); + + int w = child.getMeasuredWidth(); + int h = child.getMeasuredHeight(); + + int left = x + ((cellWidth-w)/2); + int top = y + ((cellHeight-h)/2); + + child.layout(left, top, left+w, top+h); + if (i >= (columns-1)) { + // advance to next row + i = 0; + x = 0; + y += cellHeight; + } else { + i++; + x += cellWidth; + } + } + } +} + diff --git a/samples/FixedGridLayout/src/com/example/android/fixedgridlayout/FixedGridLayoutTest.java b/samples/FixedGridLayout/src/com/example/android/fixedgridlayout/FixedGridLayoutTest.java new file mode 100644 index 000000000..19c9da7dc --- /dev/null +++ b/samples/FixedGridLayout/src/com/example/android/fixedgridlayout/FixedGridLayoutTest.java @@ -0,0 +1,19 @@ +package com.example.android.fixedgridlayout; + +import android.app.Activity; +import android.os.Bundle; + +public class FixedGridLayoutTest extends Activity +{ + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + FixedGridLayout grid = (FixedGridLayout)findViewById(R.id.grid); + grid.setCellWidth(80); + grid.setCellHeight(80); + } +} diff --git a/samples/GlobalTime/res/drawable-hdpi/app_global_time.png b/samples/GlobalTime/res/drawable-hdpi/app_global_time.png Binary files differnew file mode 100755 index 000000000..46c658e30 --- /dev/null +++ b/samples/GlobalTime/res/drawable-hdpi/app_global_time.png diff --git a/samples/GlobalTime/res/drawable/app_global_time.png b/samples/GlobalTime/res/drawable-mdpi/app_global_time.png Binary files differindex 914977d51..914977d51 100644 --- a/samples/GlobalTime/res/drawable/app_global_time.png +++ b/samples/GlobalTime/res/drawable-mdpi/app_global_time.png diff --git a/samples/HelloActivity/tests/build.properties b/samples/HelloActivity/tests/build.properties new file mode 100644 index 000000000..e0c39def1 --- /dev/null +++ b/samples/HelloActivity/tests/build.properties @@ -0,0 +1 @@ +tested.project.dir=.. diff --git a/samples/Home/res/drawable-hdpi/all_applications_label_background.9.png b/samples/Home/res/drawable-hdpi/all_applications_label_background.9.png Binary files differnew file mode 100755 index 000000000..75adf056d --- /dev/null +++ b/samples/Home/res/drawable-hdpi/all_applications_label_background.9.png diff --git a/samples/Home/res/drawable-hdpi/application_background.9.png b/samples/Home/res/drawable-hdpi/application_background.9.png Binary files differnew file mode 100755 index 000000000..70ae4d951 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/application_background.9.png diff --git a/samples/Home/res/drawable-hdpi/application_background_static.png b/samples/Home/res/drawable-hdpi/application_background_static.png Binary files differnew file mode 100755 index 000000000..450eaa454 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/application_background_static.png diff --git a/samples/Home/res/drawable-hdpi/focused_application_background_static.png b/samples/Home/res/drawable-hdpi/focused_application_background_static.png Binary files differnew file mode 100755 index 000000000..bec2cd902 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/focused_application_background_static.png diff --git a/samples/Home/res/drawable-hdpi/hide_all_applications.png b/samples/Home/res/drawable-hdpi/hide_all_applications.png Binary files differnew file mode 100755 index 000000000..13e188f9c --- /dev/null +++ b/samples/Home/res/drawable-hdpi/hide_all_applications.png diff --git a/samples/Home/res/drawable-hdpi/ic_launcher_allhide.png b/samples/Home/res/drawable-hdpi/ic_launcher_allhide.png Binary files differnew file mode 100755 index 000000000..9bef2ea70 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/ic_launcher_allhide.png diff --git a/samples/Home/res/drawable-hdpi/ic_launcher_allshow.png b/samples/Home/res/drawable-hdpi/ic_launcher_allshow.png Binary files differnew file mode 100755 index 000000000..2a6f86ae7 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/ic_launcher_allshow.png diff --git a/samples/Home/res/drawable-hdpi/ic_launcher_home.png b/samples/Home/res/drawable-hdpi/ic_launcher_home.png Binary files differnew file mode 100755 index 000000000..1e256e683 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/ic_launcher_home.png diff --git a/samples/Home/res/drawable-hdpi/pressed_application_background_static.png b/samples/Home/res/drawable-hdpi/pressed_application_background_static.png Binary files differnew file mode 100755 index 000000000..99315716d --- /dev/null +++ b/samples/Home/res/drawable-hdpi/pressed_application_background_static.png diff --git a/samples/Home/res/drawable-hdpi/show_all_applications.png b/samples/Home/res/drawable-hdpi/show_all_applications.png Binary files differnew file mode 100755 index 000000000..2a768b777 --- /dev/null +++ b/samples/Home/res/drawable-hdpi/show_all_applications.png diff --git a/samples/Home/res/drawable/all_applications_label_background.9.png b/samples/Home/res/drawable-mdpi/all_applications_label_background.9.png Binary files differindex b1bf466ca..b1bf466ca 100644 --- a/samples/Home/res/drawable/all_applications_label_background.9.png +++ b/samples/Home/res/drawable-mdpi/all_applications_label_background.9.png diff --git a/samples/Home/res/drawable/application_background.9.png b/samples/Home/res/drawable-mdpi/application_background.9.png Binary files differindex 29ae09af4..29ae09af4 100644 --- a/samples/Home/res/drawable/application_background.9.png +++ b/samples/Home/res/drawable-mdpi/application_background.9.png diff --git a/samples/Home/res/drawable/application_background_static.png b/samples/Home/res/drawable-mdpi/application_background_static.png Binary files differindex 9af69833e..9af69833e 100644 --- a/samples/Home/res/drawable/application_background_static.png +++ b/samples/Home/res/drawable-mdpi/application_background_static.png diff --git a/samples/Home/res/drawable/focused_application_background_static.png b/samples/Home/res/drawable-mdpi/focused_application_background_static.png Binary files differindex 3a6d47cb0..3a6d47cb0 100644 --- a/samples/Home/res/drawable/focused_application_background_static.png +++ b/samples/Home/res/drawable-mdpi/focused_application_background_static.png diff --git a/samples/Home/res/drawable/hide_all_applications.png b/samples/Home/res/drawable-mdpi/hide_all_applications.png Binary files differindex a67cf78de..a67cf78de 100644 --- a/samples/Home/res/drawable/hide_all_applications.png +++ b/samples/Home/res/drawable-mdpi/hide_all_applications.png diff --git a/samples/Home/res/drawable/ic_launcher_allhide.png b/samples/Home/res/drawable-mdpi/ic_launcher_allhide.png Binary files differindex 38e125dcc..38e125dcc 100755 --- a/samples/Home/res/drawable/ic_launcher_allhide.png +++ b/samples/Home/res/drawable-mdpi/ic_launcher_allhide.png diff --git a/samples/Home/res/drawable/ic_launcher_allshow.png b/samples/Home/res/drawable-mdpi/ic_launcher_allshow.png Binary files differindex 5803d32f5..5803d32f5 100755 --- a/samples/Home/res/drawable/ic_launcher_allshow.png +++ b/samples/Home/res/drawable-mdpi/ic_launcher_allshow.png diff --git a/samples/Home/res/drawable/ic_launcher_home.png b/samples/Home/res/drawable-mdpi/ic_launcher_home.png Binary files differindex 84af2a2f1..84af2a2f1 100755 --- a/samples/Home/res/drawable/ic_launcher_home.png +++ b/samples/Home/res/drawable-mdpi/ic_launcher_home.png diff --git a/samples/Home/res/drawable/pressed_application_background_static.png b/samples/Home/res/drawable-mdpi/pressed_application_background_static.png Binary files differindex b086a3f4b..b086a3f4b 100644 --- a/samples/Home/res/drawable/pressed_application_background_static.png +++ b/samples/Home/res/drawable-mdpi/pressed_application_background_static.png diff --git a/samples/Home/res/drawable/show_all_applications.png b/samples/Home/res/drawable-mdpi/show_all_applications.png Binary files differindex ed581e1b7..ed581e1b7 100644 --- a/samples/Home/res/drawable/show_all_applications.png +++ b/samples/Home/res/drawable-mdpi/show_all_applications.png diff --git a/samples/Home/src/com/example/android/home/Home.java b/samples/Home/src/com/example/android/home/Home.java index c23f7b85f..7cae87ece 100644 --- a/samples/Home/src/com/example/android/home/Home.java +++ b/samples/Home/src/com/example/android/home/Home.java @@ -110,6 +110,9 @@ public class Home extends Activity { private boolean mBlockAnimation; + private boolean mHomeDown; + private boolean mBackDown; + private View mShowApplications; private CheckBox mShowApplicationsCheck; @@ -396,19 +399,44 @@ public class Home extends Activity { } @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (!hasFocus) { + mBackDown = mHomeDown = false; + } + } + + @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_BACK: + mBackDown = true; return true; case KeyEvent.KEYCODE_HOME: + mHomeDown = true; + return true; + } + } else if (event.getAction() == KeyEvent.ACTION_UP) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_BACK: + if (!event.isCanceled()) { + // Do BACK behavior. + } + mBackDown = true; + return true; + case KeyEvent.KEYCODE_HOME: + if (!event.isCanceled()) { + // Do HOME behavior. + } + mHomeDown = true; return true; } } return super.dispatchKeyEvent(event); } - + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); diff --git a/samples/JetBoy/src/com/example/android/jetboy/JetBoy.java b/samples/JetBoy/src/com/example/android/jetboy/JetBoy.java index 21d933c87..d62eb32bb 100755 --- a/samples/JetBoy/src/com/example/android/jetboy/JetBoy.java +++ b/samples/JetBoy/src/com/example/android/jetboy/JetBoy.java @@ -133,19 +133,22 @@ public class JetBoy extends Activity implements View.OnClickListener { */ @Override public boolean onKeyDown(int keyCode, KeyEvent msg) { - - if (keyCode == 4) - super.onKeyDown(keyCode, msg); - - return mJetBoyThread.doKeyDown(keyCode, msg); + if (keyCode == KeyEvent.KEYCODE_BACK) { + return super.onKeyDown(keyCode, msg); + } else { + return mJetBoyThread.doKeyDown(keyCode, msg); + } } /** - * Standard override for key-up. We actually care about these, so we can - * turn off the engine or stop rotating. + * Standard override for key-up. */ @Override public boolean onKeyUp(int keyCode, KeyEvent msg) { - return mJetBoyThread.doKeyUp(keyCode, msg); + if (keyCode == KeyEvent.KEYCODE_BACK) { + return super.onKeyUp(keyCode, msg); + } else { + return mJetBoyThread.doKeyUp(keyCode, msg); + } } } diff --git a/samples/LunarLander/tests/build.properties b/samples/LunarLander/tests/build.properties new file mode 100644 index 000000000..8ae22a371 --- /dev/null +++ b/samples/LunarLander/tests/build.properties @@ -0,0 +1 @@ +tested.project.dir=..
\ No newline at end of file diff --git a/samples/NotePad/res/drawable-hdpi/app_notes.png b/samples/NotePad/res/drawable-hdpi/app_notes.png Binary files differnew file mode 100755 index 000000000..258d3d167 --- /dev/null +++ b/samples/NotePad/res/drawable-hdpi/app_notes.png diff --git a/samples/NotePad/res/drawable/app_notes.png b/samples/NotePad/res/drawable-mdpi/app_notes.png Binary files differindex 0479138d1..0479138d1 100644 --- a/samples/NotePad/res/drawable/app_notes.png +++ b/samples/NotePad/res/drawable-mdpi/app_notes.png diff --git a/samples/NotePad/tests/build.properties b/samples/NotePad/tests/build.properties new file mode 100644 index 000000000..e0c39def1 --- /dev/null +++ b/samples/NotePad/tests/build.properties @@ -0,0 +1 @@ +tested.project.dir=.. diff --git a/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java b/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java index db626e84e..586fddb4a 100644 --- a/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java +++ b/samples/SearchableDictionary/src/com/example/android/searchabledict/DictionaryProvider.java @@ -106,16 +106,17 @@ public class DictionaryProvider extends ContentProvider { List<Dictionary.Word> words = Dictionary.getInstance().getMatches(processedQuery); MatrixCursor cursor = new MatrixCursor(COLUMNS); + long id = 0; for (Dictionary.Word word : words) { - cursor.addRow(columnValuesOfWord(word)); + cursor.addRow(columnValuesOfWord(id++, word)); } return cursor; } - private Object[] columnValuesOfWord(Dictionary.Word word) { - return new String[] { - word.word, // _id + private Object[] columnValuesOfWord(long id, Dictionary.Word word) { + return new Object[] { + id, // _id word.word, // text1 word.definition, // text2 word.word, // intent_data (included when clicking on item) diff --git a/samples/SkeletonApp/tests/build.properties b/samples/SkeletonApp/tests/build.properties new file mode 100644 index 000000000..8ae22a371 --- /dev/null +++ b/samples/SkeletonApp/tests/build.properties @@ -0,0 +1 @@ +tested.project.dir=..
\ No newline at end of file diff --git a/samples/Snake/tests/build.properties b/samples/Snake/tests/build.properties new file mode 100644 index 000000000..e0c39def1 --- /dev/null +++ b/samples/Snake/tests/build.properties @@ -0,0 +1 @@ +tested.project.dir=.. diff --git a/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_delete.png b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_delete.png Binary files differnew file mode 100755 index 000000000..5139c7179 --- /dev/null +++ b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_delete.png diff --git a/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_done.png b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_done.png Binary files differnew file mode 100755 index 000000000..471c5021b --- /dev/null +++ b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_done.png diff --git a/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_return.png b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_return.png Binary files differnew file mode 100755 index 000000000..5a5670c32 --- /dev/null +++ b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_return.png diff --git a/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_search.png b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_search.png Binary files differnew file mode 100755 index 000000000..e72cde3bb --- /dev/null +++ b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_search.png diff --git a/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_shift.png b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_shift.png Binary files differnew file mode 100755 index 000000000..275769618 --- /dev/null +++ b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_shift.png diff --git a/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_space.png b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_space.png Binary files differnew file mode 100755 index 000000000..cef2daa5d --- /dev/null +++ b/samples/SoftKeyboard/res/drawable-hdpi/sym_keyboard_space.png diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_delete.png b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_delete.png Binary files differindex 6cee59682..6cee59682 100644 --- a/samples/SoftKeyboard/res/drawable/sym_keyboard_delete.png +++ b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_delete.png diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_done.png b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_done.png Binary files differindex c0d6d1394..c0d6d1394 100755 --- a/samples/SoftKeyboard/res/drawable/sym_keyboard_done.png +++ b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_done.png diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_return.png b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_return.png Binary files differindex cbe2b152f..cbe2b152f 100644 --- a/samples/SoftKeyboard/res/drawable/sym_keyboard_return.png +++ b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_return.png diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_search.png b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_search.png Binary files differindex 127755d6b..127755d6b 100755 --- a/samples/SoftKeyboard/res/drawable/sym_keyboard_search.png +++ b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_search.png diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_shift.png b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_shift.png Binary files differindex d05962846..d05962846 100644 --- a/samples/SoftKeyboard/res/drawable/sym_keyboard_shift.png +++ b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_shift.png diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_space.png b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_space.png Binary files differindex 09b94d9e6..09b94d9e6 100644 --- a/samples/SoftKeyboard/res/drawable/sym_keyboard_space.png +++ b/samples/SoftKeyboard/res/drawable-mdpi/sym_keyboard_space.png |
